clutter: Move Image down to GNOME Shell

As is, ClutterImage is not really useful, it only serves for rendering a
CoglTexture as an actor. Shell, has a subclass that adds more features
that unfortunately cannot be upstreamed without bringing more gdk-pixbuf
usage inside libmutter, eg implementing GIcon/GLoadableIcon.

It also has requirements based on whether the image is symbolic or not.
Things that Clutter so far doesn't care about.

So just remove ClutterImage & let shells re-implement it themselves if
needed based on their needs.

Note, that once we have ClutterSnapshot, it should be straightforward to
write a custom actor that renders a CoglTexture or so.

This "un"fortunately means getting rid of various interactive tests that
either didn't compile at all or are not useful as is, like all the
remaining interactive tests.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4133>
This commit is contained in:
Bilal Elmoussaoui 2024-11-15 12:24:23 +01:00 committed by Marge Bot
parent 4284371a26
commit a2dd7d6d1d
12 changed files with 0 additions and 2156 deletions

View File

@ -1,425 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive image' library.
*
* Copyright (C) 2012 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>
*/
/**
* ClutterImage:
*
* Image data content
*
* #ClutterImage is a #ClutterContent implementation that displays
* image data inside a [class@Actor].
*/
#include "config.h"
#include "clutter/clutter-image.h"
#include "clutter/clutter-actor-private.h"
#include "clutter/clutter-content-private.h"
#include "clutter/clutter-debug.h"
#include "clutter/clutter-paint-node.h"
#include "clutter/clutter-paint-nodes.h"
#include "clutter/clutter-private.h"
typedef struct
{
CoglTexture *texture;
gint width;
gint height;
} ClutterImagePrivate;
static void clutter_content_iface_init (ClutterContentInterface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterImage, clutter_image, G_TYPE_OBJECT,
G_ADD_PRIVATE (ClutterImage)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
clutter_content_iface_init))
static CoglTexture *
create_texture_from_data (unsigned int width,
unsigned int height,
CoglPixelFormat pixel_format,
unsigned int row_stride,
const uint8_t *data,
GError **error)
{
ClutterContext *context = _clutter_context_get_default ();
ClutterBackend *backend = clutter_context_get_backend (context);
CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
CoglTexture *texture_2d;
texture_2d = cogl_texture_2d_new_from_data (cogl_context,
width,
height,
pixel_format,
row_stride,
data,
error);
return texture_2d;
}
static void
update_image_size (ClutterImage *self)
{
ClutterImagePrivate *priv = clutter_image_get_instance_private (self);
gint width, height;
if (priv->texture == NULL)
return;
width = cogl_texture_get_width (priv->texture);
height = cogl_texture_get_height (priv->texture);
if (priv->width == width &&
priv->height == height)
return;
priv->width = width;
priv->height = height;
clutter_content_invalidate_size (CLUTTER_CONTENT (self));
}
static void
clutter_image_finalize (GObject *gobject)
{
ClutterImage *image = CLUTTER_IMAGE (gobject);
ClutterImagePrivate *priv = clutter_image_get_instance_private (image);
g_clear_object (&priv->texture);
G_OBJECT_CLASS (clutter_image_parent_class)->finalize (gobject);
}
static void
clutter_image_class_init (ClutterImageClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = clutter_image_finalize;
}
static void
clutter_image_init (ClutterImage *self)
{
}
static void
clutter_image_paint_content (ClutterContent *content,
ClutterActor *actor,
ClutterPaintNode *root,
ClutterPaintContext *paint_context)
{
ClutterImage *image = CLUTTER_IMAGE (content);
ClutterImagePrivate *priv = clutter_image_get_instance_private (image);
ClutterPaintNode *node;
if (priv->texture == NULL)
return;
node = clutter_actor_create_texture_paint_node (actor, priv->texture);
clutter_paint_node_set_static_name (node, "Image Content");
clutter_paint_node_add_child (root, node);
clutter_paint_node_unref (node);
}
static gboolean
clutter_image_get_preferred_size (ClutterContent *content,
gfloat *width,
gfloat *height)
{
ClutterImage *image = CLUTTER_IMAGE (content);
ClutterImagePrivate *priv = clutter_image_get_instance_private (image);
if (priv->texture == NULL)
return FALSE;
if (width != NULL)
*width = cogl_texture_get_width (priv->texture);
if (height != NULL)
*height = cogl_texture_get_height (priv->texture);
return TRUE;
}
static void
clutter_content_iface_init (ClutterContentInterface *iface)
{
iface->get_preferred_size = clutter_image_get_preferred_size;
iface->paint_content = clutter_image_paint_content;
}
/**
* clutter_image_new:
*
* Creates a new #ClutterImage instance.
*
* Return value: (transfer full): the newly created #ClutterImage instance.
* Use g_object_unref() when done.
*/
ClutterContent *
clutter_image_new (void)
{
return g_object_new (CLUTTER_TYPE_IMAGE, NULL);
}
/**
* clutter_image_set_data:
* @image: a #ClutterImage
* @data: (array): the image data, as an array of bytes
* @pixel_format: the Cogl pixel format of the image data
* @width: the width of the image data
* @height: the height of the image data
* @row_stride: the length of each row inside @data
* @error: return location for a #GError, or %NULL
*
* Sets the image data to be displayed by @image.
*
* If the image data was successfully loaded, the @image will be invalidated.
*
* In case of error, the @error value will be set, and this function will
* return %FALSE.
*
* The image data is copied in texture memory.
*
* The image data is expected to be a linear array of RGBA or RGB pixel data;
* how to retrieve that data is left to platform specific image loaders. For
* instance, if you use the GdkPixbuf library:
*
* ```c
* ClutterContent *image = clutter_image_new ();
*
* GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
*
* clutter_image_set_data (CLUTTER_IMAGE (image),
* gdk_pixbuf_get_pixels (pixbuf),
* gdk_pixbuf_get_has_alpha (pixbuf)
* ? COGL_PIXEL_FORMAT_RGBA_8888
* : COGL_PIXEL_FORMAT_RGB_888,
* gdk_pixbuf_get_width (pixbuf),
* gdk_pixbuf_get_height (pixbuf),
* gdk_pixbuf_get_rowstride (pixbuf),
* &error);
*
* g_object_unref (pixbuf);
* ```
*
* Return value: %TRUE if the image data was successfully loaded,
* and %FALSE otherwise.
*/
gboolean
clutter_image_set_data (ClutterImage *image,
const guint8 *data,
CoglPixelFormat pixel_format,
guint width,
guint height,
guint row_stride,
GError **error)
{
ClutterImagePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
g_return_val_if_fail (data != NULL, FALSE);
priv = clutter_image_get_instance_private (image);
if (priv->texture != NULL)
g_object_unref (priv->texture);
priv->texture = create_texture_from_data (width,
height,
pixel_format,
row_stride,
data,
error);
if (priv->texture == NULL)
return FALSE;
clutter_content_invalidate (CLUTTER_CONTENT (image));
update_image_size (image);
return TRUE;
}
/**
* clutter_image_set_bytes:
* @image: a #ClutterImage
* @data: the image data, as a #GBytes
* @pixel_format: the Cogl pixel format of the image data
* @width: the width of the image data
* @height: the height of the image data
* @row_stride: the length of each row inside @data
* @error: return location for a #GError, or %NULL
*
* Sets the image data stored inside a #GBytes to be displayed by @image.
*
* If the image data was successfully loaded, the @image will be invalidated.
*
* In case of error, the @error value will be set, and this function will
* return %FALSE.
*
* The image data contained inside the #GBytes is copied in texture memory,
* and no additional reference is acquired on the @data.
*
* Return value: %TRUE if the image data was successfully loaded,
* and %FALSE otherwise.
*/
gboolean
clutter_image_set_bytes (ClutterImage *image,
GBytes *data,
CoglPixelFormat pixel_format,
guint width,
guint height,
guint row_stride,
GError **error)
{
ClutterImagePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
g_return_val_if_fail (data != NULL, FALSE);
priv = clutter_image_get_instance_private (image);
if (priv->texture != NULL)
g_object_unref (priv->texture);
priv->texture = create_texture_from_data (width,
height,
pixel_format,
row_stride,
g_bytes_get_data (data, NULL),
error);
if (priv->texture == NULL)
return FALSE;
clutter_content_invalidate (CLUTTER_CONTENT (image));
update_image_size (image);
return TRUE;
}
/**
* clutter_image_set_area:
* @image: a #ClutterImage
* @data: (array): the image data, as an array of bytes
* @pixel_format: the Cogl pixel format of the image data
* @rect: a rectangle indicating the area that should be set
* @row_stride: the length of each row inside @data
* @error: return location for a #GError, or %NULL
*
* Sets the image data to be display by @image, using @rect to indicate
* the position and size of the image data to be set.
*
* If the @image does not have any image data set when this function is
* called, a new texture will be created with the size of the width and
* height of the rectangle, i.e. calling this function on a newly created
* #ClutterImage will be the equivalent of calling [method@Clutter.Image.set_data].
*
* If the image data was successfully loaded, the @image will be invalidated.
*
* In case of error, the @error value will be set, and this function will
* return %FALSE.
*
* The image data is copied in texture memory.
*
* Return value: %TRUE if the image data was successfully loaded,
* and %FALSE otherwise.
*/
gboolean
clutter_image_set_area (ClutterImage *image,
const guint8 *data,
CoglPixelFormat pixel_format,
const MtkRectangle *area,
guint row_stride,
GError **error)
{
ClutterImagePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
g_return_val_if_fail (data != NULL, FALSE);
g_return_val_if_fail (area != NULL, FALSE);
priv = clutter_image_get_instance_private (image);
if (priv->texture == NULL)
{
priv->texture = create_texture_from_data (area->width,
area->height,
pixel_format,
row_stride,
data,
error);
}
else
{
gboolean res;
res = cogl_texture_set_region (priv->texture,
0, 0,
area->x, area->y,
area->width, area->height,
area->width, area->height,
pixel_format,
row_stride,
data);
if (!res)
{
g_clear_object (&priv->texture);
}
}
if (priv->texture == NULL)
return FALSE;
clutter_content_invalidate (CLUTTER_CONTENT (image));
update_image_size (image);
return TRUE;
}
/**
* clutter_image_get_texture:
* @image: a #ClutterImage
*
* Retrieves a pointer to the Cogl texture used by @image.
*
* If you change the contents of the returned Cogl texture you will need
* to manually invalidate the @image with [method@Clutter.Content.invalidate]
* in order to update the actors using @image as their content.
*
* Return value: (transfer none): a pointer to the Cogl texture, or %NULL
*/
CoglTexture *
clutter_image_get_texture (ClutterImage *image)
{
ClutterImagePrivate *priv;
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), NULL);
priv = clutter_image_get_instance_private (image);
return priv->texture;
}

