Compare commits

..

1 Commits

Author SHA1 Message Date
Simon McVittie
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
344 changed files with 14060 additions and 11928 deletions

27
NEWS
View File

@@ -1,30 +1,3 @@
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 3.37.1
====== ======
* Fix screencasting non-maximized windows [Jonas Å.; !1174] * 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, G_DEFINE_TYPE_WITH_CODE (CallyStage,
cally_stage, cally_stage,
CALLY_TYPE_ACTOR, CALLY_TYPE_GROUP,
G_ADD_PRIVATE (CallyStage) G_ADD_PRIVATE (CallyStage)
G_IMPLEMENT_INTERFACE (ATK_TYPE_WINDOW, G_IMPLEMENT_INTERFACE (ATK_TYPE_WINDOW,
cally_stage_window_interface_init)); cally_stage_window_interface_init));

View File

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

View File

@@ -36,8 +36,10 @@
#include "cally.h" #include "cally.h"
#include "cally-actor.h" #include "cally-actor.h"
#include "cally-group.h"
#include "cally-stage.h" #include "cally-stage.h"
#include "cally-text.h" #include "cally-text.h"
#include "cally-rectangle.h"
#include "cally-clone.h" #include "cally-clone.h"
#include "cally-factory.h" #include "cally-factory.h"
@@ -50,8 +52,10 @@
/* factories initialization*/ /* factories initialization*/
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_ACTOR, cally_actor, cally_actor_new) 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_STAGE, cally_stage, cally_stage_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_TEXT, cally_text, cally_text_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) CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_CLONE, cally_clone, cally_clone_new)
/** /**
@@ -69,8 +73,10 @@ cally_accessibility_init (void)
{ {
/* setting the factories */ /* setting the factories */
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_ACTOR, cally_actor); 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_STAGE, cally_stage);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_TEXT, cally_text); 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); CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_CLONE, cally_clone);
/* Initialize the CallyUtility class */ /* Initialize the CallyUtility class */

View File

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

View File

@@ -615,32 +615,6 @@ clutter_actor_box_scale (ClutterActorBox *box,
box->y2 *= scale; 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, G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterActorBox, clutter_actor_box,
clutter_actor_box_copy, clutter_actor_box_copy,
clutter_actor_box_free, clutter_actor_box_free,

View File

@@ -110,12 +110,35 @@ typedef ClutterActorTraverseVisitFlags (*ClutterTraverseCallback) (ClutterActor
typedef gboolean (*ClutterForeachCallback) (ClutterActor *actor, typedef gboolean (*ClutterForeachCallback) (ClutterActor *actor,
gpointer user_data); gpointer user_data);
typedef struct _AnchorCoord AnchorCoord;
typedef struct _SizeRequest SizeRequest; typedef struct _SizeRequest SizeRequest;
typedef struct _ClutterLayoutInfo ClutterLayoutInfo; typedef struct _ClutterLayoutInfo ClutterLayoutInfo;
typedef struct _ClutterTransformInfo ClutterTransformInfo; typedef struct _ClutterTransformInfo ClutterTransformInfo;
typedef struct _ClutterAnimationInfo ClutterAnimationInfo; 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 struct _SizeRequest
{ {
guint age; guint age;
@@ -160,15 +183,24 @@ ClutterLayoutInfo * _clutter_actor_peek_layout_info
struct _ClutterTransformInfo struct _ClutterTransformInfo
{ {
/* rotation */ /* rotation (angle and center) */
gdouble rx_angle; gdouble rx_angle;
AnchorCoord rx_center;
gdouble ry_angle; gdouble ry_angle;
AnchorCoord ry_center;
gdouble rz_angle; gdouble rz_angle;
AnchorCoord rz_center;
/* scaling */ /* scaling */
gdouble scale_x; gdouble scale_x;
gdouble scale_y; gdouble scale_y;
gdouble scale_z; gdouble scale_z;
AnchorCoord scale_center;
/* anchor point */
AnchorCoord anchor;
/* translation */ /* translation */
graphene_point3d_t 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_redraw_on_clones (ClutterActor *actor);
void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor); void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor);
void _clutter_actor_queue_only_relayout (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, ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
CoglTexture *texture); CoglTexture *texture);
void clutter_actor_update_stage_views (ClutterActor *self,
int phase);
void clutter_actor_queue_immediate_relayout (ClutterActor *self);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */ #endif /* __CLUTTER_ACTOR_PRIVATE_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -142,6 +142,11 @@ struct _ClutterActor
* ClutterActorClass: * ClutterActorClass:
* @show: signal class handler for #ClutterActor::show; it must chain * @show: signal class handler for #ClutterActor::show; it must chain
* up to the parent's implementation * 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 * @hide: signal class handler for #ClutterActor::hide; it must chain
* up to the parent's implementation * up to the parent's implementation
* @hide_all: virtual function for containers and composite actors, to * @hide_all: virtual function for containers and composite actors, to
@@ -178,10 +183,7 @@ struct _ClutterActor
* implementation. * implementation.
* @apply_transform: virtual function, used when applying the transformations * @apply_transform: virtual function, used when applying the transformations
* to an actor before painting it or when transforming coordinates or * to an actor before painting it or when transforming coordinates or
* the allocation; if the transformation calculated by this function may * the allocation; it must chain up to the parent's implementation
* have changed, the cached transformation must be invalidated by calling
* clutter_actor_invalidate_transform(); it must chain up to the parent's
* implementation
* @parent_set: signal class handler for the #ClutterActor::parent-set * @parent_set: signal class handler for the #ClutterActor::parent-set
* @destroy: signal class handler for #ClutterActor::destroy. It must * @destroy: signal class handler for #ClutterActor::destroy. It must
* chain up to the parent's implementation * chain up to the parent's implementation
@@ -224,6 +226,7 @@ struct _ClutterActorClass
/*< public >*/ /*< public >*/
void (* show) (ClutterActor *self); void (* show) (ClutterActor *self);
void (* show_all) (ClutterActor *self);
void (* hide) (ClutterActor *self); void (* hide) (ClutterActor *self);
void (* hide_all) (ClutterActor *self); void (* hide_all) (ClutterActor *self);
void (* realize) (ClutterActor *self); void (* realize) (ClutterActor *self);
@@ -299,9 +302,6 @@ struct _ClutterActorClass
gboolean (* touch_event) (ClutterActor *self, gboolean (* touch_event) (ClutterActor *self,
ClutterTouchEvent *event); ClutterTouchEvent *event);
gboolean (* has_accessible) (ClutterActor *self); gboolean (* has_accessible) (ClutterActor *self);
void (* resource_scale_changed) (ClutterActor *self);
float (* calculate_resource_scale) (ClutterActor *self,
int phase);
/*< private >*/ /*< private >*/
/* padding for future expansion */ /* padding for future expansion */
@@ -593,7 +593,8 @@ gboolean clutter_actor_get_paint_box
ClutterActorBox *box); ClutterActorBox *box);
CLUTTER_EXPORT CLUTTER_EXPORT
float clutter_actor_get_resource_scale (ClutterActor *self); gboolean clutter_actor_get_resource_scale (ClutterActor *self,
gfloat *resource_scale);
CLUTTER_EXPORT CLUTTER_EXPORT
gboolean clutter_actor_has_overlaps (ClutterActor *self); gboolean clutter_actor_has_overlaps (ClutterActor *self);
@@ -918,15 +919,6 @@ void clutter_actor_pick_box (ClutterActor *self,
ClutterPickContext *pick_context, ClutterPickContext *pick_context,
const ClutterActorBox *box); const ClutterActorBox *box);
CLUTTER_EXPORT
GList * clutter_actor_peek_stage_views (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_invalidate_transform (ClutterActor *self);
CLUTTER_EXPORT
ClutterFrameClock * clutter_actor_pick_frame_clock (ClutterActor *self);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_ACTOR_H__ */ #endif /* __CLUTTER_ACTOR_H__ */

View File

@@ -58,7 +58,6 @@ struct _ClutterAlignConstraint
ClutterActor *actor; ClutterActor *actor;
ClutterActor *source; ClutterActor *source;
ClutterAlignAxis align_axis; ClutterAlignAxis align_axis;
graphene_point_t pivot;
gfloat factor; gfloat factor;
}; };
@@ -73,7 +72,6 @@ enum
PROP_SOURCE, PROP_SOURCE,
PROP_ALIGN_AXIS, PROP_ALIGN_AXIS,
PROP_PIVOT_POINT,
PROP_FACTOR, PROP_FACTOR,
PROP_LAST PROP_LAST
@@ -86,11 +84,12 @@ G_DEFINE_TYPE (ClutterAlignConstraint,
CLUTTER_TYPE_CONSTRAINT); CLUTTER_TYPE_CONSTRAINT);
static void static void
source_queue_relayout (ClutterActor *actor, source_position_changed (ClutterActor *actor,
ClutterAlignConstraint *align) GParamSpec *pspec,
ClutterAlignConstraint *align)
{ {
if (align->actor != NULL) if (align->actor != NULL)
_clutter_actor_queue_only_relayout (align->actor); clutter_actor_queue_relayout (align->actor);
} }
static void static void
@@ -135,41 +134,35 @@ clutter_align_constraint_update_allocation (ClutterConstraint *constraint,
ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (constraint); ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (constraint);
gfloat source_width, source_height; gfloat source_width, source_height;
gfloat actor_width, actor_height; gfloat actor_width, actor_height;
gfloat offset_x_start, offset_y_start; gfloat source_x, source_y;
gfloat pivot_x, pivot_y;
if (align->source == NULL) if (align->source == NULL)
return; return;
clutter_actor_box_get_size (allocation, &actor_width, &actor_height); 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); 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) switch (align->align_axis)
{ {
case CLUTTER_ALIGN_X_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; allocation->x2 = allocation->x1 + actor_width;
break; break;
case CLUTTER_ALIGN_Y_AXIS: 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; allocation->y2 = allocation->y1 + actor_height;
break; break;
case CLUTTER_ALIGN_BOTH: case CLUTTER_ALIGN_BOTH:
allocation->x1 += offset_x_start + (source_width * align->factor); allocation->x1 = ((source_width - actor_width) * align->factor)
allocation->y1 += offset_y_start + (source_height * align->factor); + source_x;
allocation->y1 = ((source_height - actor_height) * align->factor)
+ source_y;
allocation->x2 = allocation->x1 + actor_width; allocation->x2 = allocation->x1 + actor_width;
allocation->y2 = allocation->y1 + actor_height; allocation->y2 = allocation->y1 + actor_height;
break; break;
@@ -193,7 +186,7 @@ clutter_align_constraint_dispose (GObject *gobject)
G_CALLBACK (source_destroyed), G_CALLBACK (source_destroyed),
align); align);
g_signal_handlers_disconnect_by_func (align->source, g_signal_handlers_disconnect_by_func (align->source,
G_CALLBACK (source_queue_relayout), G_CALLBACK (source_position_changed),
align); align);
align->source = NULL; 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)); clutter_align_constraint_set_align_axis (align, g_value_get_enum (value));
break; break;
case PROP_PIVOT_POINT:
clutter_align_constraint_set_pivot_point (align, g_value_get_boxed (value));
break;
case PROP_FACTOR: case PROP_FACTOR:
clutter_align_constraint_set_factor (align, g_value_get_float (value)); clutter_align_constraint_set_factor (align, g_value_get_float (value));
break; break;
@@ -251,16 +240,6 @@ clutter_align_constraint_get_property (GObject *gobject,
g_value_set_enum (value, align->align_axis); g_value_set_enum (value, align->align_axis);
break; 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: case PROP_FACTOR:
g_value_set_float (value, align->factor); g_value_set_float (value, align->factor);
break; break;
@@ -314,30 +293,6 @@ clutter_align_constraint_class_init (ClutterAlignConstraintClass *klass)
CLUTTER_ALIGN_X_AXIS, CLUTTER_ALIGN_X_AXIS,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT); 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: * ClutterAlignConstraint:factor:
* *
@@ -370,8 +325,6 @@ clutter_align_constraint_init (ClutterAlignConstraint *self)
self->actor = NULL; self->actor = NULL;
self->source = NULL; self->source = NULL;
self->align_axis = CLUTTER_ALIGN_X_AXIS; self->align_axis = CLUTTER_ALIGN_X_AXIS;
self->pivot.x = -1.f;
self->pivot.y = -1.f;
self->factor = 0.0f; self->factor = 0.0f;
} }
@@ -449,15 +402,15 @@ clutter_align_constraint_set_source (ClutterAlignConstraint *align,
G_CALLBACK (source_destroyed), G_CALLBACK (source_destroyed),
align); align);
g_signal_handlers_disconnect_by_func (old_source, g_signal_handlers_disconnect_by_func (old_source,
G_CALLBACK (source_queue_relayout), G_CALLBACK (source_position_changed),
align); align);
} }
align->source = source; align->source = source;
if (align->source != NULL) if (align->source != NULL)
{ {
g_signal_connect (align->source, "queue-relayout", g_signal_connect (align->source, "notify::allocation",
G_CALLBACK (source_queue_relayout), G_CALLBACK (source_position_changed),
align); align);
g_signal_connect (align->source, "destroy", g_signal_connect (align->source, "destroy",
G_CALLBACK (source_destroyed), G_CALLBACK (source_destroyed),
@@ -534,60 +487,6 @@ clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align)
return align->align_axis; 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: * clutter_align_constraint_set_factor:
* @align: a #ClutterAlignConstraint * @align: a #ClutterAlignConstraint

View File

@@ -67,12 +67,6 @@ void clutter_align_constraint_set_align_axis (ClutterAlignConstrai
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterAlignAxis clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align); ClutterAlignAxis clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align);
CLUTTER_EXPORT 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, void clutter_align_constraint_set_factor (ClutterAlignConstraint *align,
gfloat factor); gfloat factor);
CLUTTER_EXPORT CLUTTER_EXPORT

View File

@@ -194,25 +194,3 @@ clutter_animatable_interpolate_value (ClutterAnimatable *animatable,
else else
return clutter_interval_compute_value (interval, progress, value); 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 * animatable property
* @interpolate_value: virtual function for interpolating the progress * @interpolate_value: virtual function for interpolating the progress
* of a property * of a property
* @get_actor: virtual function for getting associated actor
* *
* Since: 1.0 * Since: 1.0
*/ */
@@ -73,7 +72,6 @@ struct _ClutterAnimatableInterface
ClutterInterval *interval, ClutterInterval *interval,
gdouble progress, gdouble progress,
GValue *value); GValue *value);
ClutterActor * (* get_actor) (ClutterAnimatable *animatable);
}; };
CLUTTER_EXPORT CLUTTER_EXPORT
@@ -94,9 +92,6 @@ gboolean clutter_animatable_interpolate_value (ClutterAnimatable *animatable,
gdouble progress, gdouble progress,
GValue *value); GValue *value);
CLUTTER_EXPORT
ClutterActor * clutter_animatable_get_actor (ClutterAnimatable *animatable);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_ANIMATABLE_H__ */ #endif /* __CLUTTER_ANIMATABLE_H__ */

View File

@@ -53,8 +53,6 @@ struct _ClutterBackend
gfloat units_per_em; gfloat units_per_em;
gint32 units_serial; gint32 units_serial;
float fallback_resource_scale;
ClutterStageWindow *stage_window; ClutterStageWindow *stage_window;
ClutterInputMethod *input_method; ClutterInputMethod *input_method;
@@ -136,12 +134,6 @@ void clutter_set_allowed_drivers (const c
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterStageWindow * clutter_backend_get_stage_window (ClutterBackend *backend); 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);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_BACKEND_PRIVATE_H__ */ #endif /* __CLUTTER_BACKEND_PRIVATE_H__ */

View File

@@ -601,8 +601,6 @@ clutter_backend_init (ClutterBackend *self)
self->units_serial = 1; self->units_serial = 1;
self->dummy_onscreen = NULL; self->dummy_onscreen = NULL;
self->fallback_resource_scale = 1.f;
} }
void void
@@ -1033,16 +1031,3 @@ clutter_backend_get_default_seat (ClutterBackend *backend)
return CLUTTER_BACKEND_GET_CLASS (backend)->get_default_seat (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;
}

View File

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

View File

@@ -81,6 +81,9 @@ struct _ClutterBlurEffect
gint pixel_step_uniform; gint pixel_step_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline; CoglPipeline *pipeline;
}; };
@@ -95,42 +98,20 @@ G_DEFINE_TYPE (ClutterBlurEffect,
clutter_blur_effect, clutter_blur_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT); CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_blur_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterBlurEffect *blur_effect = CLUTTER_BLUR_EFFECT (effect);
if (blur_effect->pixel_step_uniform > -1)
{
float pixel_step[2];
int tex_width, tex_height;
tex_width = cogl_texture_get_width (texture);
tex_height = cogl_texture_get_height (texture);
pixel_step[0] = 1.0f / tex_width;
pixel_step[1] = 1.0f / tex_height;
cogl_pipeline_set_uniform_float (blur_effect->pipeline,
blur_effect->pixel_step_uniform,
2, /* n_components */
1, /* count */
pixel_step);
}
cogl_pipeline_set_layer_texture (blur_effect->pipeline, 0, texture);
return cogl_object_ref (blur_effect->pipeline);
}
static gboolean static gboolean
clutter_blur_effect_pre_paint (ClutterEffect *effect, clutter_blur_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect);
ClutterEffectClass *parent_class; ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
self->actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
if (self->actor == NULL)
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{ {
/* if we don't have support for GLSL shaders then we /* if we don't have support for GLSL shaders then we
@@ -144,7 +125,59 @@ clutter_blur_effect_pre_paint (ClutterEffect *effect,
} }
parent_class = CLUTTER_EFFECT_CLASS (clutter_blur_effect_parent_class); parent_class = CLUTTER_EFFECT_CLASS (clutter_blur_effect_parent_class);
return parent_class->pre_paint (effect, node, paint_context); if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
if (self->pixel_step_uniform > -1)
{
gfloat pixel_step[2];
pixel_step[0] = 1.0f / self->tex_width;
pixel_step[1] = 1.0f / self->tex_height;
cogl_pipeline_set_uniform_float (self->pipeline,
self->pixel_step_uniform,
2, /* n_components */
1, /* count */
pixel_step);
}
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_blur_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
guint8 paint_opacity;
paint_opacity = clutter_actor_get_paint_opacity (self->actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
} }
static gboolean static gboolean
@@ -196,7 +229,7 @@ clutter_blur_effect_class_init (ClutterBlurEffectClass *klass)
effect_class->modify_paint_volume = clutter_blur_effect_modify_paint_volume; effect_class->modify_paint_volume = clutter_blur_effect_modify_paint_volume;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_pipeline = clutter_blur_effect_create_pipeline; offscreen_class->paint_target = clutter_blur_effect_paint_target;
} }
static void static void

View File

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

View File