View File

@ -1,83 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive image' library.
*
* Copyright (C) 2012 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>
*/
#pragma once
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include "cogl/cogl.h"
#include "clutter/clutter-types.h"
#include "mtk/mtk.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_IMAGE (clutter_image_get_type ())
CLUTTER_EXPORT
G_DECLARE_DERIVABLE_TYPE (ClutterImage, clutter_image, CLUTTER, IMAGE, GObject)
/**
* ClutterImageClass:
*
* The #ClutterImageClass structure contains
* private data.
*/
struct _ClutterImageClass
{
/*< private >*/
GObjectClass parent_class;
};
CLUTTER_EXPORT
ClutterContent * clutter_image_new (void);
CLUTTER_EXPORT
gboolean clutter_image_set_data (ClutterImage *image,
const guint8 *data,
CoglPixelFormat pixel_format,
guint width,
guint height,
guint row_stride,
GError **error);
CLUTTER_EXPORT
gboolean clutter_image_set_area (ClutterImage *image,
const guint8 *data,
CoglPixelFormat pixel_format,
const MtkRectangle *rect,
guint row_stride,
GError **error);
CLUTTER_EXPORT
gboolean clutter_image_set_bytes (ClutterImage *image,
GBytes *data,
CoglPixelFormat pixel_format,
guint width,
guint height,
guint row_stride,
GError **error);
CLUTTER_EXPORT
CoglTexture * clutter_image_get_texture (ClutterImage *image);
G_END_DECLS

View File

@ -66,7 +66,6 @@
#include "clutter/clutter-gesture.h"
#include "clutter/clutter-grab.h"
#include "clutter/clutter-grid-layout.h"
#include "clutter/clutter-image.h"
#include "clutter/clutter-input-device.h"
#include "clutter/clutter-input-device-tool.h"
#include "clutter/clutter-input-method.h"

View File

@ -38,7 +38,6 @@ clutter_headers = [
'clutter-gesture.h',
'clutter-grab.h',
'clutter-grid-layout.h',
'clutter-image.h',
'clutter-input-device.h',
'clutter-input-device-tool.h',
'clutter-input-focus.h',
@ -127,7 +126,6 @@ clutter_sources = [
'clutter-gesture.c',
'clutter-grab.c',
'clutter-grid-layout.c',
'clutter-image.c',
'clutter-input-device.c',
'clutter-input-device-tool.c',
'clutter-input-focus.c',

View File

@ -14,7 +14,6 @@ clutter_tests_interactive_link_args = [
clutter_tests_interactive_test_sources = [
'test-events.c',
'test-actors.c',
'test-grab.c',
'test-cogl-shader-glsl.c',
'test-cogl-tex-tile.c',
@ -26,11 +25,8 @@ clutter_tests_interactive_test_sources = [
'test-stage-sizing.c',
'test-swipe-action.c',
'test-cogl-point-sprites.c',
'test-devices.c',
'test-content.c',
'test-keyframe-transition.c',
'test-rotate-zoom.c',
'test-image.c',
]
gen_test_unit_names = find_program('meson/gen-test-unit-names.sh')

View File

@ -1,260 +0,0 @@
#include <clutter/clutter.h>
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
#include "test-utils.h"
#include "tests/clutter-test-utils.h"
#define NHANDS 6
typedef struct SuperOH
{
ClutterActor **hand;
ClutterActor *bgtex;
ClutterActor *real_hand;
ClutterActor *group;
ClutterActor *stage;
gint stage_width;
gint stage_height;
gfloat radius;
ClutterTimeline *timeline;
} SuperOH;
int
test_actors_main (int argc, char *argv[]);
static void
on_group_destroy (ClutterActor *actor,
SuperOH *oh)
{
oh->group = NULL;
}
static void
on_hand_destroy (ClutterActor *actor,
SuperOH *oh)
{
int i;
for (i = 0; i < NHANDS; i++)
{
if (oh->hand[i] == actor)
oh->hand[i] = NULL;
}
}
static gboolean
on_button_press_event (ClutterActor *actor,
ClutterEvent *event,
SuperOH *oh)
{
gfloat x, y;
clutter_event_get_coords (event, &x, &y);
g_print ("*** button press event (button:%d) at %.2f, %.2f on %s ***\n",
clutter_event_get_button (event),
x, y,
clutter_actor_get_name (actor));
clutter_actor_hide (actor);
return TRUE;
}
static gboolean
input_cb (ClutterActor *stage,
ClutterEvent *event,
gpointer data)
{
SuperOH *oh = data;
if (clutter_event_type (event) == CLUTTER_KEY_RELEASE)
{
g_print ("*** key press event (key:%c) ***\n",
clutter_event_get_key_symbol (event));
if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_q)
{
clutter_test_quit ();
return TRUE;
}
else if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_r)
{
gint i;
for (i = 0; i < NHANDS; i++)
{
if (oh->hand[i] != NULL)
clutter_actor_show (oh->hand[i]);
}
return TRUE;
}
}
return FALSE;
}
/* Timeline handler */
static void
frame_cb (ClutterTimeline *timeline,
gint msecs,
gpointer data)
{
SuperOH *oh = data;
gint i;
float rotation = (float) (clutter_timeline_get_progress (timeline) * 360.0);
/* Rotate everything clockwise about stage center*/
if (oh->group != NULL)
clutter_actor_set_rotation_angle (oh->group, CLUTTER_Z_AXIS, rotation);
for (i = 0; i < NHANDS; i++)
{
/* Rotate each hand around there centers - to get this we need
* to take into account any scaling.
*/
if (oh->hand[i] != NULL)
clutter_actor_set_rotation_angle (oh->hand[i],
CLUTTER_Z_AXIS,
-6.0 * rotation);
}
}
static void
stop_and_quit (ClutterActor *stage,
SuperOH *data)
{
clutter_timeline_stop (data->timeline);
clutter_test_quit ();
}
G_MODULE_EXPORT int
test_actors_main (int argc, char *argv[])
{
SuperOH *oh;
gint i;
GError *error;
ClutterActor *real_hand;
gchar *file;
error = NULL;
clutter_test_init (&argc, &argv);
oh = g_new (SuperOH, 1);
oh->stage = clutter_test_get_stage ();
clutter_actor_set_size (oh->stage, 800, 600);
clutter_actor_set_name (oh->stage, "Default Stage");
clutter_actor_set_background_color (oh->stage, &COGL_COLOR_INIT (114, 159, 207, 255));
g_signal_connect (oh->stage, "destroy", G_CALLBACK (stop_and_quit), oh);
/* Create a timeline to manage animation */
oh->timeline = clutter_timeline_new_for_actor (oh->stage, 6000);
clutter_timeline_set_repeat_count (oh->timeline, -1);
/* fire a callback for frame change */
g_signal_connect (oh->timeline, "new-frame", G_CALLBACK (frame_cb), oh);
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
real_hand = clutter_test_utils_create_texture_from_file (file, &error);
if (real_hand == NULL)
g_error ("image load failed: %s", error->message);
g_free (file);
/* create a new actor to hold other actors */
oh->group = clutter_actor_new ();
clutter_actor_set_pivot_point (oh->group, 0.5, 0.5);
clutter_actor_set_layout_manager (oh->group, clutter_fixed_layout_new ());
clutter_actor_set_name (oh->group, "Group");
g_signal_connect (oh->group, "destroy", G_CALLBACK (on_group_destroy), oh);
clutter_actor_add_constraint (oh->group, clutter_align_constraint_new (oh->stage, CLUTTER_ALIGN_BOTH, 0.5));
clutter_actor_add_constraint (oh->group, clutter_bind_constraint_new (oh->stage, CLUTTER_BIND_SIZE, 0.0f));
oh->hand = g_new (ClutterActor *, NHANDS);
oh->stage_width = (int) clutter_actor_get_width (oh->stage);
oh->stage_height = (int) clutter_actor_get_height (oh->stage);
oh->radius = (oh->stage_width + oh->stage_height) / NHANDS;
for (i = 0; i < NHANDS; i++)
{
gint x, y, w, h;
if (i == 0)
{
oh->hand[i] = real_hand;
clutter_actor_set_name (oh->hand[i], "Real Hand");
}
else
{
oh->hand[i] = clutter_clone_new (real_hand);
clutter_actor_set_name (oh->hand[i], "Clone Hand");
}
clutter_actor_set_reactive (oh->hand[i], TRUE);
clutter_actor_set_size (oh->hand[i], 200, 213);
/* Place around a circle */
w = (int) clutter_actor_get_width (oh->hand[i]);
h = (int) clutter_actor_get_height (oh->hand[i]);
x = (int) (oh->stage_width / 2
+ oh->radius
* cos (i * G_PI / (NHANDS / 2))
- w / 2);
y = (int) (oh->stage_height / 2
+ oh->radius
* sin (i * G_PI / (NHANDS / 2))
- h / 2);
clutter_actor_set_position (oh->hand[i], x, y);
clutter_actor_set_translation (oh->hand[i], -100.f, -106.5, 0);
/* Add to our group group */
clutter_actor_add_child (oh->group, oh->hand[i]);
g_signal_connect (oh->hand[i], "button-press-event",
G_CALLBACK (on_button_press_event),
oh);
g_signal_connect (oh->hand[i], "destroy",
G_CALLBACK (on_hand_destroy),
oh);
}
/* Add the group to the stage */
clutter_actor_add_child (oh->stage, oh->group);
/* Show everying */
clutter_actor_show (oh->stage);
g_signal_connect (oh->stage, "key-release-event", G_CALLBACK (input_cb), oh);
/* and start it */
clutter_timeline_start (oh->timeline);
clutter_test_main ();
clutter_timeline_stop (oh->timeline);
/* clean up */
g_object_unref (oh->timeline);
g_free (oh->hand);
g_free (oh);
return EXIT_SUCCESS;
}

View File

@ -1,233 +0,0 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#include "test-utils.h"
#include "tests/clutter-test-utils.h"
typedef struct {
ClutterActor *stage;
GHashTable *devices;
} TestDevicesApp;
int
test_devices_main (int argc, char **argv);
static const gchar *
device_type_name (ClutterInputDevice *device)
{
ClutterInputDeviceType d_type;
d_type = clutter_input_device_get_device_type (device);
switch (d_type)
{
case CLUTTER_POINTER_DEVICE:
return "Pointer";
case CLUTTER_KEYBOARD_DEVICE:
return "Keyboard";
case CLUTTER_EXTENSION_DEVICE:
return "Extension";
case CLUTTER_PEN_DEVICE:
return "Pen";
case CLUTTER_ERASER_DEVICE:
return "Eraser";
case CLUTTER_CURSOR_DEVICE:
return "Cursor";
default:
return "Unknown";
}
}
static gboolean
stage_button_event_cb (ClutterActor *actor,
ClutterEvent *event,
TestDevicesApp *app)
{
ClutterInputDevice *device;
ClutterInputDevice *source_device;
ClutterActor *hand = NULL;
device = clutter_event_get_device (event);
source_device = clutter_event_get_source_device (event);
hand = g_hash_table_lookup (app->devices, device);
g_print ("Device: '%s' (type: %s, source: '%s')\n",
clutter_input_device_get_device_name (device),
device_type_name (device),
source_device != device
? clutter_input_device_get_device_name (source_device)
: "<same>");
if (hand != NULL)
{
gfloat event_x, event_y;
clutter_event_get_coords (event, &event_x, &event_y);
clutter_actor_set_position (hand, event_x, event_y);
}
return FALSE;
}
static gboolean
stage_motion_event_cb (ClutterActor *actor,
ClutterEvent *event,
TestDevicesApp *app)
{
ClutterInputDevice *device;
ClutterActor *hand = NULL;
device = clutter_event_get_device (event);
hand = g_hash_table_lookup (app->devices, device);
if (hand != NULL)
{
gfloat event_x, event_y;
clutter_event_get_coords (event, &event_x, &event_y);
clutter_actor_set_position (hand, event_x, event_y);
return TRUE;
}
return FALSE;
}
static void
seat_device_added_cb (ClutterSeat *seat,
ClutterInputDevice *device,
TestDevicesApp *app)
{
ClutterInputDeviceType device_type;
ClutterActor *hand = NULL;
g_print ("got a %s device '%s'\n",
device_type_name (device),
clutter_input_device_get_device_name (device));
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{
g_print ("*** enabling device '%s' ***\n",
clutter_input_device_get_device_name (device));
hand = clutter_test_utils_create_texture_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",
NULL);
g_hash_table_insert (app->devices, device, hand);
clutter_actor_add_child (app->stage, hand);
}
}
static void
seat_device_removed_cb (ClutterSeat *seat,
ClutterInputDevice *device,
TestDevicesApp *app)
{
ClutterInputDeviceType device_type;
ClutterActor *hand = NULL;
g_print ("removed a %s device '%s'\n",
device_type_name (device),
clutter_input_device_get_device_name (device));
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{
hand = g_hash_table_lookup (app->devices, device);
if (hand != NULL)
clutter_actor_add_child (app->stage, hand);
g_hash_table_remove (app->devices, device);
}
}
G_MODULE_EXPORT int
test_devices_main (int argc, char **argv)
{
ClutterActor *stage;
TestDevicesApp *app;
ClutterSeat *seat;
GList *stage_devices, *l;
clutter_test_init (&argc, &argv);
app = g_new0 (TestDevicesApp, 1);
app->devices = g_hash_table_new (g_direct_hash, g_direct_equal) ;
stage = clutter_test_get_stage ();
clutter_actor_set_background_color (stage, &COGL_COLOR_INIT (114, 159, 207, 255));
g_signal_connect (stage,
"destroy", G_CALLBACK (clutter_test_quit),
NULL);
g_signal_connect (stage,
"motion-event", G_CALLBACK (stage_motion_event_cb),
app);
g_signal_connect (stage,
"button-press-event", G_CALLBACK (stage_button_event_cb),
app);
app->stage = stage;
clutter_actor_show (stage);
seat = clutter_test_get_default_seat ();
g_signal_connect (seat,
"device-added", G_CALLBACK (seat_device_added_cb),
app);
g_signal_connect (seat,
"device-removed", G_CALLBACK (seat_device_removed_cb),
app);
stage_devices = clutter_seat_list_devices (seat);
if (stage_devices == NULL)
g_error ("No input devices found.");
for (l = stage_devices; l != NULL; l = l->next)
{
ClutterInputDevice *device = l->data;
ClutterInputDeviceType device_type;
ClutterActor *hand = NULL;
g_print ("got a %s device '%s'\n",
device_type_name (device),
clutter_input_device_get_device_name (device));
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{
g_print ("*** enabling device '%s' ***\n",
clutter_input_device_get_device_name (device));
hand = clutter_test_utils_create_texture_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",
NULL);
g_hash_table_insert (app->devices, device, hand);
clutter_actor_add_child (stage, hand);
}
}
g_list_free (stage_devices);
clutter_test_main ();
return EXIT_SUCCESS;
}