@@ -69,6 +69,9 @@ struct _ClutterBrightnessContrastEffect
gint brightness_offset_uniform; gint brightness_offset_uniform;
gint contrast_uniform; gint contrast_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline; CoglPipeline *pipeline;
}; };
@@ -126,26 +129,16 @@ will_have_no_effect (ClutterBrightnessContrastEffect *self)
G_APPROX_VALUE (self->contrast_blue, no_change, FLT_EPSILON)); G_APPROX_VALUE (self->contrast_blue, no_change, FLT_EPSILON));
} }
static CoglPipeline *
clutter_brightness_contrast_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterBrightnessContrastEffect *self =
CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return cogl_object_ref (self->pipeline);
}
static gboolean static gboolean
clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect, clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect); ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
ClutterEffectClass *parent_class; ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (will_have_no_effect (self)) if (will_have_no_effect (self))
return FALSE; return FALSE;
@@ -164,8 +157,47 @@ clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect,
parent_class = parent_class =
CLUTTER_EFFECT_CLASS (clutter_brightness_contrast_effect_parent_class); CLUTTER_EFFECT_CLASS (clutter_brightness_contrast_effect_parent_class);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
return parent_class->pre_paint (effect, node, paint_context); texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_brightness_contrast_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
guint8 paint_opacity;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
} }
static void static void
@@ -265,7 +297,7 @@ clutter_brightness_contrast_effect_class_init (ClutterBrightnessContrastEffectCl
ClutterOffscreenEffectClass *offscreen_class; ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_pipeline = clutter_brightness_contrast_effect_create_pipeline; offscreen_class->paint_target = clutter_brightness_contrast_effect_paint_target;
effect_class->pre_paint = clutter_brightness_contrast_effect_pre_paint; effect_class->pre_paint = clutter_brightness_contrast_effect_pre_paint;

View File

@@ -52,8 +52,6 @@
struct _ClutterClonePrivate struct _ClutterClonePrivate
{ {
ClutterActor *clone_source; ClutterActor *clone_source;
float x_scale, y_scale;
gulong source_destroy_id; gulong source_destroy_id;
}; };
@@ -124,6 +122,8 @@ static void
clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix) clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix)
{ {
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActorBox box, source_box;
gfloat x_scale, y_scale;
/* First chain up and apply all the standard ClutterActor /* First chain up and apply all the standard ClutterActor
* transformations... */ * transformations... */
@@ -134,7 +134,21 @@ clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix)
if (priv->clone_source == NULL) if (priv->clone_source == NULL)
return; 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 static void
@@ -230,8 +244,6 @@ clutter_clone_allocate (ClutterActor *self,
{ {
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv; ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActorClass *parent_class; ClutterActorClass *parent_class;
ClutterActorBox source_box;
float x_scale, y_scale;
/* chain up */ /* chain up */
parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class); parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class);
@@ -247,24 +259,6 @@ clutter_clone_allocate (ClutterActor *self,
!clutter_actor_has_allocation (priv->clone_source)) !clutter_actor_has_allocation (priv->clone_source))
clutter_actor_allocate_preferred_size (priv->clone_source); clutter_actor_allocate_preferred_size (priv->clone_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);
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));
}
#if 0 #if 0
/* XXX - this is wrong: ClutterClone cannot clone unparented /* XXX - this is wrong: ClutterClone cannot clone unparented
* actors, as it will break all invariants * actors, as it will break all invariants
@@ -370,9 +364,6 @@ static void
clutter_clone_init (ClutterClone *self) clutter_clone_init (ClutterClone *self)
{ {
self->priv = clutter_clone_get_instance_private (self); self->priv = clutter_clone_get_instance_private (self);
self->priv->x_scale = 1.f;
self->priv->y_scale = 1.f;
} }
/** /**

View File

@@ -59,6 +59,9 @@ struct _ClutterColorizeEffect
gint tint_uniform; gint tint_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline; CoglPipeline *pipeline;
}; };
@@ -101,24 +104,16 @@ G_DEFINE_TYPE (ClutterColorizeEffect,
clutter_colorize_effect, clutter_colorize_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT); CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_colorize_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterColorizeEffect *colorize_effect = CLUTTER_COLORIZE_EFFECT (effect);
cogl_pipeline_set_layer_texture (colorize_effect->pipeline, 0, texture);
return cogl_object_ref (colorize_effect->pipeline);
}
static gboolean static gboolean
clutter_colorize_effect_pre_paint (ClutterEffect *effect, clutter_colorize_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect);
ClutterEffectClass *parent_class; ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{ {
/* if we don't have support for GLSL shaders then we /* if we don't have support for GLSL shaders then we
@@ -132,7 +127,47 @@ clutter_colorize_effect_pre_paint (ClutterEffect *effect,
} }
parent_class = CLUTTER_EFFECT_CLASS (clutter_colorize_effect_parent_class); parent_class = CLUTTER_EFFECT_CLASS (clutter_colorize_effect_parent_class);
return parent_class->pre_paint (effect, node, paint_context); if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_colorize_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
guint8 paint_opacity;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
} }
static void static void
@@ -198,7 +233,7 @@ clutter_colorize_effect_class_init (ClutterColorizeEffectClass *klass)
ClutterOffscreenEffectClass *offscreen_class; ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_pipeline = clutter_colorize_effect_create_pipeline; offscreen_class->paint_target = clutter_colorize_effect_paint_target;
effect_class->pre_paint = clutter_colorize_effect_pre_paint; effect_class->pre_paint = clutter_colorize_effect_pre_paint;

View File

@@ -58,12 +58,9 @@
#include <cogl/cogl.h> #include <cogl/cogl.h>
#include "clutter-color.h"
#include "clutter-debug.h" #include "clutter-debug.h"
#include "clutter-enum-types.h" #include "clutter-enum-types.h"
#include "clutter-offscreen-effect-private.h" #include "clutter-offscreen-effect-private.h"
#include "clutter-paint-node.h"
#include "clutter-paint-nodes.h"
#include "clutter-private.h" #include "clutter-private.h"
#define DEFAULT_N_TILES 32 #define DEFAULT_N_TILES 32
@@ -169,16 +166,19 @@ clutter_deform_effect_set_actor (ClutterActorMeta *meta,
static void static void
clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect, clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect); ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
ClutterDeformEffectPrivate *priv = self->priv; ClutterDeformEffectPrivate *priv = self->priv;
CoglHandle material;
CoglPipeline *pipeline; CoglPipeline *pipeline;
CoglDepthState depth_state; CoglDepthState depth_state;
CoglFramebuffer *fb =
clutter_paint_context_get_framebuffer (paint_context);
if (priv->is_dirty) if (priv->is_dirty)
{ {
graphene_rect_t rect;
gboolean mapped_buffer; gboolean mapped_buffer;
CoglVertexP3T2C4 *verts; CoglVertexP3T2C4 *verts;
ClutterActor *actor; ClutterActor *actor;
@@ -192,7 +192,12 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
/* if we don't have a target size, fall back to the actor's /* if we don't have a target size, fall back to the actor's
* allocation, though wrong it might be * allocation, though wrong it might be
*/ */
if (!clutter_offscreen_effect_get_target_size (effect, &width, &height)) if (clutter_offscreen_effect_get_target_rect (effect, &rect))
{
width = graphene_rect_get_width (&rect);
height = graphene_rect_get_height (&rect);
}
else
clutter_actor_get_size (actor, &width, &height); clutter_actor_get_size (actor, &width, &height);
/* XXX ideally, the sub-classes should tell us what they /* XXX ideally, the sub-classes should tell us what they
@@ -272,7 +277,8 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
priv->is_dirty = FALSE; priv->is_dirty = FALSE;
} }
pipeline = clutter_offscreen_effect_get_pipeline (effect); material = clutter_offscreen_effect_get_target (effect);
pipeline = COGL_PIPELINE (material);
/* enable depth testing */ /* enable depth testing */
cogl_depth_state_init (&depth_state); cogl_depth_state_init (&depth_state);
@@ -286,22 +292,12 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
COGL_PIPELINE_CULL_FACE_MODE_BACK); COGL_PIPELINE_CULL_FACE_MODE_BACK);
/* draw the front */ /* draw the front */
if (pipeline != NULL) if (material != NULL)
{ cogl_framebuffer_draw_primitive (fb, pipeline, priv->primitive);
ClutterPaintNode *front_node;
front_node = clutter_pipeline_node_new (pipeline);
clutter_paint_node_set_static_name (front_node,
"ClutterDeformEffect (front)");
clutter_paint_node_add_child (node, front_node);
clutter_paint_node_add_primitive (front_node, priv->primitive);
clutter_paint_node_unref (front_node);
}
/* draw the back */ /* draw the back */
if (priv->back_pipeline != NULL) if (priv->back_pipeline != NULL)
{ {
ClutterPaintNode *back_node;
CoglPipeline *back_pipeline; CoglPipeline *back_pipeline;
/* We probably shouldn't be modifying the user's material so /* We probably shouldn't be modifying the user's material so
@@ -311,30 +307,20 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
cogl_pipeline_set_cull_face_mode (back_pipeline, cogl_pipeline_set_cull_face_mode (back_pipeline,
COGL_PIPELINE_CULL_FACE_MODE_FRONT); COGL_PIPELINE_CULL_FACE_MODE_FRONT);
cogl_framebuffer_draw_primitive (fb, back_pipeline, priv->primitive);
back_node = clutter_pipeline_node_new (back_pipeline);
clutter_paint_node_set_static_name (back_node,
"ClutterDeformEffect (back)");
clutter_paint_node_add_child (node, back_node);
clutter_paint_node_add_primitive (back_node, priv->primitive);
clutter_paint_node_unref (back_node);
cogl_object_unref (back_pipeline); cogl_object_unref (back_pipeline);
} }
if (G_UNLIKELY (priv->lines_primitive != NULL)) if (G_UNLIKELY (priv->lines_primitive != NULL))
{ {
const ClutterColor *red; CoglContext *ctx =
ClutterPaintNode *lines_node; clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglPipeline *lines_pipeline = cogl_pipeline_new (ctx);
red = clutter_color_get_static (CLUTTER_COLOR_RED); cogl_pipeline_set_color4f (lines_pipeline, 1.0, 0, 0, 1.0);
cogl_framebuffer_draw_primitive (fb, lines_pipeline,
lines_node = clutter_color_node_new (red); priv->lines_primitive);
clutter_paint_node_set_static_name (lines_node, cogl_object_unref (lines_pipeline);
"ClutterDeformEffect (lines)");
clutter_paint_node_add_child (node, lines_node);
clutter_paint_node_add_primitive (lines_node, priv->lines_primitive);
clutter_paint_node_unref (lines_node);
} }
} }

View File

@@ -3,7 +3,13 @@
#define __CLUTTER_DEPRECATED_H_INSIDE__ #define __CLUTTER_DEPRECATED_H_INSIDE__
#include "deprecated/clutter-actor.h"
#include "deprecated/clutter-box.h"
#include "deprecated/clutter-container.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__ #undef __CLUTTER_DEPRECATED_H_INSIDE__

View File

@@ -111,25 +111,16 @@ G_DEFINE_TYPE (ClutterDesaturateEffect,
clutter_desaturate_effect, clutter_desaturate_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT); CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_desaturate_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterDesaturateEffect *desaturate_effect =
CLUTTER_DESATURATE_EFFECT (effect);
cogl_pipeline_set_layer_texture (desaturate_effect->pipeline, 0, texture);
return cogl_object_ref (desaturate_effect->pipeline);
}
static gboolean static gboolean
clutter_desaturate_effect_pre_paint (ClutterEffect *effect, clutter_desaturate_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect);
ClutterEffectClass *parent_class; ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL)) if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{ {
/* if we don't have support for GLSL shaders then we /* if we don't have support for GLSL shaders then we
@@ -143,7 +134,52 @@ clutter_desaturate_effect_pre_paint (ClutterEffect *effect,
} }
parent_class = CLUTTER_EFFECT_CLASS (clutter_desaturate_effect_parent_class); parent_class = CLUTTER_EFFECT_CLASS (clutter_desaturate_effect_parent_class);
return parent_class->pre_paint (effect, node, paint_context); if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_desaturate_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
CoglHandle texture;
guint8 paint_opacity;
texture = clutter_offscreen_effect_get_texture (effect);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture));
} }
static void static void
@@ -218,7 +254,7 @@ clutter_desaturate_effect_class_init (ClutterDesaturateEffectClass *klass)
ClutterOffscreenEffectClass *offscreen_class; ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_pipeline = clutter_desaturate_effect_create_pipeline; offscreen_class->paint_target = clutter_desaturate_effect_paint_target;
effect_class->pre_paint = clutter_desaturate_effect_pre_paint; effect_class->pre_paint = clutter_desaturate_effect_pre_paint;

View File

@@ -5,11 +5,14 @@
G_BEGIN_DECLS G_BEGIN_DECLS
gboolean _clutter_effect_pre_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context);
void _clutter_effect_post_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context);
gboolean _clutter_effect_modify_paint_volume (ClutterEffect *effect, gboolean _clutter_effect_modify_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume); ClutterPaintVolume *volume);
gboolean _clutter_effect_has_custom_paint_volume (ClutterEffect *effect); gboolean _clutter_effect_has_custom_paint_volume (ClutterEffect *effect);
void _clutter_effect_paint (ClutterEffect *effect, void _clutter_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context, ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags); ClutterEffectPaintFlags flags);
void _clutter_effect_pick (ClutterEffect *effect, void _clutter_effect_pick (ClutterEffect *effect,

View File

@@ -169,8 +169,6 @@
#include "clutter-effect-private.h" #include "clutter-effect-private.h"
#include "clutter-enum-types.h" #include "clutter-enum-types.h"
#include "clutter-marshal.h" #include "clutter-marshal.h"
#include "clutter-paint-node-private.h"
#include "clutter-paint-nodes.h"
#include "clutter-private.h" #include "clutter-private.h"
#include "clutter-actor-private.h" #include "clutter-actor-private.h"
@@ -180,7 +178,6 @@ G_DEFINE_ABSTRACT_TYPE (ClutterEffect,
static gboolean static gboolean
clutter_effect_real_pre_paint (ClutterEffect *effect, clutter_effect_real_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
return TRUE; return TRUE;
@@ -188,7 +185,6 @@ clutter_effect_real_pre_paint (ClutterEffect *effect,
static void static void
clutter_effect_real_post_paint (ClutterEffect *effect, clutter_effect_real_post_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
} }
@@ -200,41 +196,26 @@ clutter_effect_real_modify_paint_volume (ClutterEffect *effect,
return TRUE; return TRUE;
} }
static void
clutter_effect_real_paint_node (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterPaintNode *actor_node;
ClutterActor *actor;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
actor_node = clutter_actor_node_new (actor, -1);
clutter_paint_node_add_child (node, actor_node);
clutter_paint_node_unref (actor_node);
}
static void static void
clutter_effect_real_paint (ClutterEffect *effect, clutter_effect_real_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context, ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags) ClutterEffectPaintFlags flags)
{ {
ClutterEffectClass *effect_class = CLUTTER_EFFECT_GET_CLASS (effect); ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (effect);
ClutterActor *actor;
gboolean pre_paint_succeeded; gboolean pre_paint_succeeded;
/* The default implementation provides a compatibility wrapper for /* The default implementation provides a compatibility wrapper for
effects that haven't migrated to use the 'paint' virtual yet. This effects that haven't migrated to use the 'paint' virtual yet. This
just calls the old pre and post virtuals before chaining on */ just calls the old pre and post virtuals before chaining on */
pre_paint_succeeded = effect_class->pre_paint (effect, node,paint_context); pre_paint_succeeded = _clutter_effect_pre_paint (effect, paint_context);
effect_class->paint_node (effect, node, paint_context, flags); actor = clutter_actor_meta_get_actor (actor_meta);
clutter_actor_continue_paint (actor, paint_context);
if (pre_paint_succeeded) if (pre_paint_succeeded)
effect_class->post_paint (effect, node, paint_context); _clutter_effect_post_paint (effect, paint_context);
} }
static void static void
@@ -274,7 +255,6 @@ clutter_effect_class_init (ClutterEffectClass *klass)
klass->post_paint = clutter_effect_real_post_paint; klass->post_paint = clutter_effect_real_post_paint;
klass->modify_paint_volume = clutter_effect_real_modify_paint_volume; klass->modify_paint_volume = clutter_effect_real_modify_paint_volume;
klass->paint = clutter_effect_real_paint; klass->paint = clutter_effect_real_paint;
klass->paint_node = clutter_effect_real_paint_node;
klass->pick = clutter_effect_real_pick; klass->pick = clutter_effect_real_pick;
} }
@@ -283,18 +263,32 @@ clutter_effect_init (ClutterEffect *self)
{ {
} }
gboolean
_clutter_effect_pre_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context)
{
g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
return CLUTTER_EFFECT_GET_CLASS (effect)->pre_paint (effect, paint_context);
}
void
_clutter_effect_post_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context)
{
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
CLUTTER_EFFECT_GET_CLASS (effect)->post_paint (effect, paint_context);
}
void void
_clutter_effect_paint (ClutterEffect *effect, _clutter_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context, ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags) ClutterEffectPaintFlags flags)
{ {
g_return_if_fail (CLUTTER_IS_EFFECT (effect)); g_return_if_fail (CLUTTER_IS_EFFECT (effect));
CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect, CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect, paint_context, flags);
node,
paint_context,
flags);
} }
void void

View File

@@ -77,21 +77,14 @@ struct _ClutterEffectClass
/*< public >*/ /*< public >*/
gboolean (* pre_paint) (ClutterEffect *effect, gboolean (* pre_paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context); ClutterPaintContext *paint_context);
void (* post_paint) (ClutterEffect *effect, void (* post_paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context); ClutterPaintContext *paint_context);
gboolean (* modify_paint_volume) (ClutterEffect *effect, gboolean (* modify_paint_volume) (ClutterEffect *effect,
ClutterPaintVolume *volume); ClutterPaintVolume *volume);
void (* paint) (ClutterEffect *effect, void (* paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags);
void (* paint_node) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context, ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags); ClutterEffectPaintFlags flags);
void (* pick) (ClutterEffect *effect, void (* pick) (ClutterEffect *effect,

View File

@@ -1317,6 +1317,8 @@ typedef enum
* painting the stages * painting the stages
* @CLUTTER_REPAINT_FLAGS_POST_PAINT: Run the repaint function after * @CLUTTER_REPAINT_FLAGS_POST_PAINT: Run the repaint function after
* painting the stages * 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(). * Flags to pass to clutter_threads_add_repaint_func_full().
* *
@@ -1326,6 +1328,7 @@ typedef enum
{ {
CLUTTER_REPAINT_FLAGS_PRE_PAINT = 1 << 0, CLUTTER_REPAINT_FLAGS_PRE_PAINT = 1 << 0,
CLUTTER_REPAINT_FLAGS_POST_PAINT = 1 << 1, CLUTTER_REPAINT_FLAGS_POST_PAINT = 1 << 1,
CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD = 1 << 2
} ClutterRepaintFlags; } ClutterRepaintFlags;
/** /**

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

@@ -692,6 +692,20 @@ _clutter_input_device_free_touch_info (gpointer data)
g_slice_free (ClutterTouchInfo, 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 static void
_clutter_input_device_associate_actor (ClutterInputDevice *device, _clutter_input_device_associate_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence, ClutterEventSequence *sequence,
@@ -801,7 +815,7 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterActor *actor, ClutterActor *actor,
gboolean emit_crossing) gboolean emit_crossing)
{ {
ClutterActor *old_actor = clutter_input_device_get_actor (device, sequence); ClutterActor *old_actor = _clutter_input_device_get_actor (device, sequence);
if (old_actor == actor) if (old_actor == actor)
return; return;
@@ -836,7 +850,7 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
} }
/* processing the event might have destroyed the actor */ /* 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, _clutter_input_device_unassociate_actor (device,
old_actor, old_actor,
tmp_old_actor == NULL); tmp_old_actor == NULL);
@@ -1040,7 +1054,7 @@ clutter_input_device_update (ClutterInputDevice *device,
clutter_input_device_get_coords (device, sequence, &point); clutter_input_device_get_coords (device, sequence, &point);
old_cursor_actor = clutter_input_device_get_actor (device, sequence); old_cursor_actor = _clutter_input_device_get_actor (device, sequence);
new_cursor_actor = new_cursor_actor =
_clutter_stage_do_pick (stage, point.x, point.y, CLUTTER_PICK_REACTIVE); _clutter_stage_do_pick (stage, point.x, point.y, CLUTTER_PICK_REACTIVE);
@@ -1071,33 +1085,22 @@ clutter_input_device_update (ClutterInputDevice *device,
} }
/** /**
* clutter_input_device_get_actor: * clutter_input_device_get_pointer_actor:
* @device: a #ClutterInputDevice * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
* @sequence: (allow-none): an optional #ClutterEventSequence
* *
* Retrieves the #ClutterActor underneath the pointer or touchpoint * Retrieves the #ClutterActor underneath the pointer of @device
* of @device and @sequence.
* *
* Return value: (transfer none): a pointer to the #ClutterActor or %NULL * Return value: (transfer none): a pointer to the #ClutterActor or %NULL
* *
* Since: 1.2 * Since: 1.2
*/ */
ClutterActor * ClutterActor *
clutter_input_device_get_actor (ClutterInputDevice *device, clutter_input_device_get_pointer_actor (ClutterInputDevice *device)
ClutterEventSequence *sequence)
{ {
ClutterTouchInfo *info;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); 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;
info = g_hash_table_lookup (device->touch_sequences_info, sequence);
g_return_val_if_fail (info != NULL, NULL);
return info->actor;
} }
/** /**

View File

@@ -92,8 +92,7 @@ gboolean clutter_input_device_get_coords (ClutterInputDevi
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device); ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device);
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterActor * clutter_input_device_get_actor (ClutterInputDevice *device, ClutterActor * clutter_input_device_get_pointer_actor (ClutterInputDevice *device);
ClutterEventSequence *sequence);
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device); ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device);
CLUTTER_EXPORT CLUTTER_EXPORT

View File

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

View File

@@ -61,6 +61,7 @@
#include "clutter-input-pointer-a11y-private.h" #include "clutter-input-pointer-a11y-private.h"
#include "clutter-graphene.h" #include "clutter-graphene.h"
#include "clutter-main.h" #include "clutter-main.h"
#include "clutter-master-clock.h"
#include "clutter-mutter.h" #include "clutter-mutter.h"
#include "clutter-paint-node-private.h" #include "clutter-paint-node-private.h"
#include "clutter-private.h" #include "clutter-private.h"
@@ -82,6 +83,10 @@
/* main context */ /* main context */
static ClutterMainContext *ClutterCntx = NULL; static ClutterMainContext *ClutterCntx = NULL;
G_LOCK_DEFINE_STATIC (ClutterCntx);
/* main lock and locking/unlocking functions */
static GMutex clutter_threads_mutex;
/* command line options */ /* command line options */
static gboolean clutter_is_initialized = FALSE; static gboolean clutter_is_initialized = FALSE;
@@ -140,6 +145,12 @@ static const GDebugKey clutter_paint_debug_keys[] = {
{ "damage-region", CLUTTER_DEBUG_PAINT_DAMAGE_REGION }, { "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 ENVIRONMENT_GROUP "Environment"
#define DEBUG_GROUP "Debug" #define DEBUG_GROUP "Debug"
@@ -508,7 +519,11 @@ clutter_main (void)
main_loops = g_slist_prepend (main_loops, loop); main_loops = g_slist_prepend (main_loops, loop);
if (g_main_loop_is_running (main_loops->data)) if (g_main_loop_is_running (main_loops->data))
g_main_loop_run (loop); {
_clutter_threads_release_lock ();
g_main_loop_run (loop);
_clutter_threads_acquire_lock ();
}
main_loops = g_slist_remove (main_loops, loop); main_loops = g_slist_remove (main_loops, loop);
@@ -525,9 +540,13 @@ _clutter_threads_dispatch (gpointer data)
ClutterThreadsDispatch *dispatch = data; ClutterThreadsDispatch *dispatch = data;
gboolean ret = FALSE; gboolean ret = FALSE;
_clutter_threads_acquire_lock ();
if (!g_source_is_destroyed (g_main_current_source ())) if (!g_source_is_destroyed (g_main_current_source ()))
ret = dispatch->func (dispatch->data); ret = dispatch->func (dispatch->data);
_clutter_threads_release_lock ();
return ret; return ret;
} }
@@ -752,6 +771,40 @@ clutter_threads_add_timeout (guint interval,
NULL); 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 gboolean
_clutter_context_is_initialized (void) _clutter_context_is_initialized (void)
{ {
@@ -761,8 +814,8 @@ _clutter_context_is_initialized (void)
return ClutterCntx->is_initialized; return ClutterCntx->is_initialized;
} }
ClutterMainContext * static ClutterMainContext *
_clutter_context_get_default (void) clutter_context_get_default_unlocked (void)
{ {
if (G_UNLIKELY (ClutterCntx == NULL)) if (G_UNLIKELY (ClutterCntx == NULL))
{ {
@@ -793,6 +846,20 @@ _clutter_context_get_default (void)
return ClutterCntx; 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 static gboolean
clutter_arg_direction_cb (const char *key, clutter_arg_direction_cb (const char *key,
const char *value, const char *value,
@@ -1982,8 +2049,7 @@ _clutter_process_event_details (ClutterActor *stage,
emit_touch_event (event, device); emit_touch_event (event, device);
if (event->type == CLUTTER_TOUCH_END || if (event->type == CLUTTER_TOUCH_END)
event->type == CLUTTER_TOUCH_CANCEL)
_clutter_input_device_remove_event_sequence (device, event); _clutter_input_device_remove_event_sequence (device, event);
break; break;
@@ -2018,8 +2084,7 @@ _clutter_process_event_details (ClutterActor *stage,
emit_touch_event (event, device); emit_touch_event (event, device);
if (event->type == CLUTTER_TOUCH_END || if (event->type == CLUTTER_TOUCH_END)
event->type == CLUTTER_TOUCH_CANCEL)
_clutter_input_device_remove_event_sequence (device, event); _clutter_input_device_remove_event_sequence (device, event);
break; break;
@@ -2089,6 +2154,27 @@ _clutter_process_event (ClutterEvent *event)
context->current_event = g_slist_delete_link (context->current_event, context->current_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 void
clutter_base_init (void) clutter_base_init (void)
{ {
@@ -2103,6 +2189,9 @@ clutter_base_init (void)
g_type_init (); g_type_init ();
#endif #endif
/* initialise the Big Clutter Lock™ if necessary */
clutter_threads_init_default ();
clutter_graphene_init (); clutter_graphene_init ();
} }
} }
@@ -2170,7 +2259,9 @@ clutter_threads_remove_repaint_func (guint handle_id)
g_return_if_fail (handle_id > 0); 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; l = context->repaint_funcs;
while (l != NULL) while (l != NULL)
{ {
@@ -2193,6 +2284,8 @@ clutter_threads_remove_repaint_func (guint handle_id)
l = l->next; l = l->next;
} }
_clutter_context_unlock ();
} }
/** /**
@@ -2291,13 +2384,16 @@ clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
g_return_val_if_fail (func != NULL, 0); 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 = g_slice_new (ClutterRepaintFunction);
repaint_func->id = context->last_repaint_id++; 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->func = func;
repaint_func->data = data; repaint_func->data = data;
repaint_func->notify = notify; repaint_func->notify = notify;
@@ -2305,6 +2401,15 @@ clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
context->repaint_funcs = g_list_prepend (context->repaint_funcs, context->repaint_funcs = g_list_prepend (context->repaint_funcs,
repaint_func); 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; return repaint_func->id;
} }

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 CLUTTER_EXPORT
GList * clutter_stage_peek_stage_views (ClutterStage *stage); GList * clutter_stage_peek_stage_views (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_actor_is_effectively_on_stage_view (ClutterActor *self,
ClutterStageView *view);
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_set_custom_backend_func (ClutterBackend *(* func) (void)); void clutter_set_custom_backend_func (ClutterBackend *(* func) (void));
@@ -73,7 +69,13 @@ gboolean clutter_stage_paint_to_buffer (ClutterStage *stage,
GError **error); GError **error);
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_stage_clear_stage_views (ClutterStage *stage); 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 CLUTTER_EXPORT
void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view, void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view,

View File

@@ -60,30 +60,6 @@
* #ClutterOffscreenEffectClass.create_texture() virtual function; no chain up * #ClutterOffscreenEffectClass.create_texture() virtual function; no chain up
* to the #ClutterOffscreenEffect implementation is required in this * to the #ClutterOffscreenEffect implementation is required in this
* case. * case.
*
* ## Paint nodes
*
* #ClutterOffscreenEffect is generates the following paint node tree:
*
* |[<!-- language="plain" -->
* Effect
* ├─────────┐
* Layer Pipeline
* │
* Actor
* ]|
*
* When the actor contents are cached, the generated paint node tree
* looks like this:
*
* |[<!-- language="plain" -->
* Effect
* │
* Pipeline
* ]|
*
* In both cases, the "Pipeline" node is created with the return value
* of #ClutterOffscreenEffectClass.create_pipeline().
*/ */
#include "clutter-build-config.h" #include "clutter-build-config.h"
@@ -99,8 +75,6 @@
#include "clutter-private.h" #include "clutter-private.h"
#include "clutter-stage-private.h" #include "clutter-stage-private.h"
#include "clutter-paint-context-private.h" #include "clutter-paint-context-private.h"
#include "clutter-paint-node-private.h"
#include "clutter-paint-nodes.h"
#include "clutter-paint-volume-private.h" #include "clutter-paint-volume-private.h"
#include "clutter-actor-box-private.h" #include "clutter-actor-box-private.h"
@@ -113,6 +87,8 @@ struct _ClutterOffscreenEffectPrivate
ClutterActor *actor; ClutterActor *actor;
ClutterActor *stage; ClutterActor *stage;
graphene_point3d_t position;
int fbo_offset_x; int fbo_offset_x;
int fbo_offset_y; int fbo_offset_y;
@@ -182,25 +158,6 @@ ensure_pipeline_filter_for_scale (ClutterOffscreenEffect *self,
filter, filter); filter, filter);
} }
static CoglPipeline *
clutter_offscreen_effect_real_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterOffscreenEffectPrivate *priv = effect->priv;
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglPipeline *pipeline;
float resource_scale;
resource_scale = clutter_actor_get_real_resource_scale (priv->actor);
pipeline = cogl_pipeline_new (ctx);
ensure_pipeline_filter_for_scale (effect, resource_scale);
cogl_pipeline_set_layer_texture (pipeline, 0, texture);
return pipeline;
}
static gboolean static gboolean
update_fbo (ClutterEffect *effect, update_fbo (ClutterEffect *effect,
int target_width, int target_width,
@@ -209,8 +166,6 @@ update_fbo (ClutterEffect *effect,
{ {
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv; ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterOffscreenEffectClass *offscreen_class =
CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (effect);
priv->stage = clutter_actor_get_stage (priv->actor); priv->stage = clutter_actor_get_stage (priv->actor);
if (priv->stage == NULL) if (priv->stage == NULL)
@@ -230,6 +185,15 @@ update_fbo (ClutterEffect *effect,
return TRUE; return TRUE;
} }
if (priv->pipeline == NULL)
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
priv->pipeline = cogl_pipeline_new (ctx);
ensure_pipeline_filter_for_scale (self, resource_scale);
}
g_clear_pointer (&priv->texture, cogl_object_unref); g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_pointer (&priv->offscreen, cogl_object_unref); g_clear_pointer (&priv->offscreen, cogl_object_unref);
@@ -238,6 +202,8 @@ update_fbo (ClutterEffect *effect,
if (priv->texture == NULL) if (priv->texture == NULL)
return FALSE; return FALSE;
cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->texture);
priv->target_width = target_width; priv->target_width = target_width;
priv->target_height = target_height; priv->target_height = target_height;
@@ -246,7 +212,8 @@ update_fbo (ClutterEffect *effect,
{ {
g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC); g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC);
cogl_clear_object (&priv->pipeline); cogl_object_unref (priv->pipeline);
priv->pipeline = NULL;
priv->target_width = 0; priv->target_width = 0;
priv->target_height = 0; priv->target_height = 0;
@@ -254,42 +221,50 @@ update_fbo (ClutterEffect *effect,
return FALSE; return FALSE;
} }
cogl_clear_object (&priv->pipeline);
priv->pipeline = offscreen_class->create_pipeline (self, priv->texture);
return TRUE; return TRUE;
} }
static gboolean static gboolean
clutter_offscreen_effect_pre_paint (ClutterEffect *effect, clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv; ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterActorBox raw_box, box; ClutterActorBox raw_box, box;
ClutterActor *stage; ClutterActor *stage;
CoglMatrix projection, modelview; CoglMatrix projection, old_modelview, modelview;
const ClutterPaintVolume *volume; const ClutterPaintVolume *volume;
CoglColor transparent;
gfloat stage_width, stage_height; gfloat stage_width, stage_height;
gfloat target_width = -1, target_height = -1; gfloat target_width = -1, target_height = -1;
float resource_scale; CoglFramebuffer *framebuffer;
float ceiled_resource_scale; gfloat resource_scale;
gfloat ceiled_resource_scale;
graphene_point3d_t local_offset;
gfloat old_viewport[4];
local_offset = GRAPHENE_POINT3D_INIT (0.0f, 0.0f, 0.0f);
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect))) if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
goto fail; return FALSE;
if (priv->actor == NULL) if (priv->actor == NULL)
goto fail; return FALSE;
stage = _clutter_actor_get_stage_internal (priv->actor); stage = _clutter_actor_get_stage_internal (priv->actor);
clutter_actor_get_size (stage, &stage_width, &stage_height); clutter_actor_get_size (stage, &stage_width, &stage_height);
resource_scale = clutter_actor_get_real_resource_scale (priv->actor); if (_clutter_actor_get_real_resource_scale (priv->actor, &resource_scale))
{
ceiled_resource_scale = ceilf (resource_scale); ceiled_resource_scale = ceilf (resource_scale);
stage_width *= ceiled_resource_scale; stage_width *= ceiled_resource_scale;
stage_height *= 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 /* 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 * parent of priv->actor. Note that we may actually be painting a clone of
@@ -325,7 +300,12 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
/* First assert that the framebuffer is the right size... */ /* First assert that the framebuffer is the right size... */
if (!update_fbo (effect, target_width, target_height, resource_scale)) if (!update_fbo (effect, target_width, target_height, resource_scale))
goto fail; return FALSE;
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_get_modelview_matrix (framebuffer, &old_modelview);
clutter_paint_context_push_framebuffer (paint_context, priv->offscreen);
/* We don't want the FBO contents to be transformed. That could waste memory /* We don't want the FBO contents to be transformed. That could waste memory
* (e.g. during zoom), or result in something that's not rectangular (clipped * (e.g. during zoom), or result in something that's not rectangular (clipped
@@ -337,6 +317,13 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
clutter_actor_get_transform (priv->stage, &modelview); clutter_actor_get_transform (priv->stage, &modelview);
cogl_framebuffer_set_modelview_matrix (priv->offscreen, &modelview); cogl_framebuffer_set_modelview_matrix (priv->offscreen, &modelview);
/* Save the original viewport for calculating priv->position */
_clutter_stage_get_viewport (CLUTTER_STAGE (priv->stage),
&old_viewport[0],
&old_viewport[1],
&old_viewport[2],
&old_viewport[3]);
/* Set up the viewport so that it has the same size as the stage (avoid /* Set up the viewport so that it has the same size as the stage (avoid
* distortion), but translated to account for the FBO offset... * distortion), but translated to account for the FBO offset...
*/ */
@@ -350,22 +337,45 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
_clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage), _clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage),
&projection); &projection);
/* Now save the global position of the effect (not just of the actor).
* It doesn't appear anyone actually uses this yet, but get_target_rect is
* documented as returning it. So we should...
*/
_clutter_util_fully_transform_vertices (&old_modelview,
&projection,
old_viewport,
&local_offset,
&priv->position,
1);
cogl_framebuffer_set_projection_matrix (priv->offscreen, &projection); cogl_framebuffer_set_projection_matrix (priv->offscreen, &projection);
return TRUE; cogl_color_init_from_4ub (&transparent, 0, 0, 0, 0);
cogl_framebuffer_clear (priv->offscreen,
COGL_BUFFER_BIT_COLOR |
COGL_BUFFER_BIT_DEPTH,
&transparent);
fail: cogl_framebuffer_push_matrix (priv->offscreen);
cogl_clear_object (&priv->offscreen);
return FALSE; /* Override the actor's opacity to fully opaque - we paint the offscreen
* texture with the actor's paint opacity, so we need to do this to avoid
* multiplying the opacity twice.
*/
priv->old_opacity_override =
clutter_actor_get_opacity_override (priv->actor);
clutter_actor_set_opacity_override (priv->actor, 0xff);
return TRUE;
} }
static void static void
clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect, clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterOffscreenEffectPrivate *priv = effect->priv; ClutterOffscreenEffectPrivate *priv = effect->priv;
ClutterPaintNode *pipeline_node; CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
guint8 paint_opacity; guint8 paint_opacity;
paint_opacity = clutter_actor_get_paint_opacity (priv->actor); paint_opacity = clutter_actor_get_paint_opacity (priv->actor);
@@ -376,122 +386,95 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
paint_opacity, paint_opacity,
paint_opacity); paint_opacity);
pipeline_node = clutter_pipeline_node_new (priv->pipeline);
clutter_paint_node_set_static_name (pipeline_node,
"ClutterOffscreenEffect (pipeline)");
clutter_paint_node_add_child (node, pipeline_node);
/* At this point we are in stage coordinates translated so if /* At this point we are in stage coordinates translated so if
* we draw our texture using a textured quad the size of the paint * we draw our texture using a textured quad the size of the paint
* box then we will overlay where the actor would have drawn if it * box then we will overlay where the actor would have drawn if it
* hadn't been redirected offscreen. * hadn't been redirected offscreen.
*/ */
clutter_paint_node_add_rectangle (pipeline_node, cogl_framebuffer_draw_textured_rectangle (framebuffer,
&(ClutterActorBox) { priv->pipeline,
0.f, 0.f, 0, 0,
cogl_texture_get_width (priv->texture), cogl_texture_get_width (priv->texture),
cogl_texture_get_height (priv->texture), cogl_texture_get_height (priv->texture),
}); 0.0, 0.0,
1.0, 1.0);
clutter_paint_node_unref (pipeline_node);
} }
static void static void
clutter_offscreen_effect_paint_texture (ClutterOffscreenEffect *effect, clutter_offscreen_effect_paint_texture (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterOffscreenEffectPrivate *priv = effect->priv; ClutterOffscreenEffectPrivate *priv = effect->priv;
CoglMatrix transform; CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
CoglMatrix modelview;
float resource_scale; float resource_scale;
cogl_matrix_init_identity (&transform); cogl_framebuffer_push_matrix (framebuffer);
resource_scale = clutter_actor_get_resource_scale (priv->actor); /* The current modelview matrix is *almost* perfect already. It's only
* missing a correction for the expanded FBO and offset rendering within...
*/
cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview);
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; float paint_scale = 1.0f / resource_scale;
cogl_matrix_scale (&transform, paint_scale, paint_scale, 1); cogl_matrix_scale (&modelview, paint_scale, paint_scale, 1);
} }
cogl_matrix_translate (&transform, cogl_matrix_translate (&modelview,
priv->fbo_offset_x, priv->fbo_offset_x,
priv->fbo_offset_y, priv->fbo_offset_y,
0.0f); 0.0f);
cogl_framebuffer_set_modelview_matrix (framebuffer, &modelview);
if (!cogl_matrix_is_identity (&transform))
{
ClutterPaintNode *transform_node;
transform_node = clutter_transform_node_new (&transform);
clutter_paint_node_set_static_name (transform_node,
"ClutterOffscreenEffect (transform)");
clutter_paint_node_add_child (node, transform_node);
clutter_paint_node_unref (transform_node);
node = transform_node;
}
/* paint the target material; this is virtualized for /* paint the target material; this is virtualized for
* sub-classes that require special hand-holding * sub-classes that require special hand-holding
*/ */
clutter_offscreen_effect_paint_target (effect, node, paint_context); clutter_offscreen_effect_paint_target (effect, paint_context);
cogl_framebuffer_pop_matrix (framebuffer);
} }
static void static void
clutter_offscreen_effect_post_paint (ClutterEffect *effect, clutter_offscreen_effect_post_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv; ClutterOffscreenEffectPrivate *priv = self->priv;
CoglFramebuffer *framebuffer;
g_warn_if_fail (priv->offscreen); g_warn_if_fail (priv->offscreen);
g_warn_if_fail (priv->pipeline); g_warn_if_fail (priv->pipeline);
g_warn_if_fail (priv->actor); g_warn_if_fail (priv->actor);
clutter_offscreen_effect_paint_texture (self, node, paint_context); /* Restore the previous opacity override */
} if (priv->actor)
{
clutter_actor_set_opacity_override (priv->actor,
priv->old_opacity_override);
}
static void framebuffer = clutter_paint_context_get_framebuffer (paint_context);
clutter_offscreen_effect_paint_node (ClutterEffect *effect, cogl_framebuffer_pop_matrix (framebuffer);
ClutterPaintNode *node, clutter_paint_context_pop_framebuffer (paint_context);
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = offscreen_effect->priv;
ClutterPaintNode *layer_node;
ClutterPaintNode *actor_node;
layer_node = clutter_layer_node_new_with_framebuffer (priv->offscreen, clutter_offscreen_effect_paint_texture (self, paint_context);
priv->pipeline,
255);
clutter_paint_node_set_static_name (layer_node,
"ClutterOffscreenEffect (actor offscreen)");
clutter_paint_node_add_child (node, layer_node);
clutter_paint_node_unref (layer_node);
actor_node = clutter_actor_node_new (priv->actor, 255);
clutter_paint_node_add_child (layer_node, actor_node);
clutter_paint_node_unref (actor_node);
} }
static void static void
clutter_offscreen_effect_paint (ClutterEffect *effect, clutter_offscreen_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context, ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags) ClutterEffectPaintFlags flags)
{ {
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv; ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterEffectClass *parent_class =
CLUTTER_EFFECT_CLASS (clutter_offscreen_effect_parent_class);
if (flags & CLUTTER_EFFECT_PAINT_BYPASS_EFFECT) if (flags & CLUTTER_EFFECT_PAINT_BYPASS_EFFECT)
{ {
parent_class->paint_node (effect, node, paint_context, flags); clutter_actor_continue_paint (priv->actor, paint_context);
cogl_clear_object (&priv->offscreen); cogl_clear_object (&priv->offscreen);
return; return;
} }
@@ -500,9 +483,21 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
* then we can just use the cached image in the FBO. * then we can just use the cached image in the FBO.
*/ */
if (priv->offscreen == NULL || (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY)) if (priv->offscreen == NULL || (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY))
parent_class->paint (effect, node, paint_context, flags); {
ClutterEffectClass *effect_class = CLUTTER_EFFECT_GET_CLASS (effect);
gboolean pre_paint_succeeded;
pre_paint_succeeded = effect_class->pre_paint (effect, paint_context);
clutter_actor_continue_paint (priv->actor, paint_context);
if (pre_paint_succeeded)
effect_class->post_paint (effect, paint_context);
else
g_clear_pointer (&priv->offscreen, cogl_object_unref);
}
else else
clutter_offscreen_effect_paint_texture (self, node, paint_context); clutter_offscreen_effect_paint_texture (self, paint_context);
} }
static void static void
@@ -540,7 +535,6 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->create_texture = clutter_offscreen_effect_real_create_texture; klass->create_texture = clutter_offscreen_effect_real_create_texture;
klass->create_pipeline = clutter_offscreen_effect_real_create_pipeline;
klass->paint_target = clutter_offscreen_effect_real_paint_target; klass->paint_target = clutter_offscreen_effect_real_paint_target;
meta_class->set_actor = clutter_offscreen_effect_set_actor; meta_class->set_actor = clutter_offscreen_effect_set_actor;
@@ -549,7 +543,6 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
effect_class->pre_paint = clutter_offscreen_effect_pre_paint; effect_class->pre_paint = clutter_offscreen_effect_pre_paint;
effect_class->post_paint = clutter_offscreen_effect_post_paint; effect_class->post_paint = clutter_offscreen_effect_post_paint;
effect_class->paint = clutter_offscreen_effect_paint; effect_class->paint = clutter_offscreen_effect_paint;
effect_class->paint_node = clutter_offscreen_effect_paint_node;
gobject_class->finalize = clutter_offscreen_effect_finalize; gobject_class->finalize = clutter_offscreen_effect_finalize;
} }
@@ -590,34 +583,33 @@ clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect)
} }
/** /**
* clutter_offscreen_effect_get_pipeline: * clutter_offscreen_effect_get_target: (skip)
* @effect: a #ClutterOffscreenEffect * @effect: a #ClutterOffscreenEffect
* *
* Retrieves the pipeline used as a render target for the offscreen * Retrieves the material used as a render target for the offscreen
* buffer created by @effect * buffer created by @effect
* *
* You should only use the returned #CoglPipeline when painting. The * You should only use the returned #CoglMaterial when painting. The
* returned pipeline might change between different frames. * returned material might change between different frames.
* *
* Return value: (transfer none)(nullable): a #CoglPipeline. The * Return value: (transfer none): a #CoglMaterial or %NULL. The
* pipeline is owned by Clutter and it should not be modified * returned material is owned by Clutter and it should not be
* or freed * modified or freed
* *
* Since: 1.4 * Since: 1.4
*/ */
CoglPipeline * CoglMaterial *
clutter_offscreen_effect_get_pipeline (ClutterOffscreenEffect *effect) clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect)
{ {
g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect),
NULL); NULL);
return effect->priv->pipeline; return (CoglMaterial *)effect->priv->pipeline;
} }
/** /**
* clutter_offscreen_effect_paint_target: * clutter_offscreen_effect_paint_target:
* @effect: a #ClutterOffscreenEffect * @effect: a #ClutterOffscreenEffect
* @node: a #ClutterPaintNode
* @paint_context: a #ClutterPaintContext * @paint_context: a #ClutterPaintContext
* *
* Calls the paint_target() virtual function of the @effect * Calls the paint_target() virtual function of the @effect
@@ -626,13 +618,11 @@ clutter_offscreen_effect_get_pipeline (ClutterOffscreenEffect *effect)
*/ */
void void
clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect, clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
g_return_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect)); g_return_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect));
CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (effect)->paint_target (effect, CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (effect)->paint_target (effect,
node,
paint_context); paint_context);
} }
@@ -680,6 +670,8 @@ clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect,
* and %FALSE otherwise * and %FALSE otherwise
* *
* Since: 1.8 * Since: 1.8
*
* Deprecated: 1.14: Use clutter_offscreen_effect_get_target_rect() instead
*/ */
gboolean gboolean
clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect, clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
@@ -703,3 +695,43 @@ clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
return TRUE; return TRUE;
} }
/**
* clutter_offscreen_effect_get_target_rect:
* @effect: a #ClutterOffscreenEffect
* @rect: (out caller-allocates): return location for the target area
*
* Retrieves the origin and size of the offscreen buffer used by @effect to
* paint the actor to which it has been applied.
*
* This function should only be called by #ClutterOffscreenEffect
* implementations, from within the #ClutterOffscreenEffectClass.paint_target()
* virtual function.
*
* Return value: %TRUE if the offscreen buffer has a valid rectangle,
* and %FALSE otherwise
*
* Since: 1.14
*/
gboolean
clutter_offscreen_effect_get_target_rect (ClutterOffscreenEffect *effect,
graphene_rect_t *rect)
{
ClutterOffscreenEffectPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), FALSE);
g_return_val_if_fail (rect != NULL, FALSE);
priv = effect->priv;
if (priv->texture == NULL)
return FALSE;
graphene_rect_init (rect,
priv->position.x,
priv->position.y,
cogl_texture_get_width (priv->texture),
cogl_texture_get_height (priv->texture));
return TRUE;
}