View File

@ -1,260 +0,0 @@
#include <stdlib.h>
#include <gmodule.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
#include "tests/clutter-test-utils.h"
typedef struct _SolidContent {
GObject parent_instance;
double red;
double green;
double blue;
double alpha;
float padding;
} SolidContent;
typedef struct _SolidContentClass {
GObjectClass parent_class;
} SolidContentClass;
static void clutter_content_iface_init (ClutterContentInterface *iface);
GType solid_content_get_type (void);
const char *
test_image_describe (void);
int
test_image_main (int argc, char *argv[]);
G_DEFINE_TYPE_WITH_CODE (SolidContent, solid_content, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
clutter_content_iface_init))
static void
solid_content_paint_content (ClutterContent *content,
ClutterActor *actor,
ClutterPaintNode *root,
ClutterPaintContext *paint_context)
{
SolidContent *self = (SolidContent *) content;
ClutterActorBox box, content_box;
CoglColor color;
PangoLayout *layout;
PangoRectangle logical;
ClutterPaintNode *node;
#if 0
g_debug ("Painting content [%p] "
"{ r:%.2f, g:%.2f, b:%.2f, a:%.2f } "
"for actor [%p] (context: [%p])",
content,
self->red,
self->green,
self->blue,
self->alpha,
actor, context);
#endif
clutter_actor_get_content_box (actor, &content_box);
box = content_box;
box.x1 += self->padding;
box.y1 += self->padding;
box.x2 -= self->padding;
box.y2 -= self->padding;
color.alpha = (uint8_t) (self->alpha * 255);
color.red = (uint8_t) (self->red * 255);
color.green = (uint8_t) (self->green * 255);
color.blue = (uint8_t) (self->blue * 255);
node = clutter_color_node_new (&color);
clutter_paint_node_add_rectangle (node, &box);
clutter_paint_node_add_child (root, node);
clutter_paint_node_unref (node);
color.red = (uint8_t) ((1.0 - self->red) * 255);
color.green = (uint8_t) ((1.0 - self->green) * 255);
color.blue = (uint8_t) ((1.0 - self->blue) * 255);
layout = clutter_actor_create_pango_layout (actor, "A");
pango_layout_get_pixel_extents (layout, NULL, &logical);
node = clutter_text_node_new (layout, &color);
/* top-left */
box.x1 = clutter_actor_box_get_x (&content_box);
box.y1 = clutter_actor_box_get_y (&content_box);
box.x2 = box.x1 + logical.width;
box.y2 = box.y1 + logical.height;
clutter_paint_node_add_rectangle (node, &box);
/* top-right */
box.x1 = clutter_actor_box_get_x (&content_box)
+ clutter_actor_box_get_width (&content_box)
- logical.width;
box.y1 = clutter_actor_box_get_y (&content_box);
box.x2 = box.x1 + logical.width;
box.y2 = box.y1 + logical.height;
clutter_paint_node_add_rectangle (node, &box);
/* bottom-right */
box.x1 = clutter_actor_box_get_x (&content_box)
+ clutter_actor_box_get_width (&content_box)
- logical.width;
box.y1 = clutter_actor_box_get_y (&content_box)
+ clutter_actor_box_get_height (&content_box)
- logical.height;
box.x2 = box.x1 + logical.width;
box.y2 = box.y1 + logical.height;
clutter_paint_node_add_rectangle (node, &box);
/* bottom-left */
box.x1 = clutter_actor_box_get_x (&content_box);
box.y1 = clutter_actor_box_get_y (&content_box)
+ clutter_actor_box_get_height (&content_box)
- logical.height;
box.x2 = box.x1 + logical.width;
box.y2 = box.y1 + logical.height;
clutter_paint_node_add_rectangle (node, &box);
/* center */
box.x1 = clutter_actor_box_get_x (&content_box)
+ (clutter_actor_box_get_width (&content_box) - logical.width) / 2.0f;
box.y1 = clutter_actor_box_get_y (&content_box)
+ (clutter_actor_box_get_height (&content_box) - logical.height) / 2.0f;
box.x2 = box.x1 + logical.width;
box.y2 = box.y1 + logical.height;
clutter_paint_node_add_rectangle (node, &box);
clutter_paint_node_add_child (root, node);
clutter_paint_node_unref (node);
g_object_unref (layout);
}
static void
clutter_content_iface_init (ClutterContentInterface *iface)
{
iface->paint_content = solid_content_paint_content;
}
static void
solid_content_class_init (SolidContentClass *klass)
{
}
static void
solid_content_init (SolidContent *self)
{
}
static ClutterContent *
solid_content_new (double red,
double green,
double blue,
double alpha,
float padding)
{
SolidContent *self = g_object_new (solid_content_get_type (), NULL);
self->red = red;
self->green = green;
self->blue = blue;
self->alpha = alpha;
self->padding = padding;
return (ClutterContent *) self;
}
G_MODULE_EXPORT const char *
test_image_describe (void)
{
return "A test with image content.";
}
G_MODULE_EXPORT int
test_image_main (int argc, char *argv[])
{
ClutterActor *stage, *grid;
ClutterContent *color, *image;
GdkPixbuf *pixbuf;
int i, n_rects;
clutter_test_init (&argc, &argv);
stage = clutter_test_get_stage ();
clutter_actor_set_name (stage, "Stage");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_test_quit), NULL);
clutter_actor_show (stage);
grid = clutter_actor_new ();
clutter_actor_set_name (grid, "Grid");
clutter_actor_set_margin_top (grid, 12);
clutter_actor_set_margin_right (grid, 12);
clutter_actor_set_margin_bottom (grid, 12);
clutter_actor_set_margin_left (grid, 12);
clutter_actor_set_layout_manager (grid, clutter_flow_layout_new (CLUTTER_ORIENTATION_HORIZONTAL));
clutter_actor_add_constraint (grid, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0));
clutter_actor_add_child (stage, grid);
color = solid_content_new (g_random_double_range (0.0, 1.0),
g_random_double_range (0.0, 1.0),
g_random_double_range (0.0, 1.0),
1.0,
2.0);
pixbuf = gdk_pixbuf_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL);
image = clutter_image_new ();
clutter_image_set_data (CLUTTER_IMAGE (image),
gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? COGL_PIXEL_FORMAT_RGBA_8888
: COGL_PIXEL_FORMAT_RGB_888,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_rowstride (pixbuf),
NULL);
g_object_unref (pixbuf);
n_rects = g_random_int_range (12, 24);
for (i = 0; i < n_rects; i++)
{
ClutterActor *box = clutter_actor_new ();
CoglColor bg_color = {
g_random_int_range (0, 255),
g_random_int_range (0, 255),
g_random_int_range (0, 255),
255
};
char *name, *str;
str = cogl_color_to_string (&bg_color);
name = g_strconcat ("Box <", color, ">", NULL);
clutter_actor_set_name (box, name);
g_free (name);
g_free (str);
if ((i % 2) == 0)
clutter_actor_set_content (box, color);
else
clutter_actor_set_content (box, image);
clutter_actor_set_size (box, 64, 64);
clutter_actor_add_child (grid, box);
}
clutter_test_main ();
g_object_unref (color);
g_object_unref (image);
return EXIT_SUCCESS;
}