View File

@@ -79,10 +79,7 @@ struct _ClutterOffscreenEffectClass
CoglHandle (* create_texture) (ClutterOffscreenEffect *effect, CoglHandle (* create_texture) (ClutterOffscreenEffect *effect,
gfloat width, gfloat width,
gfloat height); gfloat height);
CoglPipeline* (* create_pipeline) (ClutterOffscreenEffect *effect,
CoglTexture *texture);
void (* paint_target) (ClutterOffscreenEffect *effect, void (* paint_target) (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context); ClutterPaintContext *paint_context);
/*< private >*/ /*< private >*/
@@ -99,25 +96,28 @@ CLUTTER_EXPORT
GType clutter_offscreen_effect_get_type (void) G_GNUC_CONST; GType clutter_offscreen_effect_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT CLUTTER_EXPORT
CoglPipeline * clutter_offscreen_effect_get_pipeline (ClutterOffscreenEffect *effect); CoglMaterial * clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect);
CLUTTER_EXPORT CLUTTER_EXPORT
CoglHandle clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect); CoglHandle clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect);
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect, void clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context); ClutterPaintContext *paint_context);
CLUTTER_EXPORT CLUTTER_EXPORT
CoglHandle clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect, CoglHandle clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect,
gfloat width, gfloat width,
gfloat height); gfloat height);
CLUTTER_EXPORT CLUTTER_DEPRECATED_FOR (clutter_offscreen_effect_get_target_rect)
gboolean clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect, gboolean clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
gfloat *width, gfloat *width,
gfloat *height); gfloat *height);
CLUTTER_EXPORT
gboolean clutter_offscreen_effect_get_target_rect (ClutterOffscreenEffect *effect,
graphene_rect_t *rect);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_OFFSCREEN_EFFECT_H__ */ #endif /* __CLUTTER_OFFSCREEN_EFFECT_H__ */

View File

@@ -141,26 +141,6 @@ ClutterPaintNode * clutter_paint_node_get_last_child (Clutter
G_GNUC_INTERNAL G_GNUC_INTERNAL
ClutterPaintNode * clutter_paint_node_get_parent (ClutterPaintNode *node); ClutterPaintNode * clutter_paint_node_get_parent (ClutterPaintNode *node);
#define CLUTTER_TYPE_EFFECT_NODE (clutter_effect_node_get_type ())
#define CLUTTER_EFFECT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_EFFECT_NODE, ClutterEffectNode))
#define CLUTTER_IS_EFFECT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_EFFECT_NODE))
/**
* ClutterEffectNode:
*
* The #ClutterEffectNode structure is an opaque
* type whose members cannot be directly accessed.
*/
typedef struct _ClutterEffectNode ClutterEffectNode;
typedef struct _ClutterEffectNode ClutterEffectNodeClass;
CLUTTER_EXPORT
GType clutter_effect_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_effect_node_new (ClutterEffect *actor);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_PAINT_NODE_PRIVATE_H__ */ #endif /* __CLUTTER_PAINT_NODE_PRIVATE_H__ */

View File

@@ -551,7 +551,7 @@ clutter_pipeline_node_init (ClutterPipelineNode *self)
} }
/** /**
* clutter_pipeline_node_new: * clutter_pipeline_node_new: (skip)
* @pipeline: (allow-none): a Cogl pipeline state object, or %NULL * @pipeline: (allow-none): a Cogl pipeline state object, or %NULL
* *
* Creates a new #ClutterPaintNode that will use the @pipeline to * Creates a new #ClutterPaintNode that will use the @pipeline to
@@ -1115,8 +1115,6 @@ struct _ClutterActorNode
ClutterPaintNode parent_instance; ClutterPaintNode parent_instance;
ClutterActor *actor; ClutterActor *actor;
int opacity_override;
int old_opacity_override;
}; };
struct _ClutterActorNodeClass struct _ClutterActorNodeClass
@@ -1132,14 +1130,6 @@ clutter_actor_node_pre_draw (ClutterPaintNode *node,
{ {
ClutterActorNode *actor_node = CLUTTER_ACTOR_NODE (node); ClutterActorNode *actor_node = CLUTTER_ACTOR_NODE (node);
if (actor_node->opacity_override != -1)
{
actor_node->old_opacity_override =
clutter_actor_get_opacity_override (actor_node->actor);
clutter_actor_set_opacity_override (actor_node->actor,
actor_node->opacity_override);
}
CLUTTER_SET_PRIVATE_FLAGS (actor_node->actor, CLUTTER_IN_PAINT); CLUTTER_SET_PRIVATE_FLAGS (actor_node->actor, CLUTTER_IN_PAINT);
return TRUE; return TRUE;
@@ -1161,12 +1151,6 @@ clutter_actor_node_post_draw (ClutterPaintNode *node,
ClutterActorNode *actor_node = CLUTTER_ACTOR_NODE (node); ClutterActorNode *actor_node = CLUTTER_ACTOR_NODE (node);
CLUTTER_UNSET_PRIVATE_FLAGS (actor_node->actor, CLUTTER_IN_PAINT); CLUTTER_UNSET_PRIVATE_FLAGS (actor_node->actor, CLUTTER_IN_PAINT);
if (actor_node->opacity_override != -1)
{
clutter_actor_set_opacity_override (actor_node->actor,
actor_node->old_opacity_override);
}
} }
static JsonNode * static JsonNode *
@@ -1208,7 +1192,6 @@ clutter_actor_node_init (ClutterActorNode *self)
/* /*
* clutter_actor_node_new: * clutter_actor_node_new:
* @actor: the actor to paint * @actor: the actor to paint
* @opacity: opacity to draw the actor with, or -1 to use the actor's opacity
* *
* Creates a new #ClutterActorNode. * Creates a new #ClutterActorNode.
* *
@@ -1220,8 +1203,7 @@ clutter_actor_node_init (ClutterActorNode *self)
* Use clutter_paint_node_unref() when done. * Use clutter_paint_node_unref() when done.
*/ */
ClutterPaintNode * ClutterPaintNode *
clutter_actor_node_new (ClutterActor *actor, clutter_actor_node_new (ClutterActor *actor)
int opacity)
{ {
ClutterActorNode *res; ClutterActorNode *res;
@@ -1229,96 +1211,11 @@ clutter_actor_node_new (ClutterActor *actor,
res = _clutter_paint_node_create (CLUTTER_TYPE_ACTOR_NODE); res = _clutter_paint_node_create (CLUTTER_TYPE_ACTOR_NODE);
res->actor = actor; res->actor = actor;
res->opacity_override = CLAMP (opacity, -1, 255);
return (ClutterPaintNode *) res; return (ClutterPaintNode *) res;
} }
/*
* ClutterEffectNode
*/
struct _ClutterEffectNode
{
ClutterPaintNode parent_instance;
ClutterEffect *effect;
};
struct _ClutterEffectNodeClass
{
ClutterPaintNodeClass parent_class;
};
G_DEFINE_TYPE (ClutterEffectNode, clutter_effect_node, CLUTTER_TYPE_PAINT_NODE)
static JsonNode *
clutter_effect_node_serialize (ClutterPaintNode *node)
{
ClutterEffectNode *effect_node = CLUTTER_EFFECT_NODE (node);
ClutterActorMeta *effect_meta = CLUTTER_ACTOR_META (effect_node->effect);
g_autoptr (JsonBuilder) builder = NULL;
g_autoptr (GString) string = NULL;
const char *meta_name;
meta_name = clutter_actor_meta_get_name (effect_meta);
string = g_string_new (NULL);
g_string_append (string, G_OBJECT_TYPE_NAME (effect_node->effect));
g_string_append (string, " (");
if (meta_name)
g_string_append_printf (string, "\"%s\"", meta_name);
else
g_string_append (string, "unnamed");
g_string_append (string, ")");
builder = json_builder_new ();
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "effect");
json_builder_add_string_value (builder, string->str);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_effect_node_class_init (ClutterEffectNodeClass *klass)
{
ClutterPaintNodeClass *node_class;
node_class = CLUTTER_PAINT_NODE_CLASS (klass);
node_class->serialize = clutter_effect_node_serialize;
}
static void
clutter_effect_node_init (ClutterEffectNode *self)
{
}
/*
* clutter_effect_node_new:
* @actor: the actor to paint
*
* Creates a new #ClutterEffectNode.
*
* Return value: (transfer full): the newly created #ClutterEffectNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_effect_node_new (ClutterEffect *effect)
{
ClutterEffectNode *res;
g_assert (effect != NULL);
res = _clutter_paint_node_create (CLUTTER_TYPE_EFFECT_NODE);
res->effect = effect;
return (ClutterPaintNode *) res;
}
/* /*
* ClutterLayerNode * ClutterLayerNode
*/ */
@@ -1338,7 +1235,6 @@ struct _ClutterLayerNode
CoglFramebuffer *offscreen; CoglFramebuffer *offscreen;
guint8 opacity; guint8 opacity;
gboolean update_modelview;
}; };
struct _ClutterLayerNodeClass struct _ClutterLayerNodeClass
@@ -1353,6 +1249,8 @@ clutter_layer_node_pre_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterLayerNode *lnode = (ClutterLayerNode *) node; ClutterLayerNode *lnode = (ClutterLayerNode *) node;
CoglFramebuffer *framebuffer;
CoglMatrix matrix;
/* if we were unable to create an offscreen buffer for this node, then /* if we were unable to create an offscreen buffer for this node, then
* we simply ignore it * we simply ignore it
@@ -1360,30 +1258,29 @@ clutter_layer_node_pre_draw (ClutterPaintNode *node,
if (lnode->offscreen == NULL) if (lnode->offscreen == NULL)
return FALSE; return FALSE;
if (lnode->update_modelview) /* if no geometry was submitted for this node then we simply ignore it */
{ if (node->operations == NULL)
CoglFramebuffer *framebuffer; return FALSE;
CoglMatrix matrix;
/* copy the same modelview from the current framebuffer to the one we /* copy the same modelview from the current framebuffer to the one we
* are going to use * are going to use
*/ */
framebuffer = clutter_paint_context_get_framebuffer (paint_context); framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_get_modelview_matrix (framebuffer, &matrix); cogl_framebuffer_get_modelview_matrix (framebuffer, &matrix);
cogl_framebuffer_set_modelview_matrix (lnode->offscreen, &matrix);
cogl_framebuffer_set_viewport (lnode->offscreen,
lnode->viewport.x,
lnode->viewport.y,
lnode->viewport.width,
lnode->viewport.height);
cogl_framebuffer_set_projection_matrix (lnode->offscreen,
&lnode->projection);
}
clutter_paint_context_push_framebuffer (paint_context, lnode->offscreen); clutter_paint_context_push_framebuffer (paint_context, lnode->offscreen);
cogl_framebuffer_set_modelview_matrix (lnode->offscreen, &matrix);
cogl_framebuffer_set_viewport (lnode->offscreen,
lnode->viewport.x,
lnode->viewport.y,
lnode->viewport.width,
lnode->viewport.height);
cogl_framebuffer_set_projection_matrix (lnode->offscreen,
&lnode->projection);
/* clear out the target framebuffer */ /* clear out the target framebuffer */
cogl_framebuffer_clear4f (lnode->offscreen, cogl_framebuffer_clear4f (lnode->offscreen,
COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH,
@@ -1410,10 +1307,6 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
cogl_framebuffer_pop_matrix (lnode->offscreen); cogl_framebuffer_pop_matrix (lnode->offscreen);
clutter_paint_context_pop_framebuffer (paint_context); clutter_paint_context_pop_framebuffer (paint_context);
/* if no geometry was submitted for this node then we simply ignore it */
if (node->operations == NULL)
return;
fb = clutter_paint_context_get_framebuffer (paint_context); fb = clutter_paint_context_get_framebuffer (paint_context);
for (i = 0; i < node->operations->len; i++) for (i = 0; i < node->operations->len; i++)
@@ -1474,25 +1367,6 @@ clutter_layer_node_finalize (ClutterPaintNode *node)
CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node); CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node);
} }
static JsonNode *
clutter_layer_node_serialize (ClutterPaintNode *node)
{
ClutterLayerNode *layer_node = CLUTTER_LAYER_NODE (node);
g_autoptr (JsonBuilder) builder = NULL;
g_autofree char *framebuffer_ptr = NULL;
builder = json_builder_new ();
framebuffer_ptr = g_strdup_printf ("%p", layer_node->offscreen);
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "framebuffer");
json_builder_add_string_value (builder, framebuffer_ptr);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void static void
clutter_layer_node_class_init (ClutterLayerNodeClass *klass) clutter_layer_node_class_init (ClutterLayerNodeClass *klass)
{ {
@@ -1502,7 +1376,6 @@ clutter_layer_node_class_init (ClutterLayerNodeClass *klass)
node_class->pre_draw = clutter_layer_node_pre_draw; node_class->pre_draw = clutter_layer_node_pre_draw;
node_class->post_draw = clutter_layer_node_post_draw; node_class->post_draw = clutter_layer_node_post_draw;
node_class->finalize = clutter_layer_node_finalize; node_class->finalize = clutter_layer_node_finalize;
node_class->serialize = clutter_layer_node_serialize;
} }
static void static void
@@ -1539,13 +1412,11 @@ clutter_layer_node_new (const CoglMatrix *projection,
{ {
ClutterLayerNode *res; ClutterLayerNode *res;
CoglContext *context; CoglContext *context;
CoglTexture2D *tex_2d;
CoglTexture *texture; CoglTexture *texture;
CoglColor color; CoglColor color;
res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE); res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
res->update_modelview = TRUE;
res->projection = *projection; res->projection = *projection;
res->viewport = *viewport; res->viewport = *viewport;
res->fbo_width = width; res->fbo_width = width;
@@ -1555,10 +1426,9 @@ clutter_layer_node_new (const CoglMatrix *projection,
/* the texture backing the FBO */ /* the texture backing the FBO */
context = clutter_backend_get_cogl_context (clutter_get_default_backend ()); context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
tex_2d = cogl_texture_2d_new_with_size (context, texture = cogl_texture_2d_new_with_size (context,
MAX (res->fbo_width, 1), MAX (res->fbo_width, 1),
MAX (res->fbo_height, 1)); MAX (res->fbo_height, 1));
texture = COGL_TEXTURE (tex_2d);
cogl_texture_set_premultiplied (texture, TRUE); cogl_texture_set_premultiplied (texture, TRUE);
res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (texture)); res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (texture));
@@ -1586,245 +1456,3 @@ out:
return (ClutterPaintNode *) res; return (ClutterPaintNode *) res;
} }
/**
* clutter_layer_node_new_with_framebuffer:
* @framebuffer: a #CoglFramebuffer
* @pipeline: a #CoglPipeline
* @opacity: the opacity to be used when drawing the layer
*
* Creates a new #ClutterLayerNode with @framebuffer and
* @pipeline. @framebuffer will then be painted using the
* given @opacity.
*
* When using this constructor, the caller is responsible
* for setting up the framebuffer's modelview and projection
* matrices.
*
* Return value: (transfer full)(nullable): the newly created #ClutterLayerNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_layer_node_new_with_framebuffer (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
guint8 opacity)
{
ClutterLayerNode *res;
CoglColor color;
g_return_val_if_fail (cogl_is_framebuffer (framebuffer), NULL);
res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
res->update_modelview = FALSE;
res->offscreen = cogl_object_ref (framebuffer);
res->pipeline = cogl_pipeline_copy (pipeline);
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
cogl_pipeline_set_color (res->pipeline, &color);
return (ClutterPaintNode *) res;
}
/*
* ClutterBlitNode
*/
struct _ClutterBlitNode
{
ClutterPaintNode parent_instance;
CoglFramebuffer *source;
CoglFramebuffer *dest;
};
struct _ClutterBlitNodeClass
{
ClutterPaintNodeClass parent_class;
};
G_DEFINE_TYPE (ClutterBlitNode, clutter_blit_node, CLUTTER_TYPE_PAINT_NODE)
static gboolean
clutter_blit_node_pre_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
return TRUE;
}
static void
clutter_blit_node_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
g_autoptr (GError) error = NULL;
CoglFramebuffer *source;
guint i;
if (node->operations == NULL)
return;
source = blit_node->source;
if (!source)
source = clutter_paint_context_get_framebuffer (paint_context);
for (i = 0; i < node->operations->len; i++)
{
const ClutterPaintOperation *op;
float op_width, op_height;
op = &g_array_index (node->operations, ClutterPaintOperation, i);
switch (op->opcode)
{
case PAINT_OP_INVALID:
break;
case PAINT_OP_TEX_RECT:
op_width = op->op.texrect[6] - op->op.texrect[4];
op_height = op->op.texrect[7] - op->op.texrect[5];
cogl_blit_framebuffer (source,
blit_node->dest,
op->op.texrect[0],
op->op.texrect[1],
op->op.texrect[4],
op->op.texrect[5],
op_width,
op_height,
&error);
if (error)
{
g_warning ("Error blitting framebuffers: %s", error->message);
return;
}
break;
case PAINT_OP_MULTITEX_RECT:
case PAINT_OP_PRIMITIVE:
break;
}
}
}
static void
clutter_blit_node_finalize (ClutterPaintNode *node)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
cogl_clear_object (&blit_node->source);
cogl_clear_object (&blit_node->dest);
CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node);
}
static JsonNode *
clutter_blit_node_serialize (ClutterPaintNode *node)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
g_autoptr (JsonBuilder) builder = NULL;
g_autofree char *source_ptr = NULL;
g_autofree char *dest_ptr = NULL;
builder = json_builder_new ();
source_ptr = g_strdup_printf ("%p", blit_node->source);
dest_ptr = g_strdup_printf ("%p", blit_node->dest);
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "source");
json_builder_add_string_value (builder, source_ptr);
json_builder_end_object (builder);
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "dest");
json_builder_add_string_value (builder, dest_ptr);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_blit_node_class_init (ClutterTransformNodeClass *klass)
{
ClutterPaintNodeClass *node_class;
node_class = CLUTTER_PAINT_NODE_CLASS (klass);
node_class->pre_draw = clutter_blit_node_pre_draw;
node_class->draw = clutter_blit_node_draw;
node_class->finalize = clutter_blit_node_finalize;
node_class->serialize = clutter_blit_node_serialize;
}
static void
clutter_blit_node_init (ClutterBlitNode *self)
{
}
/**
* clutter_blit_node_new:
* @source: (nullable): the source #CoglFramebuffer
* @dest: the destination #CoglFramebuffer
*
* Creates a new #ClutterBlitNode that blits @source into @dest.
*
* If @source is %NULL, the most recent framebuffer stacked into a
* #ClutterPaintContext is used.
*
* You must only add rectangles using clutter_blit_node_add_blit_rectangle().
*
* Return value: (transfer full): the newly created #ClutterBlitNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_blit_node_new (CoglFramebuffer *source,
CoglFramebuffer *dest)
{
ClutterBlitNode *res;
g_return_val_if_fail (cogl_is_framebuffer (dest), NULL);
res = _clutter_paint_node_create (CLUTTER_TYPE_BLIT_NODE);
res->source = source ? cogl_object_ref (source) : NULL;
res->dest = cogl_object_ref (dest);
return (ClutterPaintNode *) res;
}
/**
* clutter_blit_node_add_blit_rectangle:
* @blit_node: a #ClutterBlitNode
* @src_x: Source x position
* @src_y: Source y position
* @dst_x: Destination x position
* @dst_y: Destination y position
* @width: Width of region to copy
* @height: Height of region to copy
*
* Adds a new blit rectangle to the stack of rectangles. All the
* constraints of cogl_blit_framebuffer() apply here.
*/
void
clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height)
{
g_return_if_fail (CLUTTER_IS_BLIT_NODE (blit_node));
clutter_paint_node_add_texture_rectangle (CLUTTER_PAINT_NODE (blit_node),
&(ClutterActorBox) {
src_x,
src_y,
src_x + width,
src_y + height,
},
dst_x,
dst_y,
dst_x + width,
dst_y + height);
}

View File

@@ -160,8 +160,7 @@ CLUTTER_EXPORT
GType clutter_actor_node_get_type (void) G_GNUC_CONST; GType clutter_actor_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterPaintNode * clutter_actor_node_new (ClutterActor *actor, ClutterPaintNode * clutter_actor_node_new (ClutterActor *actor);
int opacity);
#define CLUTTER_TYPE_ROOT_NODE (clutter_root_node_get_type ()) #define CLUTTER_TYPE_ROOT_NODE (clutter_root_node_get_type ())
#define CLUTTER_ROOT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ROOT_NODE, ClutterRootNode)) #define CLUTTER_ROOT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ROOT_NODE, ClutterRootNode))
@@ -209,11 +208,6 @@ ClutterPaintNode * clutter_layer_node_new (const CoglMatrix
float height, float height,
guint8 opacity); guint8 opacity);
CLUTTER_EXPORT
ClutterPaintNode * clutter_layer_node_new_with_framebuffer (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
guint8 opacity);
#define CLUTTER_TYPE_TRANSFORM_NODE (clutter_transform_node_get_type ()) #define CLUTTER_TYPE_TRANSFORM_NODE (clutter_transform_node_get_type ())
#define CLUTTER_TRANSFORM_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TRANSFORM_NODE, ClutterTransformNode)) #define CLUTTER_TRANSFORM_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TRANSFORM_NODE, ClutterTransformNode))
@@ -236,38 +230,6 @@ GType clutter_transform_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterPaintNode * clutter_transform_node_new (const CoglMatrix *projection); ClutterPaintNode * clutter_transform_node_new (const CoglMatrix *projection);
#define CLUTTER_TYPE_BLIT_NODE (clutter_blit_node_get_type ())
#define CLUTTER_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BLIT_NODE, ClutterBlitNode))
#define CLUTTER_IS_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BLIT_NODE))
/*
* ClutterBlitNode:
*
* The #ClutterLayerNode structure is an opaque
* type whose members cannot be directly accessed.
*
* Since: 1.10
*/
typedef struct _ClutterBlitNode ClutterBlitNode;
typedef struct _ClutterPaintNodeClass ClutterBlitNodeClass;
CLUTTER_EXPORT
GType clutter_blit_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_blit_node_new (CoglFramebuffer *source,
CoglFramebuffer *dest);
CLUTTER_EXPORT
void clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_PAINT_NODES_H__ */ #endif /* __CLUTTER_PAINT_NODES_H__ */

View File

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

View File