View File

@ -1,675 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <gmodule.h>
#include <cogl/cogl.h>
#include <clutter/clutter.h>
#include "test-utils.h"
#include "tests/clutter-test-utils.h"
/* layout actor, by Lucas Rocha */
#define MY_TYPE_THING (my_thing_get_type ())
#define MY_THING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_THING, MyThing))
#define MY_IS_THING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_THING))
#define MY_THING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_THING, MyThingClass))
#define MY_IS_THING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_THING))
#define MY_THING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MY_TYPE_THING, MyThingClass))
typedef struct _MyThing MyThing;
typedef struct _MyThingPrivate MyThingPrivate;
typedef struct _MyThingClass MyThingClass;
struct _MyThing
{
ClutterActor parent_instance;
MyThingPrivate *priv;
};
struct _MyThingClass
{
ClutterActorClass parent_class;
};
enum
{
PROP_0,
PROP_SPACING,
PROP_PADDING,
PROP_USE_TRANSFORMED_BOX
};
struct _MyThingPrivate
{
gfloat spacing;
gfloat padding;
guint use_transformed_box : 1;
};
GType my_thing_get_type (void);
int
test_layout_main (int argc, char *argv[]);
const char *
test_layout_describe (void);
G_DEFINE_TYPE_WITH_PRIVATE (MyThing, my_thing, CLUTTER_TYPE_ACTOR)
#define MY_THING_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MY_TYPE_THING, MyThingPrivate))
static void
my_thing_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MyThingPrivate *priv = MY_THING (gobject)->priv;
gboolean needs_relayout = TRUE;
switch (prop_id)
{
case PROP_SPACING:
priv->spacing = g_value_get_float (value);
break;
case PROP_PADDING:
priv->padding = g_value_get_float (value);
break;
case PROP_USE_TRANSFORMED_BOX:
priv->use_transformed_box = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
needs_relayout = FALSE;
break;
}
/* setting spacing or padding queues a relayout
because they are supposed to change the internal
allocation of children */
if (needs_relayout)
clutter_actor_queue_relayout (CLUTTER_ACTOR (gobject));
}
static void
my_thing_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MyThingPrivate *priv = MY_THING (gobject)->priv;
switch (prop_id)
{
case PROP_SPACING:
g_value_set_float (value, priv->spacing);
break;
case PROP_PADDING:
g_value_set_float (value, priv->padding);
break;
case PROP_USE_TRANSFORMED_BOX:
g_value_set_boolean (value, priv->use_transformed_box);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
my_thing_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterActorIter iter;
ClutterActor *child;
gfloat min_left, min_right;
gfloat natural_left, natural_right;
min_left = 0;
min_right = 0;
natural_left = 0;
natural_right = 0;
clutter_actor_iter_init (&iter, self);
while (clutter_actor_iter_next (&iter, &child))
{
gfloat child_x, child_min, child_natural;
child_x = clutter_actor_get_x (child);
clutter_actor_get_preferred_size (child,
&child_min, NULL,
&child_natural, NULL);
if (child == clutter_actor_get_first_child (self))
{
/* First child */
min_left = child_x;
natural_left = child_x;
min_right = min_left + child_min;
natural_right = natural_left + child_natural;
}
else
{
/* Union of extents with previous children */
if (child_x < min_left)
min_left = child_x;
if (child_x < natural_left)
natural_left = child_x;
if (child_x + child_min > min_right)
min_right = child_x + child_min;
if (child_x + child_natural > natural_right)
natural_right = child_x + child_natural;
}
}
if (min_left < 0)
min_left = 0;
if (natural_left < 0)
natural_left = 0;
if (min_right < 0)
min_right = 0;
if (natural_right < 0)
natural_right = 0;
g_assert_true (min_right >= min_left);
g_assert_true (natural_right >= natural_left);
if (min_width_p)
*min_width_p = min_right - min_left;
if (natural_width_p)
*natural_width_p = natural_right - min_left;
}
static void
my_thing_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterActorIter iter;
ClutterActor *child;
gfloat min_top, min_bottom;
gfloat natural_top, natural_bottom;
min_top = 0;
min_bottom = 0;
natural_top = 0;
natural_bottom = 0;
clutter_actor_iter_init (&iter, self);
while (clutter_actor_iter_next (&iter, &child))
{
gfloat child_y, child_min, child_natural;
child_y = clutter_actor_get_y (child);
clutter_actor_get_preferred_size (child,
NULL, &child_min,
NULL, &child_natural);
if (child == clutter_actor_get_first_child (self))
{
/* First child */
min_top = child_y;
natural_top = child_y;
min_bottom = min_top + child_min;
natural_bottom = natural_top + child_natural;
}
else
{
/* Union of extents with previous children */
if (child_y < min_top)
min_top = child_y;
if (child_y < natural_top)
natural_top = child_y;
if (child_y + child_min > min_bottom)
min_bottom = child_y + child_min;
if (child_y + child_natural > natural_bottom)
natural_bottom = child_y + child_natural;
}
}
if (min_top < 0)
min_top = 0;
if (natural_top < 0)
natural_top = 0;
if (min_bottom < 0)
min_bottom = 0;
if (natural_bottom < 0)
natural_bottom = 0;
g_assert_true (min_bottom >= min_top);
g_assert_true (natural_bottom >= natural_top);
if (min_height_p)
*min_height_p = min_bottom - min_top;
if (natural_height_p)
*natural_height_p = natural_bottom - min_top;
}
static void
my_thing_allocate (ClutterActor *self,
const ClutterActorBox *box)
{
MyThingPrivate *priv;
gfloat current_x, current_y, max_row_height;
ClutterActorIter iter;
ClutterActor *child;
clutter_actor_set_allocation (self, box);
priv = MY_THING (self)->priv;
current_x = priv->padding;
current_y = priv->padding;
max_row_height = 0;
/* The allocation logic here is to horizontally place children
* side-by-side and reflow into a new row when we run out of
* space
*/
clutter_actor_iter_init (&iter, self);
while (clutter_actor_iter_next (&iter, &child))
{
gfloat natural_width, natural_height;
ClutterActorBox child_box;
clutter_actor_get_preferred_size (child,
NULL, NULL,
&natural_width,
&natural_height);
/* if it fits in the current row, keep it there; otherwise
* reflow into another row
*/
if (current_x + natural_width > box->x2 - box->x1 - priv->padding)
{
current_x = priv->padding;
current_y += max_row_height + priv->spacing;
max_row_height = 0;
}
child_box.x1 = current_x;
child_box.y1 = current_y;
child_box.x2 = child_box.x1 + natural_width;
child_box.y2 = child_box.y1 + natural_height;
clutter_actor_allocate (child, &child_box);
/* if we take into account the transformation of the children
* then we first check if it's transformed; then we get the
* onscreen coordinates of the two points of the bounding box
* of the actor (origin(x, y) and (origin + size)(x,y)) and
* we update the coordinates and area given to the next child
*/
if (priv->use_transformed_box)
{
if (clutter_actor_is_scaled (child) ||
clutter_actor_is_rotated (child))
{
graphene_point3d_t v1 = { 0, }, v2 = { 0, };
ClutterActorBox transformed_box = { 0, };
v1.x = box->x1;
v1.y = box->y1;
clutter_actor_apply_transform_to_point (child, &v1, &v2);
transformed_box.x1 = v2.x;
transformed_box.y1 = v2.y;
/* size */
v1.x = natural_width;
v1.y = natural_height;
clutter_actor_apply_transform_to_point (child, &v1, &v2);
transformed_box.x2 = v2.x;
transformed_box.y2 = v2.y;
natural_width = transformed_box.x2 - transformed_box.x1;
natural_height = transformed_box.y2 - transformed_box.y1;
}
}
/* Record the maximum child height on current row to know
* what's the increment that should be used for the next
* row
*/
if (natural_height > max_row_height)
max_row_height = natural_height;
current_x += natural_width + priv->spacing;
}
}
#define MIN_SIZE 24
#define MAX_SIZE 64
static void
my_thing_class_init (MyThingClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->set_property = my_thing_set_property;
gobject_class->get_property = my_thing_get_property;
actor_class->get_preferred_width = my_thing_get_preferred_width;
actor_class->get_preferred_height = my_thing_get_preferred_height;
actor_class->allocate = my_thing_allocate;
g_object_class_install_property (gobject_class,
PROP_SPACING,
g_param_spec_float ("spacing", NULL, NULL,
0, G_MAXFLOAT,
0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_PADDING,
g_param_spec_float ("padding", NULL, NULL,
0, G_MAXFLOAT,
0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_USE_TRANSFORMED_BOX,
g_param_spec_boolean ("use-transformed-box", NULL, NULL,
FALSE,
G_PARAM_READWRITE));
}
static void
my_thing_init (MyThing *thing)
{
thing->priv = MY_THING_GET_PRIVATE (thing);
}
static ClutterActor *
my_thing_new (gfloat padding,
gfloat spacing)
{
return g_object_new (MY_TYPE_THING,
"padding", padding,
"spacing", spacing,
NULL);
}
/* test code */
static ClutterActor *box = NULL;
static ClutterActor *icon = NULL;
static ClutterTimeline *main_timeline = NULL;
static void
toggle_property_value (ClutterActor *actor,
const gchar *property_name)
{
gboolean value;
g_object_get (actor, property_name, &value, NULL);
value = !value;
g_object_set (box, property_name, value, NULL);
}
static void
increase_property_value (ClutterActor *actor,
const char *property_name)
{
gfloat value;
g_object_get (actor, property_name, &value, NULL);
value = value + 10.0;
g_object_set (box, property_name, value, NULL);
}
static void
decrease_property_value (ClutterActor *actor,
const char *property_name)
{
gfloat value;
g_object_get (actor, property_name, &value, NULL);
value = MAX (0, value - 10.0);
g_object_set (box, property_name, value, NULL);
}
static ClutterActor *
create_item (void)
{
ClutterActor *clone = clutter_clone_new (icon);
gint32 size = g_random_int_range (MIN_SIZE, MAX_SIZE);
clutter_actor_set_size (clone, size, size);
clutter_actor_animate_with_timeline (clone, CLUTTER_EASE_OUT_CUBIC,
main_timeline,
"scale-x", 2.0,
"scale-y", 2.0,
NULL);
return clone;
}
static gboolean
keypress_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
switch (clutter_event_get_key_symbol (event))
{
case CLUTTER_KEY_q:
clutter_test_quit ();
break;
case CLUTTER_KEY_a:
{
if (icon != NULL)
{
ClutterActor *clone = create_item ();
/* Add one item to container */
clutter_actor_add_child (box, clone);
}
break;
}
case CLUTTER_KEY_d:
{
ClutterActor *last_child;
last_child = clutter_actor_get_last_child (box);
if (last_child != NULL)
{
/* Remove last item on container */
clutter_actor_remove_child (box, last_child);
}
break;
}
case CLUTTER_KEY_w:
{
decrease_property_value (box, "padding");
break;
}
case CLUTTER_KEY_e:
{
increase_property_value (box, "padding");
break;
}
case CLUTTER_KEY_r:
{
decrease_property_value (box, "spacing");
break;
}
case CLUTTER_KEY_s:
{
toggle_property_value (box, "use-transformed-box");
break;
}
case CLUTTER_KEY_t:
{
increase_property_value (box, "spacing");
break;
}
case CLUTTER_KEY_z:
{
if (clutter_timeline_is_playing (main_timeline))
clutter_timeline_pause (main_timeline);
else
clutter_timeline_start (main_timeline);
break;
}
default:
break;
}
return FALSE;
}
static void
relayout_on_frame (ClutterTimeline *timeline)
{
gboolean use_transformed_box;
/* if we care about transformations updating the layout, we need to inform
* the layout that a transformation is happening; this is either done by
* attaching a notification on the transformation properties or by simply
* queuing a relayout on each frame of the timeline used to drive the
* behaviour. for simplicity's sake, we used the latter
*/
g_object_get (G_OBJECT (box),
"use-transformed-box", &use_transformed_box,
NULL);
if (use_transformed_box)
clutter_actor_queue_relayout (box);
}
G_MODULE_EXPORT int
test_layout_main (int argc, char *argv[])
{
ClutterActor *stage, *instructions;
gint i, size;
GError *error = NULL;
clutter_test_init (&argc, &argv);
stage = clutter_test_get_stage ();
clutter_actor_set_size (stage, 800, 600);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_test_quit), NULL);
main_timeline = clutter_timeline_new_for_actor (stage, 2000);
clutter_timeline_set_repeat_count (main_timeline, -1);
clutter_timeline_set_auto_reverse (main_timeline, TRUE);
g_signal_connect (main_timeline, "new-frame",
G_CALLBACK (relayout_on_frame),
NULL);
box = my_thing_new (10, 10);
clutter_actor_set_position (box, 20, 20);
clutter_actor_set_size (box, 350, -1);
icon = clutter_test_utils_create_texture_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",
&error);
if (error)
g_error ("Unable to load 'redhand.png': %s", error->message);
size = g_random_int_range (MIN_SIZE, MAX_SIZE);
clutter_actor_set_size (icon, size, size);
clutter_actor_add_child (box, icon);
clutter_actor_animate_with_timeline (icon, CLUTTER_EASE_OUT_CUBIC,
main_timeline,
"scale-x", 2.0,
"scale-y", 2.0,
NULL);
for (i = 1; i < 33; i++)
{
ClutterActor *clone = create_item ();
clutter_actor_add_child (box, clone);
}
clutter_actor_add_child (stage, box);
instructions = clutter_text_new_with_text (NULL,
"<b>Instructions:</b>\n"
"a - add a new item\n"
"d - remove last item\n"
"z - start/pause behaviour\n"
"w - decrease padding\n"
"e - increase padding\n"
"r - decrease spacing\n"
"t - increase spacing\n"
"s - use transformed box\n"
"q - quit");
clutter_text_set_use_markup (CLUTTER_TEXT (instructions), TRUE);
clutter_actor_set_position (instructions, 450, 10);
clutter_actor_add_child (stage, instructions);
g_signal_connect (stage, "key-release-event",
G_CALLBACK (keypress_cb),
NULL);
clutter_timeline_stop (main_timeline);
clutter_actor_show (stage);
clutter_test_main ();
g_object_unref (main_timeline);
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_layout_describe (void)
{
return "Container implementing a layout policy.";
}