@@ -37,6 +37,7 @@
#include "clutter-feature.h" #include "clutter-feature.h"
#include "clutter-id-pool.h" #include "clutter-id-pool.h"
#include "clutter-layout-manager.h" #include "clutter-layout-manager.h"
#include "clutter-master-clock.h"
#include "clutter-settings.h" #include "clutter-settings.h"
#include "clutter-stage-manager.h" #include "clutter-stage-manager.h"
#include "clutter-stage.h" #include "clutter-stage.h"
@@ -121,6 +122,9 @@ struct _ClutterMainContext
/* the object holding all the stage instances */ /* the object holding all the stage instances */
ClutterStageManager *stage_manager; ClutterStageManager *stage_manager;
/* the clock driving all the frame operations */
ClutterMasterClock *master_clock;
/* the main event queue */ /* the main event queue */
GQueue *events_queue; GQueue *events_queue;
@@ -173,6 +177,11 @@ typedef struct
gboolean _clutter_threads_dispatch (gpointer data); gboolean _clutter_threads_dispatch (gpointer data);
void _clutter_threads_dispatch_free (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); ClutterMainContext * _clutter_context_get_default (void);
void _clutter_context_lock (void); void _clutter_context_lock (void);
void _clutter_context_unlock (void); void _clutter_context_unlock (void);
@@ -307,30 +316,6 @@ gboolean _clutter_run_progress_function (GType gtype,
void clutter_timeline_cancel_delay (ClutterTimeline *timeline); void clutter_timeline_cancel_delay (ClutterTimeline *timeline);
static inline uint64_t
us (uint64_t us)
{
return us;
}
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 G_END_DECLS
#endif /* __CLUTTER_PRIVATE_H__ */ #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); 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: * clutter_property_transition_new:
* @property_name: (allow-none): a property of @animatable, or %NULL * @property_name: (allow-none): a property of @animatable, or %NULL

View File

@@ -78,13 +78,8 @@ struct _ClutterPropertyTransitionClass
CLUTTER_EXPORT CLUTTER_EXPORT
GType clutter_property_transition_get_type (void) G_GNUC_CONST; 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 CLUTTER_EXPORT
ClutterTransition * clutter_property_transition_new (const char *property_name); ClutterTransition * clutter_property_transition_new (const char *property_name);
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_property_transition_set_property_name (ClutterPropertyTransition *transition, void clutter_property_transition_set_property_name (ClutterPropertyTransition *transition,
const char *property_name); const char *property_name);

View File

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

View File

@@ -50,14 +50,14 @@
* <informalexample><programlisting><![CDATA[ * <informalexample><programlisting><![CDATA[
* { * {
* "id" : "red-button", * "id" : "red-button",
* "type" : "ClutterActor", * "type" : "ClutterRectangle",
* "width" : 100, * "width" : 100,
* "height" : 100, * "height" : 100,
* "background-color" : "&num;ff0000ff" * "color" : "&num;ff0000ff"
* } * }
* ]]></programlisting></informalexample> * ]]></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: * with a ClutterScript id of "red-button"; it can be retrieved by calling:
* *
* |[ * |[

View File

@@ -354,17 +354,6 @@ clutter_seat_get_keyboard (ClutterSeat *seat)
return CLUTTER_SEAT_GET_CLASS (seat)->get_keyboard (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: * clutter_seat_list_devices:
* @seat: a #ClutterSeat * @seat: a #ClutterSeat
@@ -381,7 +370,7 @@ clutter_seat_list_devices (ClutterSeat *seat)
{ {
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), NULL); 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 void
@@ -645,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 ClutterVirtualDeviceType
clutter_seat_get_supported_virtual_device_types (ClutterSeat *seat) clutter_seat_get_supported_virtual_device_types (ClutterSeat *seat)
{ {
@@ -693,6 +682,7 @@ clutter_seat_warp_pointer (ClutterSeat *seat,
* requirements are fulfilled: * requirements are fulfilled:
* *
* - A touchscreen is available * - A touchscreen is available
* - No external keyboard is attached to the device
* - A tablet mode switch, if present, is enabled * - A tablet mode switch, if present, is enabled
* *
* Returns: %TRUE if the device is a tablet that doesn't have an external * Returns: %TRUE if the device is a tablet that doesn't have an external

View File

@@ -96,7 +96,7 @@ struct _ClutterSeatClass
ClutterInputDevice * (* get_pointer) (ClutterSeat *seat); ClutterInputDevice * (* get_pointer) (ClutterSeat *seat);
ClutterInputDevice * (* get_keyboard) (ClutterSeat *seat); ClutterInputDevice * (* get_keyboard) (ClutterSeat *seat);
const GList * (* peek_devices) (ClutterSeat *seat); GList * (* list_devices) (ClutterSeat *seat);
void (* bell_notify) (ClutterSeat *seat); void (* bell_notify) (ClutterSeat *seat);
@@ -133,7 +133,6 @@ CLUTTER_EXPORT
ClutterInputDevice * clutter_seat_get_keyboard (ClutterSeat *seat); ClutterInputDevice * clutter_seat_get_keyboard (ClutterSeat *seat);
CLUTTER_EXPORT CLUTTER_EXPORT
GList * clutter_seat_list_devices (ClutterSeat *seat); GList * clutter_seat_list_devices (ClutterSeat *seat);
const GList * clutter_seat_peek_devices (ClutterSeat *seat);
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_seat_bell_notify (ClutterSeat *seat); void clutter_seat_bell_notify (ClutterSeat *seat);

View File

@@ -384,13 +384,12 @@ clutter_shader_effect_try_static_source (ClutterShaderEffect *self)
static void static void
clutter_shader_effect_paint_target (ClutterOffscreenEffect *effect, clutter_shader_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context) ClutterPaintContext *paint_context)
{ {
ClutterShaderEffect *self = CLUTTER_SHADER_EFFECT (effect); ClutterShaderEffect *self = CLUTTER_SHADER_EFFECT (effect);
ClutterShaderEffectPrivate *priv = self->priv; ClutterShaderEffectPrivate *priv = self->priv;
ClutterOffscreenEffectClass *parent; ClutterOffscreenEffectClass *parent;
CoglPipeline *pipeline; CoglHandle material;
/* If the source hasn't been set then we'll try to get it from the /* If the source hasn't been set then we'll try to get it from the
static source instead */ static source instead */
@@ -408,14 +407,14 @@ clutter_shader_effect_paint_target (ClutterOffscreenEffect *effect,
clutter_shader_effect_update_uniforms (CLUTTER_SHADER_EFFECT (effect)); clutter_shader_effect_update_uniforms (CLUTTER_SHADER_EFFECT (effect));
/* associate the program to the offscreen target pipeline */ /* associate the program to the offscreen target material */
pipeline = clutter_offscreen_effect_get_pipeline (effect); material = clutter_offscreen_effect_get_target (effect);
cogl_pipeline_set_user_program (pipeline, priv->program); cogl_pipeline_set_user_program (material, priv->program);
out: out:
/* paint the offscreen buffer */ /* paint the offscreen buffer */
parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (clutter_shader_effect_parent_class); parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (clutter_shader_effect_parent_class);
parent->paint_target (effect, node, paint_context); parent->paint_target (effect, paint_context);
} }

View File

@@ -40,14 +40,7 @@ void clutter_stage_paint_view (ClutterStage
ClutterStageView *view, ClutterStageView *view,
const cairo_region_t *redraw_clip); const cairo_region_t *redraw_clip);
void clutter_stage_emit_before_update (ClutterStage *stage, void _clutter_stage_emit_after_paint (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);
CLUTTER_EXPORT CLUTTER_EXPORT
void _clutter_stage_set_window (ClutterStage *stage, 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, void _clutter_stage_get_projection_matrix (ClutterStage *stage,
CoglMatrix *projection); CoglMatrix *projection);
void _clutter_stage_dirty_projection (ClutterStage *stage); 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, void _clutter_stage_get_viewport (ClutterStage *stage,
float *x, float *x,
float *y, float *y,
@@ -65,12 +63,9 @@ void _clutter_stage_get_viewport (ClutterStage
void _clutter_stage_dirty_viewport (ClutterStage *stage); void _clutter_stage_dirty_viewport (ClutterStage *stage);
void _clutter_stage_maybe_setup_viewport (ClutterStage *stage, void _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
ClutterStageView *view); ClutterStageView *view);
void clutter_stage_maybe_relayout (ClutterActor *stage); void _clutter_stage_maybe_relayout (ClutterActor *stage);
void clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage); gboolean _clutter_stage_needs_update (ClutterStage *stage);
GSList * clutter_stage_find_updated_devices (ClutterStage *stage); gboolean _clutter_stage_do_update (ClutterStage *stage);
void clutter_stage_update_devices (ClutterStage *stage,
GSList *devices);
void clutter_stage_update_actor_stage_views (ClutterStage *stage);
CLUTTER_EXPORT CLUTTER_EXPORT
void _clutter_stage_queue_event (ClutterStage *stage, 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); gboolean _clutter_stage_has_queued_events (ClutterStage *stage);
void _clutter_stage_process_queued_events (ClutterStage *stage); void _clutter_stage_process_queued_events (ClutterStage *stage);
void _clutter_stage_update_input_devices (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); gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage);
void clutter_stage_log_pick (ClutterStage *stage, void clutter_stage_log_pick (ClutterStage *stage,
@@ -133,19 +130,17 @@ gboolean _clutter_stage_update_state (ClutterStage *stag
void _clutter_stage_set_scale_factor (ClutterStage *stage, void _clutter_stage_set_scale_factor (ClutterStage *stage,
int factor); 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, void _clutter_stage_presented (ClutterStage *stage,
ClutterStageView *view, CoglFrameEvent frame_event,
ClutterFrameInfo *frame_info); ClutterFrameInfo *frame_info);
void clutter_stage_queue_actor_relayout (ClutterStage *stage, void clutter_stage_queue_actor_relayout (ClutterStage *stage,
ClutterActor *actor); 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 G_END_DECLS
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */ #endif /* __CLUTTER_STAGE_PRIVATE_H__ */

View File

@@ -19,7 +19,6 @@
#define __CLUTTER_STAGE_VIEW_PRIVATE_H__ #define __CLUTTER_STAGE_VIEW_PRIVATE_H__
#include "clutter/clutter-stage-view.h" #include "clutter/clutter-stage-view.h"
#include "clutter/clutter-types.h"
void clutter_stage_view_after_paint (ClutterStageView *view, void clutter_stage_view_after_paint (ClutterStageView *view,
cairo_region_t *redraw_clip); cairo_region_t *redraw_clip);
@@ -63,12 +62,4 @@ void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView
int dst_height, int dst_height,
cairo_rectangle_int_t *dst_rect); 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__ */ #endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */

View File

@@ -24,10 +24,8 @@
#include <math.h> #include <math.h>
#include "clutter/clutter-damage-history.h" #include "clutter/clutter-damage-history.h"
#include "clutter/clutter-frame-clock.h"
#include "clutter/clutter-private.h" #include "clutter/clutter-private.h"
#include "clutter/clutter-mutter.h" #include "clutter/clutter-mutter.h"
#include "clutter/clutter-stage-private.h"
#include "cogl/cogl.h" #include "cogl/cogl.h"
enum enum
@@ -35,13 +33,11 @@ enum
PROP_0, PROP_0,
PROP_NAME, PROP_NAME,
PROP_STAGE,
PROP_LAYOUT, PROP_LAYOUT,
PROP_FRAMEBUFFER, PROP_FRAMEBUFFER,
PROP_OFFSCREEN, PROP_OFFSCREEN,
PROP_USE_SHADOWFB, PROP_USE_SHADOWFB,
PROP_SCALE, PROP_SCALE,
PROP_REFRESH_RATE,
PROP_LAST PROP_LAST
}; };
@@ -52,8 +48,6 @@ typedef struct _ClutterStageViewPrivate
{ {
char *name; char *name;
ClutterStage *stage;
cairo_rectangle_int_t layout; cairo_rectangle_int_t layout;
float scale; float scale;
CoglFramebuffer *framebuffer; CoglFramebuffer *framebuffer;
@@ -77,9 +71,6 @@ typedef struct _ClutterStageViewPrivate
gboolean has_redraw_clip; gboolean has_redraw_clip;
cairo_region_t *redraw_clip; cairo_region_t *redraw_clip;
float refresh_rate;
ClutterFrameClock *frame_clock;
guint dirty_viewport : 1; guint dirty_viewport : 1;
guint dirty_projection : 1; guint dirty_projection : 1;
} ClutterStageViewPrivate; } ClutterStageViewPrivate;
@@ -111,9 +102,9 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
clutter_stage_view_get_instance_private (view); clutter_stage_view_get_instance_private (view);
if (priv->offscreen) if (priv->offscreen)
return COGL_FRAMEBUFFER (priv->offscreen); return priv->offscreen;
else if (priv->shadow.framebuffer) else if (priv->shadow.framebuffer)
return COGL_FRAMEBUFFER (priv->shadow.framebuffer); return priv->shadow.framebuffer;
else else
return priv->framebuffer; return priv->framebuffer;
} }
@@ -136,9 +127,8 @@ clutter_stage_view_get_onscreen (ClutterStageView *view)
} }
static CoglPipeline * 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; CoglPipeline *pipeline;
pipeline = cogl_pipeline_new (cogl_framebuffer_get_context (framebuffer)); pipeline = cogl_pipeline_new (cogl_framebuffer_get_context (framebuffer));
@@ -147,7 +137,7 @@ clutter_stage_view_create_offscreen_pipeline (CoglOffscreen *offscreen)
COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST); COGL_PIPELINE_FILTER_NEAREST);
cogl_pipeline_set_layer_texture (pipeline, 0, 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_set_layer_wrap_mode (pipeline, 0,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
@@ -168,7 +158,7 @@ clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
return; return;
priv->offscreen_pipeline = 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) if (view_class->setup_offscreen_blit_pipeline)
view_class->setup_offscreen_blit_pipeline (view, priv->offscreen_pipeline); view_class->setup_offscreen_blit_pipeline (view, priv->offscreen_pipeline);
@@ -202,7 +192,7 @@ clutter_stage_view_transform_rect_to_onscreen (ClutterStageView *view
static void static void
paint_transformed_framebuffer (ClutterStageView *view, paint_transformed_framebuffer (ClutterStageView *view,
CoglPipeline *pipeline, CoglPipeline *pipeline,
CoglOffscreen *src_framebuffer, CoglFramebuffer *src_framebuffer,
CoglFramebuffer *dst_framebuffer, CoglFramebuffer *dst_framebuffer,
const cairo_region_t *redraw_clip) const cairo_region_t *redraw_clip)
{ {
@@ -442,13 +432,10 @@ clutter_stage_view_after_paint (ClutterStageView *view,
if (priv->shadow.framebuffer) if (priv->shadow.framebuffer)
{ {
CoglFramebuffer *shadowfb =
COGL_FRAMEBUFFER (priv->shadow.framebuffer);
paint_transformed_framebuffer (view, paint_transformed_framebuffer (view,
priv->offscreen_pipeline, priv->offscreen_pipeline,
priv->offscreen, priv->offscreen,
shadowfb, priv->shadow.framebuffer,
redraw_clip); redraw_clip);
} }
else else
@@ -521,7 +508,7 @@ find_damaged_tiles (ClutterStageView *view,
stride = cogl_dma_buf_handle_get_stride (current_dma_buf_handle); stride = cogl_dma_buf_handle_get_stride (current_dma_buf_handle);
bpp = cogl_dma_buf_handle_get_bpp (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)) if (!cogl_dma_buf_handle_sync_read_start (prev_dma_buf_handle, error))
return NULL; return NULL;
@@ -614,7 +601,7 @@ swap_dma_buf_framebuffer (ClutterStageView *view)
clutter_stage_view_get_instance_private (view); clutter_stage_view_get_instance_private (view);
int next_idx; int next_idx;
CoglDmaBufHandle *next_dma_buf_handle; CoglDmaBufHandle *next_dma_buf_handle;
CoglFramebuffer *next_framebuffer; CoglOffscreen *next_framebuffer;
next_idx = ((priv->shadow.dma_buf.current_idx + 1) % next_idx = ((priv->shadow.dma_buf.current_idx + 1) %
G_N_ELEMENTS (priv->shadow.dma_buf.handles)); G_N_ELEMENTS (priv->shadow.dma_buf.handles));
@@ -710,13 +697,12 @@ copy_shadowfb_to_onscreen (ClutterStageView *view,
for (i = 0; i < cairo_region_num_rectangles (damage_region); i++) for (i = 0; i < cairo_region_num_rectangles (damage_region); i++)
{ {
CoglFramebuffer *shadowfb = COGL_FRAMEBUFFER (priv->shadow.framebuffer);
g_autoptr (GError) error = NULL; g_autoptr (GError) error = NULL;
cairo_rectangle_int_t rect; cairo_rectangle_int_t rect;
cairo_region_get_rectangle (damage_region, i, &rect); cairo_region_get_rectangle (damage_region, i, &rect);
if (!cogl_blit_framebuffer (shadowfb, if (!cogl_blit_framebuffer (priv->shadow.framebuffer,
priv->framebuffer, priv->framebuffer,
rect.x, rect.y, rect.x, rect.y,
rect.x, rect.y, rect.x, rect.y,
@@ -768,7 +754,7 @@ clutter_stage_view_foreach_front_buffer (ClutterStageView *view,
if (priv->offscreen) if (priv->offscreen)
{ {
callback (COGL_FRAMEBUFFER (priv->offscreen), user_data); callback (priv->offscreen, user_data);
} }
else if (priv->shadow.framebuffer) else if (priv->shadow.framebuffer)
{ {
@@ -787,7 +773,7 @@ clutter_stage_view_foreach_front_buffer (ClutterStageView *view,
} }
else else
{ {
callback (COGL_FRAMEBUFFER (priv->shadow.framebuffer), user_data); callback (priv->shadow.framebuffer, user_data);
} }
} }
else else
@@ -1002,154 +988,6 @@ clutter_stage_view_take_scanout (ClutterStageView *view)
return g_steal_pointer (&priv->next_scanout); 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 static void
clutter_stage_view_get_property (GObject *object, clutter_stage_view_get_property (GObject *object,
guint prop_id, guint prop_id,
@@ -1165,9 +1003,6 @@ clutter_stage_view_get_property (GObject *object,
case PROP_NAME: case PROP_NAME:
g_value_set_string (value, priv->name); g_value_set_string (value, priv->name);
break; break;
case PROP_STAGE:
g_value_set_boxed (value, &priv->stage);
break;
case PROP_LAYOUT: case PROP_LAYOUT:
g_value_set_boxed (value, &priv->layout); g_value_set_boxed (value, &priv->layout);
break; break;
@@ -1183,9 +1018,6 @@ clutter_stage_view_get_property (GObject *object,
case PROP_SCALE: case PROP_SCALE:
g_value_set_float (value, priv->scale); g_value_set_float (value, priv->scale);
break; break;
case PROP_REFRESH_RATE:
g_value_set_float (value, priv->refresh_rate);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
@@ -1207,15 +1039,26 @@ clutter_stage_view_set_property (GObject *object,
case PROP_NAME: case PROP_NAME:
priv->name = g_value_dup_string (value); priv->name = g_value_dup_string (value);
break; break;
case PROP_STAGE:
priv->stage = g_value_get_object (value);
break;
case PROP_LAYOUT: case PROP_LAYOUT:
layout = g_value_get_boxed (value); layout = g_value_get_boxed (value);
priv->layout = *layout; priv->layout = *layout;
break; break;
case PROP_FRAMEBUFFER: 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; break;
case PROP_OFFSCREEN: case PROP_OFFSCREEN:
priv->offscreen = g_value_dup_boxed (value); priv->offscreen = g_value_dup_boxed (value);
@@ -1226,9 +1069,6 @@ clutter_stage_view_set_property (GObject *object,
case PROP_SCALE: case PROP_SCALE:
priv->scale = g_value_get_float (value); priv->scale = g_value_get_float (value);
break; break;
case PROP_REFRESH_RATE:
priv->refresh_rate = g_value_get_float (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
@@ -1244,10 +1084,6 @@ clutter_stage_view_constructed (GObject *object)
if (priv->use_shadowfb) if (priv->use_shadowfb)
init_shadowfb (view); 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); G_OBJECT_CLASS (clutter_stage_view_parent_class)->constructed (object);
} }
@@ -1274,7 +1110,6 @@ clutter_stage_view_dispose (GObject *object)
g_clear_pointer (&priv->offscreen, cogl_object_unref); g_clear_pointer (&priv->offscreen, cogl_object_unref);
g_clear_pointer (&priv->offscreen_pipeline, 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->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); G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
} }
@@ -1288,7 +1123,6 @@ clutter_stage_view_init (ClutterStageView *view)
priv->dirty_viewport = TRUE; priv->dirty_viewport = TRUE;
priv->dirty_projection = TRUE; priv->dirty_projection = TRUE;
priv->scale = 1.0; priv->scale = 1.0;
priv->refresh_rate = 60.0;
} }
static void static void
@@ -1312,16 +1146,6 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS); 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] = obj_props[PROP_LAYOUT] =
g_param_spec_boxed ("layout", g_param_spec_boxed ("layout",
"View layout", "View layout",
@@ -1367,14 +1191,5 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS); 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); g_object_class_install_properties (object_class, PROP_LAST, obj_props);
} }

View File

@@ -27,7 +27,6 @@
#include <cogl/cogl.h> #include <cogl/cogl.h>
#include "clutter-macros.h" #include "clutter-macros.h"
#include "clutter-frame-clock.h"
#define CLUTTER_TYPE_STAGE_VIEW (clutter_stage_view_get_type ()) #define CLUTTER_TYPE_STAGE_VIEW (clutter_stage_view_get_type ())
CLUTTER_EXPORT CLUTTER_EXPORT
@@ -70,7 +69,4 @@ CLUTTER_EXPORT
void clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view, void clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view,
CoglMatrix *matrix); CoglMatrix *matrix);
CLUTTER_EXPORT
ClutterFrameClock * clutter_stage_view_get_frame_clock (ClutterStageView *view);
#endif /* __CLUTTER_STAGE_VIEW_H__ */ #endif /* __CLUTTER_STAGE_VIEW_H__ */

View File

@@ -103,12 +103,81 @@ _clutter_stage_window_get_geometry (ClutterStageWindow *window,
} }
void void
_clutter_stage_window_redraw_view (ClutterStageWindow *window, _clutter_stage_window_schedule_update (ClutterStageWindow *window,
ClutterStageView *view) int sync_delay)
{ {
ClutterStageWindowInterface *iface;
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window)); 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 gboolean

View File

@@ -44,8 +44,12 @@ struct _ClutterStageWindowInterface
void (* get_geometry) (ClutterStageWindow *stage_window, void (* get_geometry) (ClutterStageWindow *stage_window,
cairo_rectangle_int_t *geometry); cairo_rectangle_int_t *geometry);
void (* redraw_view) (ClutterStageWindow *stage_window, void (* schedule_update) (ClutterStageWindow *stage_window,
ClutterStageView *view); 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); gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window);
@@ -74,12 +78,15 @@ void _clutter_stage_window_resize (ClutterStageWin
CLUTTER_EXPORT CLUTTER_EXPORT
void _clutter_stage_window_get_geometry (ClutterStageWindow *window, void _clutter_stage_window_get_geometry (ClutterStageWindow *window,
cairo_rectangle_int_t *geometry); 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, void _clutter_stage_window_set_accept_focus (ClutterStageWindow *window,
gboolean accept_focus); gboolean accept_focus);
void _clutter_stage_window_redraw_view (ClutterStageWindow *window, void _clutter_stage_window_redraw (ClutterStageWindow *window);
ClutterStageView *view);
gboolean _clutter_stage_window_can_clip_redraws (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." #error "Only <clutter/clutter.h> can be included directly."
#endif #endif
#include <clutter/clutter-actor.h>
#include <clutter/clutter-types.h> #include <clutter/clutter-types.h>
#include <clutter/clutter-group.h>
#include <clutter/clutter-stage-view.h> #include <clutter/clutter-stage-view.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@@ -56,7 +56,7 @@ typedef struct _ClutterStagePrivate ClutterStagePrivate;
struct _ClutterStage struct _ClutterStage
{ {
/*< private >*/ /*< private >*/
ClutterActor parent_instance; ClutterGroup parent_instance;
ClutterStagePrivate *priv; ClutterStagePrivate *priv;
}; };
@@ -74,7 +74,7 @@ struct _ClutterStage
struct _ClutterStageClass struct _ClutterStageClass
{ {
/*< private >*/ /*< private >*/
ClutterActorClass parent_class; ClutterGroupClass parent_class;
/*< public >*/ /*< public >*/
/* signals */ /* signals */
@@ -195,10 +195,11 @@ guchar * clutter_stage_read_pixels (ClutterStage
CLUTTER_EXPORT CLUTTER_EXPORT
void clutter_stage_ensure_viewport (ClutterStage *stage); void clutter_stage_ensure_viewport (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_ensure_redraw (ClutterStage *stage);
CLUTTER_EXPORT CLUTTER_EXPORT
gboolean clutter_stage_is_redraw_queued_on_view (ClutterStage *stage, gboolean clutter_stage_is_redraw_queued (ClutterStage *stage);
ClutterStageView *view);
#ifdef CLUTTER_ENABLE_EXPERIMENTAL_API #ifdef CLUTTER_ENABLE_EXPERIMENTAL_API
CLUTTER_EXPORT CLUTTER_EXPORT

View File

@@ -187,6 +187,9 @@ struct _ClutterTextPrivate
ClutterInputContentHintFlags input_hints; ClutterInputContentHintFlags input_hints;
ClutterInputContentPurpose input_purpose; ClutterInputContentPurpose input_purpose;
/* Signal handler for when the :resource-scale changes */
gulong resource_scale_changed_id;
/* bitfields */ /* bitfields */
guint alignment : 2; guint alignment : 2;
guint wrap : 1; guint wrap : 1;
@@ -595,7 +598,9 @@ ensure_effective_pango_scale_attribute (ClutterText *self)
float resource_scale; float resource_scale;
ClutterTextPrivate *priv = self->priv; 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) 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 */ /* 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: * clutter_text_create_layout:
* @text: a #ClutterText * @text: a #ClutterText
@@ -1120,7 +1137,8 @@ maybe_create_text_layout_with_resource_scale (ClutterText *text,
{ {
float resource_scale; 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, return create_text_layout_with_scale (text,
allocation_width, allocation_width,
@@ -1152,7 +1170,8 @@ clutter_text_coords_to_position (ClutterText *self,
g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0); 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 /* Take any offset due to scrolling into account, and normalize
* the coordinates to PangoScale units * 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); 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, ret = clutter_text_position_to_coords_internal (self, position,
x, y, line_height); x, y, line_height);
@@ -1756,6 +1776,7 @@ clutter_text_dispose (GObject *gobject)
clutter_text_dirty_cache (self); clutter_text_dirty_cache (self);
g_clear_signal_handler (&priv->direction_changed_id, 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, g_clear_signal_handler (&priv->settings_changed_id,
clutter_get_default_backend ()); clutter_get_default_backend ());
@@ -2620,7 +2641,8 @@ clutter_text_paint (ClutterActor *self,
!clutter_text_should_draw_cursor (text)) !clutter_text_should_draw_cursor (text))
return; 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_scale (&alloc, resource_scale);
clutter_actor_box_get_size (&alloc, &alloc_width, &alloc_height); 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)) if (!clutter_actor_has_allocation (self))
return FALSE; 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); _clutter_paint_volume_init_static (&priv->paint_volume, self);
@@ -2909,7 +2932,8 @@ clutter_text_get_preferred_width (ClutterActor *self,
gfloat layout_width; gfloat layout_width;
gfloat resource_scale; 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); layout = clutter_text_create_layout (text, -1, -1);
pango_layout_get_extents (layout, NULL, &logical_rect); pango_layout_get_extents (layout, NULL, &logical_rect);
@@ -2965,7 +2989,8 @@ clutter_text_get_preferred_height (ClutterActor *self,
gfloat layout_height; gfloat layout_height;
gfloat resource_scale; 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) if (priv->single_line_mode)
for_width = -1; for_width = -1;
@@ -3041,33 +3066,6 @@ clutter_text_has_overlaps (ClutterActor *self)
return clutter_text_should_draw_cursor ((ClutterText *) 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 static void
clutter_text_im_focus (ClutterText *text) 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_in = clutter_text_key_focus_in;
actor_class->key_focus_out = clutter_text_key_focus_out; actor_class->key_focus_out = clutter_text_key_focus_out;
actor_class->has_overlaps = clutter_text_has_overlaps; 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: * ClutterText:buffer:
@@ -4625,6 +4621,11 @@ clutter_text_init (ClutterText *self)
NULL); NULL);
priv->input_focus = clutter_text_input_focus_new (self); 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);
} }
/** /**

View File

@@ -1,33 +0,0 @@
/*
* 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_TIMELINE_PRIVATE_H
#define CLUTTER_TIMELINE_PRIVATE_H
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);
#endif /* CLUTTER_TIMELINE_PRIVATE_H */

View File

@@ -95,31 +95,22 @@
#include "clutter-build-config.h" #include "clutter-build-config.h"
#include "clutter-timeline.h" #include "clutter-timeline.h"
#include "deprecated/clutter-timeline.h"
#include "clutter-debug.h" #include "clutter-debug.h"
#include "clutter-easing.h" #include "clutter-easing.h"
#include "clutter-enum-types.h" #include "clutter-enum-types.h"
#include "clutter-frame-clock.h"
#include "clutter-main.h" #include "clutter-main.h"
#include "clutter-marshal.h" #include "clutter-marshal.h"
#include "clutter-master-clock.h"
#include "clutter-private.h" #include "clutter-private.h"
#include "clutter-scriptable.h" #include "clutter-scriptable.h"
#include "clutter-timeline-private.h"
#include "deprecated/clutter-timeline.h"
struct _ClutterTimelinePrivate struct _ClutterTimelinePrivate
{ {
ClutterTimelineDirection direction; ClutterTimelineDirection direction;
ClutterFrameClock *custom_frame_clock;
ClutterFrameClock *frame_clock;
ClutterActor *actor;
gulong actor_destroy_handler_id;
gulong actor_stage_views_handler_id;
gulong stage_stage_views_handler_id;
ClutterActor *stage;
guint delay_id; guint delay_id;
/* The total length in milliseconds of this timeline */ /* The total length in milliseconds of this timeline */
@@ -181,14 +172,13 @@ enum
{ {
PROP_0, PROP_0,
PROP_ACTOR, PROP_LOOP,
PROP_DELAY, PROP_DELAY,
PROP_DURATION, PROP_DURATION,
PROP_DIRECTION, PROP_DIRECTION,
PROP_AUTO_REVERSE, PROP_AUTO_REVERSE,
PROP_REPEAT_COUNT, PROP_REPEAT_COUNT,
PROP_PROGRESS_MODE, PROP_PROGRESS_MODE,
PROP_FRAME_CLOCK,
PROP_LAST PROP_LAST
}; };
@@ -209,8 +199,6 @@ enum
static guint timeline_signals[LAST_SIGNAL] = { 0, }; static guint timeline_signals[LAST_SIGNAL] = { 0, };
static void update_frame_clock (ClutterTimeline *timeline);
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterTimeline, clutter_timeline, G_TYPE_OBJECT, G_DEFINE_TYPE_WITH_CODE (ClutterTimeline, clutter_timeline, G_TYPE_OBJECT,
@@ -302,175 +290,21 @@ clutter_timeline_add_marker_internal (ClutterTimeline *timeline,
g_hash_table_insert (priv->markers_by_name, marker->name, marker); g_hash_table_insert (priv->markers_by_name, marker->name, marker);
} }
static void static inline void
on_actor_destroyed (ClutterActor *actor, clutter_timeline_set_loop_internal (ClutterTimeline *timeline,
ClutterTimeline *timeline) gboolean loop)
{ {
ClutterTimelinePrivate *priv = timeline->priv; gint old_repeat_count;
priv->actor = NULL; old_repeat_count = timeline->priv->repeat_count;
}
/** if (loop)
* clutter_timeline_get_actor: clutter_timeline_set_repeat_count (timeline, -1);
* @timeline: a #ClutterTimeline else
* clutter_timeline_set_repeat_count (timeline, 0);
* 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;
return priv->actor; if (old_repeat_count != timeline->priv->repeat_count)
} g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_LOOP]);
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
update_frame_clock (ClutterTimeline *timeline)
{
ClutterTimelinePrivate *priv = timeline->priv;
ClutterFrameClock *frame_clock = NULL;
ClutterActor *stage;
if (!priv->actor)
goto out;
frame_clock = clutter_actor_pick_frame_clock (priv->actor);
if (frame_clock)
{
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);
} }
/* Scriptable */ /* Scriptable */
@@ -614,8 +448,8 @@ clutter_timeline_set_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_ACTOR: case PROP_LOOP:
clutter_timeline_set_actor (timeline, g_value_get_object (value)); clutter_timeline_set_loop_internal (timeline, g_value_get_boolean (value));
break; break;
case PROP_DELAY: case PROP_DELAY:
@@ -642,10 +476,6 @@ clutter_timeline_set_property (GObject *object,
clutter_timeline_set_progress_mode (timeline, g_value_get_enum (value)); clutter_timeline_set_progress_mode (timeline, g_value_get_enum (value));
break; break;
case PROP_FRAME_CLOCK:
clutter_timeline_set_frame_clock (timeline, g_value_get_object (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@@ -663,8 +493,8 @@ clutter_timeline_get_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_ACTOR: case PROP_LOOP:
g_value_set_object (value, priv->actor); g_value_set_boolean (value, priv->repeat_count != 0);
break; break;
case PROP_DELAY: case PROP_DELAY:
@@ -691,10 +521,6 @@ clutter_timeline_get_property (GObject *object,
g_value_set_enum (value, priv->progress_mode); g_value_set_enum (value, priv->progress_mode);
break; break;
case PROP_FRAME_CLOCK:
g_value_set_object (value, priv->frame_clock);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@@ -706,14 +532,16 @@ clutter_timeline_finalize (GObject *object)
{ {
ClutterTimeline *self = CLUTTER_TIMELINE (object); ClutterTimeline *self = CLUTTER_TIMELINE (object);
ClutterTimelinePrivate *priv = self->priv; ClutterTimelinePrivate *priv = self->priv;
ClutterMasterClock *master_clock;
if (priv->markers_by_name) if (priv->markers_by_name)
g_hash_table_destroy (priv->markers_by_name); g_hash_table_destroy (priv->markers_by_name);
if (priv->is_playing) if (priv->is_playing)
maybe_remove_timeline (self); {
master_clock = _clutter_master_clock_get_default ();
g_clear_object (&priv->frame_clock); _clutter_master_clock_remove_timeline (master_clock, self);
}
G_OBJECT_CLASS (clutter_timeline_parent_class)->finalize (object); G_OBJECT_CLASS (clutter_timeline_parent_class)->finalize (object);
} }
@@ -728,14 +556,6 @@ clutter_timeline_dispose (GObject *object)
clutter_timeline_cancel_delay (self); 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->progress_notify != NULL) if (priv->progress_notify != NULL)
{ {
priv->progress_notify (priv->progress_data); priv->progress_notify (priv->progress_data);
@@ -753,17 +573,24 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
/** /**
* ClutterTimeline::actor: * ClutterTimeline:loop:
* *
* The actor the timeline is associated with. This will determine what frame * Whether the timeline should automatically rewind and restart.
* clock will drive it. *
* 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] = obj_props[PROP_LOOP] =
g_param_spec_object ("actor", g_param_spec_boolean ("loop",
P_("Actor"), P_("Loop"),
P_("Associated ClutterActor"), P_("Should the timeline automatically restart"),
CLUTTER_TYPE_ACTOR, FALSE,
G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE); CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED);
/** /**
* ClutterTimeline:delay: * ClutterTimeline:delay:
* *
@@ -862,18 +689,6 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
CLUTTER_LINEAR, CLUTTER_LINEAR,
CLUTTER_PARAM_READWRITE); 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->dispose = clutter_timeline_dispose;
object_class->finalize = clutter_timeline_finalize; object_class->finalize = clutter_timeline_finalize;
object_class->set_property = clutter_timeline_set_property; object_class->set_property = clutter_timeline_set_property;
@@ -1156,6 +971,7 @@ set_is_playing (ClutterTimeline *timeline,
gboolean is_playing) gboolean is_playing)
{ {
ClutterTimelinePrivate *priv = timeline->priv; ClutterTimelinePrivate *priv = timeline->priv;
ClutterMasterClock *master_clock;
is_playing = !!is_playing; is_playing = !!is_playing;
@@ -1164,17 +980,15 @@ set_is_playing (ClutterTimeline *timeline,
priv->is_playing = is_playing; priv->is_playing = is_playing;
master_clock = _clutter_master_clock_get_default ();
if (priv->is_playing) if (priv->is_playing)
{ {
priv->waiting_first_tick = TRUE; priv->waiting_first_tick = TRUE;
priv->current_repeat = 0; priv->current_repeat = 0;
_clutter_master_clock_add_timeline (master_clock, timeline);
maybe_add_timeline (timeline);
} }
else else
{ _clutter_master_clock_remove_timeline (master_clock, timeline);
maybe_remove_timeline (timeline);
}
} }
static gboolean static gboolean
@@ -1371,9 +1185,6 @@ clutter_timeline_start (ClutterTimeline *timeline)
if (priv->duration == 0) if (priv->duration == 0)
return; return;
g_warn_if_fail ((priv->actor && clutter_actor_get_stage (priv->actor)) ||
priv->frame_clock);
if (priv->delay) if (priv->delay)
priv->delay_id = clutter_threads_add_timeout (priv->delay, priv->delay_id = clutter_threads_add_timeout (priv->delay,
delay_timeout_func, delay_timeout_func,
@@ -1440,6 +1251,45 @@ clutter_timeline_stop (ClutterTimeline *timeline)
g_signal_emit (timeline, timeline_signals[STOPPED], 0, FALSE); 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: * clutter_timeline_rewind:
* @timeline: A #ClutterTimeline * @timeline: A #ClutterTimeline
@@ -1556,10 +1406,48 @@ clutter_timeline_is_playing (ClutterTimeline *timeline)
} }
/** /**
* clutter_timeline_new: * clutter_timeline_clone:
* @duration_ms: Duration of the timeline in milliseconds * @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 * Return value: the newly created #ClutterTimeline instance. Use
* g_object_unref() when done using it * g_object_unref() when done using it
@@ -1567,50 +1455,10 @@ clutter_timeline_is_playing (ClutterTimeline *timeline)
* Since: 0.6 * Since: 0.6
*/ */
ClutterTimeline * ClutterTimeline *
clutter_timeline_new (guint duration_ms) clutter_timeline_new (guint msecs)
{ {
return g_object_new (CLUTTER_TYPE_TIMELINE, return g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", duration_ms, "duration", msecs,
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,
NULL); NULL);
} }
@@ -1876,7 +1724,7 @@ _clutter_timeline_do_tick (ClutterTimeline *timeline,
/* Check the is_playing variable before performing the timeline tick. /* Check the is_playing variable before performing the timeline tick.
* This is necessary, as if a timeline is stopped in response to a * 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. * still be reached.
*/ */
if (!priv->is_playing) if (!priv->is_playing)
@@ -2694,32 +2542,3 @@ clutter_timeline_get_cubic_bezier_progress (ClutterTimeline *timeline,
return TRUE; 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; GType clutter_timeline_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT CLUTTER_EXPORT
ClutterTimeline * clutter_timeline_new_for_actor (ClutterActor *actor, ClutterTimeline * clutter_timeline_new (guint msecs);
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);
CLUTTER_EXPORT CLUTTER_EXPORT
guint clutter_timeline_get_duration (ClutterTimeline *timeline); guint clutter_timeline_get_duration (ClutterTimeline *timeline);
@@ -233,13 +221,6 @@ gint64 clutter_timeline_get_duration_hint
CLUTTER_EXPORT CLUTTER_EXPORT
gint clutter_timeline_get_current_repeat (ClutterTimeline *timeline); 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 G_END_DECLS
#endif /* _CLUTTER_TIMELINE_H__ */ #endif /* _CLUTTER_TIMELINE_H__ */

View File

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

View File

@@ -364,7 +364,6 @@ clutter_transition_set_animatable (ClutterTransition *transition,
ClutterAnimatable *animatable) ClutterAnimatable *animatable)
{ {
ClutterTransitionPrivate *priv; ClutterTransitionPrivate *priv;
ClutterActor *actor;
g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
g_return_if_fail (animatable == NULL || CLUTTER_IS_ANIMATABLE (animatable)); 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); priv->animatable = g_object_ref (animatable);
clutter_transition_attach (transition, priv->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 _ClutterPaintNode ClutterPaintNode;
typedef struct _ClutterContent ClutterContent; /* dummy */ typedef struct _ClutterContent ClutterContent; /* dummy */
typedef struct _ClutterScrollActor ClutterScrollActor; typedef struct _ClutterScrollActor ClutterScrollActor;
typedef struct _ClutterFrameClock ClutterFrameClock;
typedef struct _ClutterInterval ClutterInterval; typedef struct _ClutterInterval ClutterInterval;
typedef struct _ClutterAnimatable ClutterAnimatable; /* dummy */ 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) #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 CLUTTER_EXPORT
GType clutter_actor_box_get_type (void) G_GNUC_CONST; GType clutter_actor_box_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT CLUTTER_EXPORT
@@ -267,9 +252,6 @@ CLUTTER_EXPORT
void clutter_actor_box_scale (ClutterActorBox *box, void clutter_actor_box_scale (ClutterActorBox *box,
gfloat scale); gfloat scale);
CLUTTER_EXPORT
gboolean clutter_actor_box_is_initialized (ClutterActorBox *box);
/** /**
* ClutterKnot: * ClutterKnot:
* @x: X coordinate of the knot * @x: X coordinate of the knot

View File

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

View File

@@ -47,7 +47,6 @@
#include "clutter-private.h" #include "clutter-private.h"
#include "clutter-stage-private.h" #include "clutter-stage-private.h"
#include "clutter-stage-view-private.h" #include "clutter-stage-view-private.h"
#include "cogl.h"
#define MAX_STACK_RECTS 256 #define MAX_STACK_RECTS 256
@@ -56,25 +55,17 @@ typedef struct _ClutterStageViewCoglPrivate
/* Damage history, in stage view render target framebuffer coordinate space. /* Damage history, in stage view render target framebuffer coordinate space.
*/ */
ClutterDamageHistory *damage_history; ClutterDamageHistory *damage_history;
guint notify_presented_handle_id;
} ClutterStageViewCoglPrivate; } ClutterStageViewCoglPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl, G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl,
CLUTTER_TYPE_STAGE_VIEW) CLUTTER_TYPE_STAGE_VIEW)
typedef struct _ClutterStageCoglPrivate
{
int64_t global_frame_counter;
} ClutterStageCoglPrivate;
static void static void
clutter_stage_window_iface_init (ClutterStageWindowInterface *iface); clutter_stage_window_iface_init (ClutterStageWindowInterface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageCogl, G_DEFINE_TYPE_WITH_CODE (ClutterStageCogl,
_clutter_stage_cogl, _clutter_stage_cogl,
G_TYPE_OBJECT, G_TYPE_OBJECT,
G_ADD_PRIVATE (ClutterStageCogl)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init)); clutter_stage_window_iface_init));
@@ -86,12 +77,67 @@ enum
PROP_LAST PROP_LAST
}; };
static void
clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window,
gint sync_delay);
static void static void
clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window) clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window)
{ {
CLUTTER_NOTE (BACKEND, "Unrealizing Cogl stage [%p]", 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 static gboolean
clutter_stage_cogl_realize (ClutterStageWindow *stage_window) clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
{ {
@@ -112,14 +158,101 @@ clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
return TRUE; return TRUE;
} }
static int64_t static void
clutter_stage_cogl_get_frame_counter (ClutterStageWindow *stage_window) clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window,
gint sync_delay)
{ {
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
ClutterStageCoglPrivate *priv = gint64 now;
_clutter_stage_cogl_get_instance_private (stage_cogl); 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 * static ClutterActor *
@@ -222,35 +355,12 @@ paint_damage_region (ClutterStageWindow *stage_window,
cogl_framebuffer_pop_matrix (framebuffer); cogl_framebuffer_pop_matrix (framebuffer);
} }
typedef struct _NotifyPresentedClosure
{
ClutterStageView *view;
ClutterFrameInfo frame_info;
} NotifyPresentedClosure;
static gboolean 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, swap_framebuffer (ClutterStageWindow *stage_window,
ClutterStageView *view, ClutterStageView *view,
cairo_region_t *swap_region, cairo_region_t *swap_region,
gboolean swap_with_damage) 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); CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
clutter_stage_view_before_swap_buffer (view, swap_region); clutter_stage_view_before_swap_buffer (view, swap_region);
@@ -259,7 +369,6 @@ swap_framebuffer (ClutterStageWindow *stage_window,
{ {
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
int *damage, n_rects, i; int *damage, n_rects, i;
CoglFrameInfo *frame_info;
n_rects = cairo_region_num_rectangles (swap_region); n_rects = cairo_region_num_rectangles (swap_region);
damage = g_newa (int, n_rects * 4); damage = g_newa (int, n_rects * 4);
@@ -274,9 +383,6 @@ swap_framebuffer (ClutterStageWindow *stage_window,
damage[i * 4 + 3] = rect.height; damage[i * 4 + 3] = rect.height;
} }
frame_info = cogl_frame_info_new (priv->global_frame_counter);
priv->global_frame_counter++;
/* push on the screen */ /* push on the screen */
if (n_rects > 0 && !swap_with_damage) if (n_rects > 0 && !swap_with_damage)
{ {
@@ -285,8 +391,9 @@ swap_framebuffer (ClutterStageWindow *stage_window,
onscreen); onscreen);
cogl_onscreen_swap_region (onscreen, cogl_onscreen_swap_region (onscreen,
damage, n_rects, damage, n_rects);
frame_info);
return FALSE;
} }
else else
{ {
@@ -294,35 +401,18 @@ swap_framebuffer (ClutterStageWindow *stage_window,
onscreen); onscreen);
cogl_onscreen_swap_buffers_with_damage (onscreen, cogl_onscreen_swap_buffers_with_damage (onscreen,
damage, n_rects, damage, n_rects);
frame_info);
return TRUE;
} }
} }
else 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)", CLUTTER_NOTE (BACKEND, "cogl_framebuffer_finish (framebuffer: %p)",
framebuffer); framebuffer);
cogl_framebuffer_finish (framebuffer); cogl_framebuffer_finish (framebuffer);
closure = g_new0 (NotifyPresentedClosure, 1); return FALSE;
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);
} }
} }
@@ -449,11 +539,11 @@ is_buffer_age_enabled (void)
cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE); cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
} }
static void static gboolean
clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl, clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
ClutterStageView *view) 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); ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
ClutterStageViewCoglPrivate *view_priv = ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl); 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); CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
cairo_rectangle_int_t view_rect; cairo_rectangle_int_t view_rect;
gboolean is_full_redraw; gboolean is_full_redraw;
gboolean use_clipped_redraw = TRUE; gboolean use_clipped_redraw;
gboolean can_blit_sub_buffer; gboolean can_blit_sub_buffer;
gboolean has_buffer_age; gboolean has_buffer_age;
gboolean swap_with_damage; gboolean swap_with_damage;
@@ -471,7 +561,8 @@ clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl,
cairo_region_t *swap_region; cairo_region_t *swap_region;
float fb_scale; float fb_scale;
int fb_width, fb_height; int fb_width, fb_height;
int buffer_age = 0; int buffer_age;
gboolean res;
clutter_stage_view_get_layout (view, &view_rect); clutter_stage_view_get_layout (view, &view_rect);
fb_scale = clutter_stage_view_get_scale (view); 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); 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; swap_with_damage = FALSE;
if (has_buffer_age) if (has_buffer_age)
@@ -639,12 +730,14 @@ clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl,
cairo_region_destroy (queued_redraw_clip); cairo_region_destroy (queued_redraw_clip);
} }
swap_framebuffer (stage_window, res = swap_framebuffer (stage_window,
view, view,
swap_region, swap_region,
swap_with_damage); swap_with_damage);
cairo_region_destroy (swap_region); cairo_region_destroy (swap_region);
return res;
} }
static void static void
@@ -652,34 +745,62 @@ clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
ClutterStageView *view, ClutterStageView *view,
CoglScanout *scanout) CoglScanout *scanout)
{ {
ClutterStageCoglPrivate *priv =
_clutter_stage_cogl_get_instance_private (stage_cogl);
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view); CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
CoglOnscreen *onscreen; CoglOnscreen *onscreen;
CoglFrameInfo *frame_info;
g_return_if_fail (cogl_is_onscreen (framebuffer)); g_return_if_fail (cogl_is_onscreen (framebuffer));
onscreen = COGL_ONSCREEN (framebuffer); onscreen = COGL_ONSCREEN (framebuffer);
cogl_onscreen_direct_scanout (onscreen, scanout);
frame_info = cogl_frame_info_new (priv->global_frame_counter);
priv->global_frame_counter++;
cogl_onscreen_direct_scanout (onscreen, scanout, frame_info);
} }
static void static void
clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window, clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
ClutterStageView *view)
{ {
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (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); COGL_TRACE_BEGIN (ClutterStageCoglRedraw, "Paint (Cogl Redraw)");
if (scanout)
clutter_stage_cogl_scanout_view (stage_cogl, view, scanout); for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
else {
clutter_stage_cogl_redraw_view_primary (stage_cogl, view); 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 static void
@@ -691,8 +812,10 @@ clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
iface->resize = clutter_stage_cogl_resize; iface->resize = clutter_stage_cogl_resize;
iface->show = clutter_stage_cogl_show; iface->show = clutter_stage_cogl_show;
iface->hide = clutter_stage_cogl_hide; iface->hide = clutter_stage_cogl_hide;
iface->get_frame_counter = clutter_stage_cogl_get_frame_counter; iface->schedule_update = clutter_stage_cogl_schedule_update;
iface->redraw_view = clutter_stage_cogl_redraw_view; 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 static void
@@ -733,43 +856,10 @@ _clutter_stage_cogl_class_init (ClutterStageCoglClass *klass)
static void static void
_clutter_stage_cogl_init (ClutterStageCogl *stage) _clutter_stage_cogl_init (ClutterStageCogl *stage)
{ {
} stage->last_presentation_time = 0;
stage->refresh_rate = 0.0;
static void stage->update_time = -1;
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 static void
@@ -779,7 +869,6 @@ clutter_stage_view_cogl_finalize (GObject *object)
ClutterStageViewCoglPrivate *view_priv = ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl); clutter_stage_view_cogl_get_instance_private (view_cogl);
g_clear_handle_id (&view_priv->notify_presented_handle_id, g_source_remove);
clutter_damage_history_free (view_priv->damage_history); clutter_damage_history_free (view_priv->damage_history);
G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->finalize (object); G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->finalize (object);
@@ -792,9 +881,6 @@ clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl)
clutter_stage_view_cogl_get_instance_private (view_cogl); clutter_stage_view_cogl_get_instance_private (view_cogl);
view_priv->damage_history = clutter_damage_history_new (); view_priv->damage_history = clutter_damage_history_new ();
g_signal_connect (view_cogl, "notify::framebuffer",
G_CALLBACK (on_framebuffer_set), NULL);
} }
static void static void