View File

@ -1,96 +0,0 @@
/*
* Copyright (C) 2013 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <math.h>
#include <glib.h>
#include <clutter/clutter.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "tests/clutter-test-utils.h"
#define STAGE_WIDTH 800
#define STAGE_HEIGHT 550
int
test_rotate_zoom_main (int argc, char *argv[]);
const char *
test_rotate_zoom_describe (void);
static ClutterActor *
create_hand (void)
{
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL);
ClutterContent *image = clutter_image_new ();
ClutterActor *actor = clutter_actor_new ();
clutter_image_set_data (CLUTTER_IMAGE (image),
gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? COGL_PIXEL_FORMAT_RGBA_8888
: COGL_PIXEL_FORMAT_RGB_888,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_rowstride (pixbuf),
NULL);
clutter_actor_set_content (actor, image);
clutter_actor_set_size (actor,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf));
clutter_actor_set_reactive (actor, TRUE);
g_object_unref (pixbuf);
return actor;
}
G_MODULE_EXPORT int
test_rotate_zoom_main (int argc, char *argv[])
{
ClutterActor *stage, *actor;
gfloat width, height;
/* initialize Clutter */
clutter_test_init (&argc, &argv);
/* create a resizable stage */
stage = clutter_test_get_stage ();
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_test_quit), NULL);
clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT);
clutter_actor_set_reactive (stage, FALSE);
clutter_actor_show (stage);
actor = create_hand ();
clutter_actor_add_action (actor, clutter_rotate_action_new ());
clutter_actor_add_action (actor, clutter_zoom_action_new ());
clutter_actor_add_child (stage, actor);
clutter_actor_get_size (actor, &width, &height);
clutter_actor_set_position (actor,
STAGE_WIDTH / 2 - width / 2,
STAGE_HEIGHT / 2 - height / 2);
clutter_test_main ();
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_rotate_zoom_describe (void)
{
return "Rotates and zooms an actor using touch events";
}

View File

@ -1,89 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#include "test-utils.h"
#include "tests/clutter-test-utils.h"
int
test_shader_effects_main (int argc, char *argv[]);
G_MODULE_EXPORT int
test_shader_effects_main (int argc, char *argv[])
{
ClutterTimeline *timeline;
ClutterActor *stage, *hand, *label, *rect;
gchar *file;
clutter_test_init (&argc, &argv);
stage = clutter_test_get_stage ();
clutter_actor_set_background_color (stage, &COGL_COLOR_INIT (186, 189, 182, 255));
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_test_quit), NULL);
/* Make a timeline */
timeline = clutter_timeline_new_for_actor (stage, 7692);
clutter_timeline_set_repeat_count (timeline, -1);
/* Make a hand */
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
hand = clutter_test_utils_create_texture_from_file (file, NULL);
if (!hand)
g_error("Unable to load '%s'", file);
g_free (file);
clutter_actor_set_position (hand, 326, 265);
clutter_actor_add_effect_with_name (hand, "desaturate", clutter_desaturate_effect_new (0.75));
clutter_actor_add_effect_with_name (hand, "blur", clutter_blur_effect_new ());
clutter_actor_animate_with_timeline (hand, CLUTTER_LINEAR, timeline,
"@effects.desaturate.factor", 1.0,
"rotation-angle-z", 360.0,
"fixed::anchor-x", 86.0,
"fixed::anchor-y", 125.0,
"opacity", 128,
NULL);
rect = clutter_actor_new ();
clutter_actor_set_background_color (rect, &COGL_COLOR_INIT (206, 92, 0, 255));
clutter_actor_add_effect_with_name (rect, "blur", clutter_blur_effect_new ());
clutter_actor_set_position (rect, 415, 215);
clutter_actor_set_size (rect, 150, 150);
clutter_actor_animate_with_timeline (rect, CLUTTER_LINEAR, timeline,
"rotation-angle-z", 360.0,
"fixed::anchor-x", 75.0,
"fixed::anchor-y", 75.0,
NULL);
label = clutter_text_new_with_text ("Mono 16",
"The Wonder\n"
"of the\n"
"Spinning Hand");
clutter_text_set_line_alignment (CLUTTER_TEXT (label), PANGO_ALIGN_CENTER);
clutter_actor_set_position (label, 336, 275);
clutter_actor_set_size (label, 500, 100);
clutter_actor_animate_with_timeline (label, CLUTTER_LINEAR, timeline,
"rotation-angle-z", 360.0,
"fixed::anchor-x", 86.0,
"fixed::anchor-y", 125.0,
NULL);
clutter_actor_add_child (stage, rect);
clutter_actor_add_child (stage, hand);
clutter_actor_add_child (stage, label);
/* start the timeline and thus the animations */
clutter_timeline_start (timeline);
clutter_actor_show (stage);
clutter_test_main ();
g_object_unref (timeline);
return 0;
}

View File

@ -3,34 +3,6 @@
static GQuark pixbuf_key = 0;
static inline ClutterActor *
clutter_test_utils_create_texture_from_file (const char *filename,
GError **error)
{
g_autoptr (ClutterContent) image = NULL;
g_autoptr (GdkPixbuf) pixbuf = NULL;
pixbuf = gdk_pixbuf_new_from_file (filename, error);
if (!pixbuf)
return NULL;
image = clutter_image_new ();
if (!clutter_image_set_data (CLUTTER_IMAGE (image),
gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? COGL_PIXEL_FORMAT_RGBA_8888
: COGL_PIXEL_FORMAT_RGB_888,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_rowstride (pixbuf),
error))
return NULL;
return g_object_new (CLUTTER_TYPE_ACTOR,
"content", image,
NULL);
}
static inline CoglBitmap *
clutter_test_create_bitmap_from_file (CoglContext *ctx,
const char *filename,