View File

@@ -41,6 +41,20 @@ struct _ClutterStageCogl
/* back pointer to the backend */ /* back pointer to the backend */
ClutterBackend *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 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 G_BEGIN_DECLS
CLUTTER_DEPRECATED_FOR(clutter_timeline_new_for_actor) CLUTTER_DEPRECATED_FOR(clutter_timeline_new)
ClutterTimeline * clutter_timeline_new (guint duration_ms); 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 G_END_DECLS

View File

@@ -36,9 +36,9 @@ clutter_headers = [
'clutter-feature.h', 'clutter-feature.h',
'clutter-fixed-layout.h', 'clutter-fixed-layout.h',
'clutter-flow-layout.h', 'clutter-flow-layout.h',
'clutter-frame-clock.h',
'clutter-gesture-action.h', 'clutter-gesture-action.h',
'clutter-grid-layout.h', 'clutter-grid-layout.h',
'clutter-group.h',
'clutter-image.h', 'clutter-image.h',
'clutter-input-device.h', 'clutter-input-device.h',
'clutter-input-device-tool.h', 'clutter-input-device-tool.h',
@@ -123,7 +123,6 @@ clutter_sources = [
'clutter-fixed-layout.c', 'clutter-fixed-layout.c',
'clutter-flatten-effect.c', 'clutter-flatten-effect.c',
'clutter-flow-layout.c', 'clutter-flow-layout.c',
'clutter-frame-clock.c',
'clutter-gesture-action.c', 'clutter-gesture-action.c',
'clutter-graphene.c', 'clutter-graphene.c',
'clutter-grid-layout.c', 'clutter-grid-layout.c',
@@ -141,6 +140,8 @@ clutter_sources = [
'clutter-layout-manager.c', 'clutter-layout-manager.c',
'clutter-layout-meta.c', 'clutter-layout-meta.c',
'clutter-main.c', 'clutter-main.c',
'clutter-master-clock.c',
'clutter-master-clock-default.c',
'clutter-offscreen-effect.c', 'clutter-offscreen-effect.c',
'clutter-page-turn-effect.c', 'clutter-page-turn-effect.c',
'clutter-paint-context.c', 'clutter-paint-context.c',
@@ -198,6 +199,8 @@ clutter_private_headers = [
'clutter-input-focus-private.h', 'clutter-input-focus-private.h',
'clutter-input-method-private.h', 'clutter-input-method-private.h',
'clutter-input-pointer-a11y-private.h', 'clutter-input-pointer-a11y-private.h',
'clutter-master-clock.h',
'clutter-master-clock-default.h',
'clutter-offscreen-effect-private.h', 'clutter-offscreen-effect-private.h',
'clutter-paint-context-private.h', 'clutter-paint-context-private.h',
'clutter-paint-node-private.h', 'clutter-paint-node-private.h',
@@ -209,7 +212,6 @@ clutter_private_headers = [
'clutter-stage-private.h', 'clutter-stage-private.h',
'clutter-stage-view-private.h', 'clutter-stage-view-private.h',
'clutter-stage-window.h', 'clutter-stage-window.h',
'clutter-timeline-private.h',
] ]
clutter_nonintrospected_sources = [ clutter_nonintrospected_sources = [
@@ -218,10 +220,21 @@ clutter_nonintrospected_sources = [
] ]
clutter_deprecated_headers = [ clutter_deprecated_headers = [
'deprecated/clutter-actor.h',
'deprecated/clutter-box.h',
'deprecated/clutter-container.h', 'deprecated/clutter-container.h',
'deprecated/clutter-group.h',
'deprecated/clutter-rectangle.h',
'deprecated/clutter-stage.h',
'deprecated/clutter-timeline.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_sources = []
clutter_backend_nonintrospected_sources = [ clutter_backend_nonintrospected_sources = [
'cogl/clutter-stage-cogl.c', 'cogl/clutter-stage-cogl.c',
@@ -275,8 +288,10 @@ cally_headers = [
'cally/cally-actor.h', 'cally/cally-actor.h',
'cally/cally-clone.h', 'cally/cally-clone.h',
'cally/cally-factory.h', 'cally/cally-factory.h',
'cally/cally-group.h',
'cally/cally.h', 'cally/cally.h',
'cally/cally-main.h', 'cally/cally-main.h',
'cally/cally-rectangle.h',
'cally/cally-root.h', 'cally/cally-root.h',
'cally/cally-stage.h', 'cally/cally-stage.h',
'cally/cally-text.h', 'cally/cally-text.h',
@@ -287,6 +302,8 @@ cally_sources = [
'cally/cally-actor.c', 'cally/cally-actor.c',
'cally/cally.c', 'cally/cally.c',
'cally/cally-clone.c', 'cally/cally-clone.c',
'cally/cally-group.c',
'cally/cally-rectangle.c',
'cally/cally-root.c', 'cally/cally-root.c',
'cally/cally-stage.c', 'cally/cally-stage.c',
'cally/cally-text.c', 'cally/cally-text.c',
@@ -368,6 +385,7 @@ libmutter_clutter = shared_library(libmutter_clutter_name,
clutter_headers, clutter_headers,
clutter_private_headers, clutter_private_headers,
clutter_nonintrospected_sources, clutter_nonintrospected_sources,
clutter_deprecated_sources,
clutter_deprecated_headers, clutter_deprecated_headers,
clutter_backend_sources, clutter_backend_sources,
clutter_backend_nonintrospected_sources, clutter_backend_nonintrospected_sources,
@@ -413,6 +431,7 @@ if have_introspection
clutter_built_headers, clutter_built_headers,
clutter_sources, clutter_sources,
clutter_headers, clutter_headers,
clutter_deprecated_sources,
clutter_deprecated_headers, clutter_deprecated_headers,
], ],
nsversion: libmutter_api_version, nsversion: libmutter_api_version,

View File

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

View File

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

View File

@@ -51,6 +51,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.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); static void _cogl_attribute_free (CoglAttribute *attribute);
COGL_OBJECT_DEFINE (Attribute, attribute); COGL_OBJECT_DEFINE (Attribute, attribute);

View File

@@ -34,6 +34,7 @@
#include "cogl-boxed-value.h" #include "cogl-boxed-value.h"
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "driver/gl/cogl-util-gl-private.h"
gboolean gboolean
_cogl_boxed_value_equal (const CoglBoxedValue *bva, _cogl_boxed_value_equal (const CoglBoxedValue *bva,
@@ -285,5 +286,90 @@ _cogl_boxed_value_set_uniform (CoglContext *ctx,
GLint location, GLint location,
const CoglBoxedValue *value) 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-pipeline-cache.h"
#include "cogl-texture-2d.h" #include "cogl-texture-2d.h"
#include "cogl-sampler-cache-private.h" #include "cogl-sampler-cache-private.h"
#include "cogl-gpu-info-private.h"
#include "cogl-gl-header.h" #include "cogl-gl-header.h"
#include "cogl-framebuffer-private.h" #include "cogl-framebuffer-private.h"
#include "cogl-onscreen-private.h" #include "cogl-onscreen-private.h"
@@ -69,12 +70,14 @@ struct _CoglContext
CoglDriver driver; CoglDriver driver;
/* Information about the GPU and driver which we can use to
determine certain workarounds */
CoglGpuInfo gpu;
/* vtables for the driver functions */ /* vtables for the driver functions */
const CoglDriverVtable *driver_vtable; const CoglDriverVtable *driver_vtable;
const CoglTextureDriver *texture_driver; const CoglTextureDriver *texture_driver;
void *driver_context;
int glsl_major; int glsl_major;
int glsl_minor; int glsl_minor;
@@ -121,6 +124,9 @@ struct _CoglContext
CoglMatrixEntry identity_entry; CoglMatrixEntry identity_entry;
GArray *texture_units;
int active_texture_unit;
/* Only used for comparing other pipelines when reading pixels. */ /* Only used for comparing other pipelines when reading pixels. */
CoglPipeline *opaque_color_pipeline; CoglPipeline *opaque_color_pipeline;
@@ -309,4 +315,18 @@ void
_cogl_context_set_current_modelview_entry (CoglContext *context, _cogl_context_set_current_modelview_entry (CoglContext *context,
CoglMatrixEntry *entry); 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 */ #endif /* __COGL_CONTEXT_PRIVATE_H */

View File

@@ -45,12 +45,40 @@
#include "cogl-onscreen-private.h" #include "cogl-onscreen-private.h"
#include "cogl-attribute-private.h" #include "cogl-attribute-private.h"
#include "cogl1-context.h" #include "cogl1-context.h"
#include "cogl-gpu-info-private.h"
#include "cogl-gtype-private.h" #include "cogl-gtype-private.h"
#include "winsys/cogl-winsys-private.h" #include "winsys/cogl-winsys-private.h"
#include <string.h> #include <string.h>
#include <stdlib.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); static void _cogl_context_free (CoglContext *context);
COGL_OBJECT_DEFINE (Context, context); COGL_OBJECT_DEFINE (Context, context);
@@ -442,6 +470,94 @@ _cogl_context_set_current_modelview_entry (CoglContext *context,
context->current_modelview_entry = entry; 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 int64_t
cogl_get_clock_time (CoglContext *context) cogl_get_clock_time (CoglContext *context)
{ {
@@ -456,11 +572,24 @@ cogl_get_clock_time (CoglContext *context)
CoglGraphicsResetStatus CoglGraphicsResetStatus
cogl_get_graphics_reset_status (CoglContext *context) 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 switch (context->glGetGraphicsResetStatus ())
cogl_context_is_hardware_accelerated (CoglContext *context) {
{ case GL_GUILTY_CONTEXT_RESET_ARB:
return context->driver_vtable->is_hardware_accelerated (context); return COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET;
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_EXPORT CoglGraphicsResetStatus
cogl_get_graphics_reset_status (CoglContext *context); 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 G_END_DECLS
#endif /* __COGL_CONTEXT_H__ */ #endif /* __COGL_CONTEXT_H__ */

View File

@@ -35,7 +35,6 @@
#include "cogl-offscreen.h" #include "cogl-offscreen.h"
#include "cogl-framebuffer-private.h" #include "cogl-framebuffer-private.h"
#include "cogl-attribute-private.h" #include "cogl-attribute-private.h"
#include "cogl-sampler-cache-private.h"
typedef struct _CoglDriverVtable CoglDriverVtable; typedef struct _CoglDriverVtable CoglDriverVtable;
@@ -47,12 +46,6 @@ struct _CoglDriverVtable
void void
(* context_deinit) (CoglContext *context); (* 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 /* TODO: factor this out since this is OpenGL specific and
* so can be ignored by non-OpenGL drivers. */ * so can be ignored by non-OpenGL drivers. */
gboolean gboolean
@@ -269,19 +262,6 @@ struct _CoglDriverVtable
const void *data, const void *data,
unsigned int size, unsigned int size,
GError **error); 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 ()) #define COGL_DRIVER_ERROR (_cogl_driver_error_quark ())

View File

@@ -43,9 +43,10 @@ struct _CoglFrameInfo
float refresh_rate; float refresh_rate;
int64_t global_frame_counter; int64_t global_frame_counter;
CoglOutput *output;
}; };
COGL_EXPORT CoglFrameInfo *_cogl_frame_info_new (void);
CoglFrameInfo *cogl_frame_info_new (int64_t global_frame_counter);
#endif /* __COGL_FRAME_INFO_PRIVATE_H */ #endif /* __COGL_FRAME_INFO_PRIVATE_H */

View File

@@ -39,12 +39,11 @@ COGL_OBJECT_DEFINE (FrameInfo, frame_info);
COGL_GTYPE_DEFINE_CLASS (FrameInfo, frame_info); COGL_GTYPE_DEFINE_CLASS (FrameInfo, frame_info);
CoglFrameInfo * CoglFrameInfo *
cogl_frame_info_new (int64_t global_frame_counter) _cogl_frame_info_new (void)
{ {
CoglFrameInfo *info; CoglFrameInfo *info;
info = g_slice_new0 (CoglFrameInfo); info = g_slice_new0 (CoglFrameInfo);
info->global_frame_counter = global_frame_counter;
return _cogl_frame_info_object_new (info); return _cogl_frame_info_object_new (info);
} }
@@ -73,6 +72,12 @@ cogl_frame_info_get_refresh_rate (CoglFrameInfo *info)
return info->refresh_rate; return info->refresh_rate;
} }
CoglOutput *
cogl_frame_info_get_output (CoglFrameInfo *info)
{
return info->output;
}
int64_t int64_t
cogl_frame_info_get_global_frame_counter (CoglFrameInfo *info) cogl_frame_info_get_global_frame_counter (CoglFrameInfo *info)
{ {

View File

@@ -45,11 +45,6 @@
G_BEGIN_DECLS G_BEGIN_DECLS
/**
* CoglFrameInfo:
*
* Frame information.
*/
typedef struct _CoglFrameInfo CoglFrameInfo; typedef struct _CoglFrameInfo CoglFrameInfo;
#define COGL_FRAME_INFO(X) ((CoglFrameInfo *)(X)) #define COGL_FRAME_INFO(X) ((CoglFrameInfo *)(X))
@@ -131,6 +126,20 @@ int64_t cogl_frame_info_get_presentation_time (CoglFrameInfo *info);
COGL_EXPORT COGL_EXPORT
float cogl_frame_info_get_refresh_rate (CoglFrameInfo *info); float cogl_frame_info_get_refresh_rate (CoglFrameInfo *info);
/**
* cogl_frame_info_get_output:
* @info: a #CoglFrameInfo object
*
* Gets the #CoglOutput that the swapped frame was presented to.
*
* Return value: (transfer none): The #CoglOutput that the frame was
* presented to, or %NULL if this could not be determined.
* Since: 1.14
* Stability: unstable
*/
COGL_EXPORT CoglOutput *
cogl_frame_info_get_output (CoglFrameInfo *info);
/** /**
* cogl_frame_info_get_global_frame_counter: (skip) * cogl_frame_info_get_global_frame_counter: (skip)
*/ */

View File

@@ -0,0 +1,41 @@
/*
* Cogl
*
* A Low Level GPU Graphics and Utilities API
*
* Copyright (C) 2012 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _COGL_GLSL_SHADER_PRIVATE_H_
#define _COGL_GLSL_SHADER_PRIVATE_H_
void
_cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx,
GLuint shader_gl_handle,
GLenum shader_gl_type,
CoglPipeline *pipeline,
GLsizei count_in,
const char **strings_in,
const GLint *lengths_in);
#endif /* _COGL_GLSL_SHADER_PRIVATE_H_ */

View File

@@ -0,0 +1,189 @@
/*
* Cogl
*
* A Low Level GPU Graphics and Utilities API
*
* Copyright (C) 2012 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*
* Authors:
* Robert Bragg <robert@linux.intel.com>
* Neil Roberts <neil@linux.intel.com>
*/
#include "cogl-config.h"
#include "cogl-context-private.h"
#include "cogl-glsl-shader-private.h"
#include "cogl-glsl-shader-boilerplate.h"
#include "driver/gl/cogl-util-gl-private.h"
#include <string.h>
#include <glib.h>
static gboolean
add_layer_vertex_boilerplate_cb (CoglPipelineLayer *layer,
void *user_data)
{
GString *layer_declarations = user_data;
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
g_string_append_printf (layer_declarations,
"attribute vec4 cogl_tex_coord%d_in;\n"
"#define cogl_texture_matrix%i cogl_texture_matrix[%i]\n"
"#define cogl_tex_coord%i_out _cogl_tex_coord[%i]\n",
layer->index,
layer->index,
unit_index,
layer->index,
unit_index);
return TRUE;
}
static gboolean
add_layer_fragment_boilerplate_cb (CoglPipelineLayer *layer,
void *user_data)
{
GString *layer_declarations = user_data;
g_string_append_printf (layer_declarations,
"#define cogl_tex_coord%i_in _cogl_tex_coord[%i]\n",
layer->index,
_cogl_pipeline_layer_get_unit_index (layer));
return TRUE;
}
void
_cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx,
GLuint shader_gl_handle,
GLenum shader_gl_type,
CoglPipeline *pipeline,
GLsizei count_in,
const char **strings_in,
const GLint *lengths_in)
{
const char *vertex_boilerplate;
const char *fragment_boilerplate;
const char **strings = g_alloca (sizeof (char *) * (count_in + 4));
GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 4));
char *version_string;
int count = 0;
int n_layers;
vertex_boilerplate = _COGL_VERTEX_SHADER_BOILERPLATE;
fragment_boilerplate = _COGL_FRAGMENT_SHADER_BOILERPLATE;
version_string = g_strdup_printf ("#version %i\n\n",
ctx->glsl_version_to_use);
strings[count] = version_string;
lengths[count++] = -1;
if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL))
{
static const char image_external_extension[] =
"#extension GL_OES_EGL_image_external : require\n";
strings[count] = image_external_extension;
lengths[count++] = sizeof (image_external_extension) - 1;
}
if (shader_gl_type == GL_VERTEX_SHADER)
{
strings[count] = vertex_boilerplate;
lengths[count++] = strlen (vertex_boilerplate);
}
else if (shader_gl_type == GL_FRAGMENT_SHADER)
{
strings[count] = fragment_boilerplate;
lengths[count++] = strlen (fragment_boilerplate);
}
n_layers = cogl_pipeline_get_n_layers (pipeline);
if (n_layers)
{
GString *layer_declarations = ctx->codegen_boilerplate_buffer;
g_string_set_size (layer_declarations, 0);
g_string_append_printf (layer_declarations,
"varying vec4 _cogl_tex_coord[%d];\n",
n_layers);
if (shader_gl_type == GL_VERTEX_SHADER)
{
g_string_append_printf (layer_declarations,
"uniform mat4 cogl_texture_matrix[%d];\n",
n_layers);
_cogl_pipeline_foreach_layer_internal (pipeline,
add_layer_vertex_boilerplate_cb,
layer_declarations);
}
else if (shader_gl_type == GL_FRAGMENT_SHADER)
{
_cogl_pipeline_foreach_layer_internal (pipeline,
add_layer_fragment_boilerplate_cb,
layer_declarations);
}
strings[count] = layer_declarations->str;
lengths[count++] = -1; /* null terminated */
}
memcpy (strings + count, strings_in, sizeof (char *) * count_in);
if (lengths_in)
memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in);
else
{
int i;
for (i = 0; i < count_in; i++)
lengths[count + i] = -1; /* null terminated */
}
count += count_in;
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
{
GString *buf = g_string_new (NULL);
int i;
g_string_append_printf (buf,
"%s shader:\n",
shader_gl_type == GL_VERTEX_SHADER ?
"vertex" : "fragment");
for (i = 0; i < count; i++)
if (lengths[i] != -1)
g_string_append_len (buf, strings[i], lengths[i]);
else
g_string_append (buf, strings[i]);
g_message ("%s", buf->str);
g_string_free (buf, TRUE);
}
GE( ctx, glShaderSource (shader_gl_handle, count,
(const char **) strings, lengths) );
g_free (version_string);
}

View File

@@ -0,0 +1,112 @@
/*
* Cogl
*
* A Low Level GPU Graphics and Utilities API
*
* Copyright (C) 2012 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
#ifndef __COGL_GPU_INFO_PRIVATE_H
#define __COGL_GPU_INFO_PRIVATE_H
#include "cogl-context.h"
typedef enum _CoglGpuInfoArchitectureFlag
{
COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_IMMEDIATE_MODE,
COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_TILED,
COGL_GPU_INFO_ARCHITECTURE_FLAG_VERTEX_SOFTWARE,
COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_IMMEDIATE_MODE,
COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_DEFERRED,
COGL_GPU_INFO_ARCHITECTURE_FLAG_FRAGMENT_SOFTWARE
} CoglGpuInfoArchitectureFlag;
typedef enum _CoglGpuInfoArchitecture
{
COGL_GPU_INFO_ARCHITECTURE_UNKNOWN,
COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE,
COGL_GPU_INFO_ARCHITECTURE_SGX,
COGL_GPU_INFO_ARCHITECTURE_MALI,
COGL_GPU_INFO_ARCHITECTURE_LLVMPIPE,
COGL_GPU_INFO_ARCHITECTURE_SOFTPIPE,
COGL_GPU_INFO_ARCHITECTURE_SWRAST
} CoglGpuInfoArchitecture;
typedef enum
{
COGL_GPU_INFO_VENDOR_UNKNOWN,
COGL_GPU_INFO_VENDOR_INTEL,
COGL_GPU_INFO_VENDOR_IMAGINATION_TECHNOLOGIES,
COGL_GPU_INFO_VENDOR_ARM,
COGL_GPU_INFO_VENDOR_QUALCOMM,
COGL_GPU_INFO_VENDOR_NVIDIA,
COGL_GPU_INFO_VENDOR_ATI,
COGL_GPU_INFO_VENDOR_MESA
} CoglGpuInfoVendor;
typedef enum
{
COGL_GPU_INFO_DRIVER_PACKAGE_UNKNOWN,
COGL_GPU_INFO_DRIVER_PACKAGE_MESA
} CoglGpuInfoDriverPackage;
typedef enum
{
COGL_GPU_INFO_DRIVER_STUB
} CoglGpuInfoDriverBug;
typedef struct _CoglGpuInfoVersion CoglGpuInfoVersion;
typedef struct _CoglGpuInfo CoglGpuInfo;
struct _CoglGpuInfo
{
CoglGpuInfoVendor vendor;
const char *vendor_name;
CoglGpuInfoDriverPackage driver_package;
const char *driver_package_name;
int driver_package_version;
CoglGpuInfoArchitecture architecture;
const char *architecture_name;
CoglGpuInfoArchitectureFlag architecture_flags;
CoglGpuInfoDriverBug driver_bugs;
};
/*
* _cogl_gpu_info_init:
* @ctx: A #CoglContext
* @gpu: A return location for the GPU information
*
* Determines information about the GPU and driver from the given
* context.
*/
void
_cogl_gpu_info_init (CoglContext *ctx,
CoglGpuInfo *gpu);
#endif /* __COGL_GPU_INFO_PRIVATE_H */

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