clutter: Move tests to src/tests

Clutter doesn't hold anymore backend implementations, move tests where
we have one that we may assign.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/672
This commit is contained in:
Carlos Garnacho
2019-07-03 11:51:45 +02:00
committed by Jonas Ådahl
parent c0a71720af
commit cfb8f18cef
133 changed files with 4 additions and 3 deletions

38
src/tests/clutter/README Normal file
View File

@ -0,0 +1,38 @@
Outline of test categories:
The conform/ tests should be non-interactive unit-tests that verify a single
feature is behaving as documented. Use the GLib and Clutter test API and macros
to write the test units. The conformance test suites are meant to be used with
continuous integration builds.
The performance/ tests are performance tests, both focused tests testing single
metrics and larger tests. These tests are used to report one or more
performance markers for the build of Clutter. Each performance marker is picked
up from the standard output of running the tests from strings having the form
"\n@ marker-name: 42.23" where 'marker-name' and '42.23' are the key/value pairs
of a single metric. Each test can provide multiple key/value pairs. Note that
if framerate is the feedback metric the test should forcibly enable FPS
debugging itself. The file test-common.h contains utility function helping to
do fps reporting.
The interactive/ tests are any tests whose status can not be determined without
a user looking at some visual output, or providing some manual input etc. This
covers most of the original Clutter tests. Ideally some of these tests will be
migrated into the conform/ directory.
The accessibility/ tests are tests created to test the accessibility support of
clutter, testing some of the atk interfaces.
Other notes:
• All tests should ideally include a detailed description in the source
explaining exactly what the test is for, how the test was designed to work,
and possibly a rationale for the approach taken for testing. Tests for specific
bugs should reference the bug report URL or number.
• When running tests under Valgrind, you should follow the instructions
available here:
https://wiki.gnome.org/Valgrind
and also use the suppression file available in the Git repository.

View File

@ -0,0 +1,5 @@
/cally-atkcomponent-example
/cally-atkeditabletext-example
/cally-atkevents-example
/cally-atktext-example
/cally-clone-example

View File

@ -0,0 +1,94 @@
/* 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.
*/
#include <clutter/clutter.h>
#include "cally-examples-util.h"
#define WIDTH 300
#define HEIGHT 300
#define SIZE 50
#define DEPTH -100
int
main (int argc, char *argv[])
{
ClutterActor *stage = NULL;
ClutterActor *button1 = NULL;
ClutterActor *button2 = NULL;
ClutterActor *button3 = NULL;
ClutterActor *button4 = NULL;
ClutterActor *group[4];
int i = 0;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
cally_util_a11y_init (&argc, &argv);
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - AtkComponent Test");
clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_White);
clutter_actor_set_size (stage, WIDTH, HEIGHT);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
button1 = clutter_rectangle_new_with_color (CLUTTER_COLOR_Yellow);
clutter_actor_set_size (button1, SIZE, SIZE);
button2 = clutter_rectangle_new_with_color (CLUTTER_COLOR_Green);
clutter_actor_set_position (button2, 2 * SIZE, 0);
clutter_actor_set_size (button2, SIZE, SIZE);
button3 = clutter_rectangle_new_with_color (CLUTTER_COLOR_Blue);
clutter_actor_set_position (button3, 0, 2 * SIZE);
clutter_actor_set_size (button3, SIZE, SIZE);
clutter_actor_set_depth( button3, DEPTH);
/* a nested hierarchy, to check that the relative positions are
computed properly */
button4 = clutter_rectangle_new_with_color (CLUTTER_COLOR_Magenta);
clutter_actor_set_position (button4, SIZE / 2, SIZE / 2);
clutter_actor_set_size (button4, SIZE, SIZE);
for (i = 0; i < 4; i++) {
group[i] = clutter_group_new ();
clutter_actor_set_position (group[i], SIZE / 2, SIZE / 2);
clutter_actor_set_size (group[i], SIZE, SIZE);
if (i > 0)
clutter_container_add_actor (CLUTTER_CONTAINER (group[i]), group [i - 1]);
}
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button1);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button2);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button3);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group[3]);
clutter_container_add_actor (CLUTTER_CONTAINER (group[0]), button4);
clutter_actor_show (stage);
clutter_main ();
return 0;
}

View File

@ -0,0 +1,268 @@
/* 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.
*/
#include <atk/atk.h>
#include <clutter/clutter.h>
#include "cally-examples-util.h"
#define WIDTH 800
#define HEIGHT 600
static ClutterActor *text_actor = NULL;
static ClutterActor *text_editable_actor = NULL;
/*
* Test AtkText interface
*/
static void
test_atk_text (ClutterActor *actor)
{
AtkObject *object = NULL;
AtkEditableText *cally_editable_text = NULL;
gint pos = 0;
object = atk_gobject_accessible_for_object (G_OBJECT (actor));
cally_editable_text = ATK_EDITABLE_TEXT (object);
if (cally_editable_text != NULL) {
atk_editable_text_set_text_contents (cally_editable_text, "New text");
atk_editable_text_delete_text (cally_editable_text, 0, 3);
pos = 3;
atk_editable_text_insert_text (cally_editable_text, "New", 0, &pos);
/* Not implemented in cally, just checking that we can call this
functions */
atk_editable_text_copy_text (cally_editable_text, 0, -1);
atk_editable_text_paste_text (cally_editable_text, 5);
atk_editable_text_cut_text (cally_editable_text, 0, -1);
}
}
static gboolean
insert_text_press_cb (ClutterActor *actor,
ClutterButtonEvent *event,
gpointer data)
{
AtkObject *object = NULL;
AtkEditableText *cally_editable_text = NULL;
gint pos = 0;
object = atk_gobject_accessible_for_object (G_OBJECT (text_editable_actor));
cally_editable_text = ATK_EDITABLE_TEXT (object);
pos = 3;
atk_editable_text_insert_text (cally_editable_text, "New", 0, &pos);
return TRUE;
}
static gboolean
delete_text_press_cb (ClutterActor *actor,
ClutterButtonEvent *event,
gpointer data)
{
AtkObject *object = NULL;
AtkEditableText *cally_editable_text = NULL;
object = atk_gobject_accessible_for_object (G_OBJECT (text_editable_actor));
cally_editable_text = ATK_EDITABLE_TEXT (object);
atk_editable_text_delete_text (cally_editable_text, 0, 3);
return TRUE;
}
static gboolean
set_text_press_cb (ClutterActor *actor,
ClutterButtonEvent *event,
gpointer data)
{
AtkObject *object = NULL;
AtkEditableText *cally_editable_text = NULL;
object = atk_gobject_accessible_for_object (G_OBJECT (text_editable_actor));
cally_editable_text = ATK_EDITABLE_TEXT (object);
atk_editable_text_set_text_contents (cally_editable_text, "New text");
return TRUE;
}
static gboolean
activate_deactivate_press_cb (ClutterActor *actor,
ClutterButtonEvent *event,
gpointer data)
{
gboolean active = FALSE;
active = clutter_text_get_activatable (CLUTTER_TEXT (text_editable_actor));
clutter_text_set_activatable (CLUTTER_TEXT (text_editable_actor), !active);
return TRUE;
}
static gboolean
print_cursor_position_press_cb (ClutterActor *actor,
ClutterButtonEvent *event,
gpointer data)
{
gint pos = 0;
pos = clutter_text_get_cursor_position (CLUTTER_TEXT (text_editable_actor));
g_print ("current cursor position %i\n", pos);
return TRUE;
}
static void
activate_cb (ClutterActor *actor,
gpointer data)
{
g_print ("Actor activated\n");
}
static ClutterActor*
_create_button (const gchar *text)
{
ClutterActor *button = NULL;
ClutterActor *rectangle = NULL;
ClutterActor *label = NULL;
button = clutter_group_new ();
rectangle = clutter_rectangle_new_with_color (CLUTTER_COLOR_Magenta);
clutter_actor_set_size (rectangle, 375, 35);
label = clutter_text_new_full ("Sans Bold 32px",
text,
CLUTTER_COLOR_Black);
clutter_container_add_actor (CLUTTER_CONTAINER (button), rectangle);
clutter_container_add_actor (CLUTTER_CONTAINER (button), label);
clutter_actor_set_reactive (button, TRUE);
return button;
}
static void
make_ui (ClutterActor *stage)
{
ClutterActor *button = NULL;
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - AtkEditable Test");
clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_White);
clutter_actor_set_size (stage, WIDTH, HEIGHT);
/* text */
text_actor = clutter_text_new_full ("Sans Bold 32px",
"Lorem ipsum dolor sit amet",
CLUTTER_COLOR_Red);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), text_actor);
/* text_editable */
text_editable_actor = clutter_text_new_full ("Sans Bold 32px",
"consectetur adipisicing elit",
CLUTTER_COLOR_Red);
clutter_actor_set_position (text_editable_actor, 0, 100);
clutter_text_set_editable (CLUTTER_TEXT (text_editable_actor), TRUE);
clutter_text_set_selectable (CLUTTER_TEXT (text_editable_actor), TRUE);
clutter_text_set_selection_color (CLUTTER_TEXT (text_editable_actor),
CLUTTER_COLOR_Green);
clutter_text_set_activatable (CLUTTER_TEXT (text_editable_actor),
TRUE);
clutter_text_set_line_wrap (CLUTTER_TEXT (text_editable_actor), TRUE);
clutter_actor_grab_key_focus (text_editable_actor);
clutter_actor_set_reactive (text_editable_actor, TRUE);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), text_editable_actor);
g_signal_connect (text_editable_actor, "activate",
G_CALLBACK (activate_cb), NULL);
/* test buttons */
button = _create_button ("Set");
clutter_actor_set_position (button, 100, 200);
g_signal_connect_after (button, "button-press-event",
G_CALLBACK (set_text_press_cb), NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
button = _create_button ("Delete");
clutter_actor_set_position (button, 100, 250);
g_signal_connect_after (button, "button-press-event",
G_CALLBACK (delete_text_press_cb), NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
button = _create_button ("Insert");
clutter_actor_set_position (button, 100, 300);
g_signal_connect_after (button, "button-press-event",
G_CALLBACK (insert_text_press_cb), NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
button = _create_button ("Activate/Deactivate");
clutter_actor_set_position (button, 100, 350);
g_signal_connect_after (button, "button-press-event",
G_CALLBACK (activate_deactivate_press_cb), NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
button = _create_button ("Cursor position");
clutter_actor_set_position (button, 100, 450);
g_signal_connect_after (button, "button-press-event",
G_CALLBACK (print_cursor_position_press_cb), NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
}
int
main (int argc, char *argv[])
{
ClutterActor *stage = NULL;
g_set_application_name ("AtkEditableText");
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
cally_util_a11y_init (&argc, &argv);
stage = clutter_stage_new ();
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
make_ui (stage);
clutter_actor_show_all (stage);
test_atk_text (text_actor);
test_atk_text (text_editable_actor);
clutter_main ();
return 0;
}

View File

@ -0,0 +1,196 @@
/* 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.
*/
/*
* The purpose of this example is test key event and global event
* implementation, specifically:
*
* atk_add_global_event_listener
* atk_remove_global_event_listener
* atk_add_key_event_listener
* atk_remove_key_event_listener
*/
#include <atk/atk.h>
#include <clutter/clutter.h>
#include <cally/cally.h>
#include "cally-examples-util.h"
#define WIDTH 800
#define HEIGHT 600
#define HEIGHT_STEP 100
#define NUM_ENTRIES 3
struct _Data{
gint value;
};
typedef struct _Data Data;
static gboolean
atk_key_listener (AtkKeyEventStruct *event, gpointer data)
{
Data *my_data = (Data*) data;
g_print ("atk_listener: 0x%x ", event->keyval);
if (my_data != NULL) {
g_print ("\t Data value: %i\n", my_data->value);
} else {
g_print ("\tNo data!!\n");
}
return FALSE;
}
static gboolean
window_event_listener (GSignalInvocationHint * signal_hint,
guint n_param_values,
const GValue * param_values, gpointer data)
{
AtkObject *accessible;
GSignalQuery signal_query;
const gchar *name, *s;
g_signal_query (signal_hint->signal_id, &signal_query);
name = signal_query.signal_name;
accessible = ATK_OBJECT (g_value_get_object (&param_values[0]));
s = atk_object_get_name (accessible);
g_print ("Detected window event \"%s\" from object \"%p\" named \"%s\"\n",
name, accessible, s);
return TRUE;
}
static void
make_ui (ClutterActor *stage)
{
gint i = 0;
ClutterActor *editable = NULL;
ClutterActor *rectangle = NULL;
ClutterActor *label = NULL;
ClutterColor color_sel = { 0x00, 0xff, 0x00, 0x55 };
ClutterColor color_label = { 0x00, 0xff, 0x55, 0xff };
ClutterColor color_rect = { 0x00, 0xff, 0xff, 0x55 };
float label_geom_y, editable_geom_y;
clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_White);
clutter_actor_set_size (stage, WIDTH, HEIGHT);
label_geom_y = 50;
editable_geom_y = 50;
for (i = 0; i < NUM_ENTRIES; i++)
{
/* label */
label = clutter_text_new_full ("Sans Bold 32px",
"Entry",
&color_label);
clutter_actor_set_position (label, 0, label_geom_y);
/* editable */
editable = clutter_text_new_full ("Sans Bold 32px",
"ddd",
CLUTTER_COLOR_Red);
clutter_actor_set_position (editable, 150, editable_geom_y);
clutter_actor_set_size (editable, 500, 75);
clutter_text_set_editable (CLUTTER_TEXT (editable), TRUE);
clutter_text_set_selectable (CLUTTER_TEXT (editable), TRUE);
clutter_text_set_selection_color (CLUTTER_TEXT (editable),
&color_sel);
clutter_actor_grab_key_focus (editable);
clutter_actor_set_reactive (editable, TRUE);
/* rectangle: to create a entry "feeling" */
rectangle = clutter_rectangle_new_with_color (&color_rect);
clutter_actor_set_position (rectangle, 150, editable_geom_y);
clutter_actor_set_size (rectangle, 500, 75);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), label);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), editable);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle);
label_geom_y += HEIGHT_STEP;
editable_geom_y += HEIGHT_STEP;
}
}
int
main (int argc, char *argv[])
{
ClutterActor *stage, *stage_main;
Data data1, data2, data3;
guint id_1 = 0, id_2 = 0, id_3 = 0;
g_set_application_name ("AtkText");
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
if (cally_util_a11y_init (&argc, &argv) == FALSE)
{
g_error ("This example requires the accessibility support, "
"especifically AtkUtil implementation loaded, "
"as it tries to register and remove event listeners");
}
data1.value = 10;
data2.value = 20;
data3.value = 30;
/* key event listeners */
id_1 = atk_add_key_event_listener ((AtkKeySnoopFunc)atk_key_listener, &data1);
atk_remove_key_event_listener (id_1);
id_2 = atk_add_key_event_listener ((AtkKeySnoopFunc)atk_key_listener, &data2);
id_3 = atk_add_key_event_listener ((AtkKeySnoopFunc)atk_key_listener, &data3);
atk_remove_key_event_listener (id_2);
g_print ("key event listener ids registered: (%i, %i, %i)\n", id_1, id_2, id_3);
/* event listeners */
atk_add_global_event_listener (window_event_listener, "Atk:AtkWindow:create");
atk_add_global_event_listener (window_event_listener, "Atk:AtkWindow:destroy");
atk_add_global_event_listener (window_event_listener, "Atk:AtkWindow:activate");
atk_add_global_event_listener (window_event_listener, "Atk:AtkWindow:deactivate");
stage_main = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage_main), "Cally - AtkEvents/1");
g_signal_connect (stage_main, "destroy", G_CALLBACK (clutter_main_quit), NULL);
make_ui (stage_main);
clutter_actor_show_all (stage_main);
if (clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
{
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - AtkEvents/2");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
make_ui (stage);
clutter_actor_show_all (stage);
}
clutter_main ();
return 0;
}

View File

@ -0,0 +1,255 @@
/* 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.
*/
#include <atk/atk.h>
#include <clutter/clutter.h>
#include "cally-examples-util.h"
#define WIDTH 800
#define HEIGHT 600
static ClutterActor *text_actor = NULL;
static ClutterActor *text_editable_actor = NULL;
/*
* Test AtkText interface
*/
static void
test_atk_text (ClutterActor *actor)
{
gchar *text = NULL;
AtkObject *object = NULL;
AtkText *cally_text = NULL;
gboolean bool = FALSE;
gunichar unichar;
gint count = -1;
gint start = -1;
gint end = -1;
gint pos = -1;
AtkAttributeSet *at_set = NULL;
GSList *attrs;
gchar *buf;
gint x, y, width, height;
object = atk_gobject_accessible_for_object (G_OBJECT (actor));
cally_text = ATK_TEXT (object);
if (!cally_text)
return;
text = atk_text_get_text (cally_text, 0, -1);
g_print ("atk_text_get_text output: %s\n", text);
unichar = atk_text_get_character_at_offset (cally_text, 5);
buf = g_ucs4_to_utf8 (&unichar, 1, NULL, NULL, NULL);
g_print ("atk_text_get_character_at_offset(5): '%s' vs '%c'\n", buf, text[5]);
g_free (text); text = NULL;
g_free (buf); buf = NULL;
text = atk_text_get_string_at_offset (cally_text,
5,
ATK_TEXT_GRANULARITY_WORD,
&start, &end);
g_print ("atk_text_get_string_at_offset: %s, %i, %i\n",
text, start, end);
g_free (text); text = NULL;
pos = atk_text_get_caret_offset (cally_text);
g_print ("atk_text_get_caret_offset: %i\n", pos);
atk_text_set_caret_offset (cally_text, 5);
count = atk_text_get_character_count (cally_text);
g_print ("atk_text_get_character_count: %i\n", count);
count = atk_text_get_n_selections (cally_text);
g_print ("atk_text_get_n_selections: %i\n", count);
text = atk_text_get_selection (cally_text, 0, &start, &end);
g_print ("atk_text_get_selection: %s, %i, %i\n", text, start, end);
g_free(text); text = NULL;
bool = atk_text_remove_selection (cally_text, 0);
g_print ("atk_text_remove_selection (0): %i\n", bool);
bool = atk_text_remove_selection (cally_text, 1);
g_print ("atk_text_remove_selection (1): %i\n", bool);
bool = atk_text_add_selection (cally_text, 5, 10);
g_print ("atk_text_add_selection: %i\n", bool);
bool = atk_text_set_selection (cally_text, 0, 6, 10);
g_print ("atk_text_set_selection: %i\n", bool);
at_set = atk_text_get_run_attributes (cally_text, 0,
&start, &end);
g_print ("atk_text_get_run_attributes: %i, %i\n", start, end);
attrs = (GSList*) at_set;
while (attrs)
{
AtkAttribute *at = (AtkAttribute *) attrs->data;
g_print ("text run %s = %s\n", at->name, at->value);
attrs = g_slist_next (attrs);
}
atk_text_get_character_extents (cally_text, 0, &x, &y, &width, &height,
ATK_XY_WINDOW);
g_print ("atk_text_get_character_extents (0, window): x=%i y=%i width=%i height=%i\n",
x, y, width, height);
atk_text_get_character_extents (cally_text, 0, &x, &y, &width, &height,
ATK_XY_SCREEN);
g_print ("atk_text_get_character_extents (0, screen): x=%i y=%i width=%i height=%i\n",
x, y, width, height);
pos = atk_text_get_offset_at_point (cally_text, 200, 10, ATK_XY_WINDOW);
g_print ("atk_text_get_offset_at_point (200, 10, window): %i\n", pos);
pos = atk_text_get_offset_at_point (cally_text, 200, 100, ATK_XY_SCREEN);
g_print ("atk_text_get_offset_at_point (200, 100, screen): %i\n", pos);
}
static void
dump_actor_default_atk_attributes (ClutterActor *actor)
{
AtkObject *object = NULL;
AtkText *cally_text = NULL;
AtkAttributeSet *at_set = NULL;
GSList *attrs;
const gchar *text_value = NULL;
object = atk_gobject_accessible_for_object (G_OBJECT (actor));
cally_text = ATK_TEXT (object);
if (!cally_text)
return;
text_value = clutter_text_get_text (CLUTTER_TEXT (actor));
g_print ("text value = %s\n", text_value);
at_set = atk_text_get_default_attributes (cally_text);
attrs = (GSList*) at_set;
while (attrs) {
AtkAttribute *at = (AtkAttribute *) attrs->data;
g_print ("text default %s = %s\n", at->name, at->value);
attrs = g_slist_next (attrs);
}
}
static gboolean
button_press_cb (ClutterActor *actor,
ClutterButtonEvent *event,
gpointer data)
{
test_atk_text (text_actor);
test_atk_text (text_editable_actor);
return TRUE;
}
static void
make_ui (ClutterActor *stage)
{
ClutterColor color_stage = { 0x00, 0x00, 0x00, 0xff };
ClutterColor color_text = { 0xff, 0x00, 0x00, 0xff };
ClutterColor color_sel = { 0x00, 0xff, 0x00, 0x55 };
ClutterColor color_rect = { 0x00, 0xff, 0xff, 0xff };
ClutterColor color_label = { 0x00, 0x00, 0x00, 0xff };
ClutterActor *button = NULL;
ClutterActor *rectangle = NULL;
ClutterActor *label = NULL;
clutter_stage_set_color (CLUTTER_STAGE (stage), &color_stage);
clutter_actor_set_size (stage, WIDTH, HEIGHT);
/* text */
text_actor = clutter_text_new_full ("Sans Bold 32px",
"",
&color_text);
clutter_text_set_markup (CLUTTER_TEXT(text_actor),
"<span fgcolor=\"#FFFF00\" bgcolor=\"#00FF00\"><s>Lorem ipsum dolor sit amet</s></span>");
clutter_container_add_actor (CLUTTER_CONTAINER (stage), text_actor);
dump_actor_default_atk_attributes (text_actor);
/* text_editable */
text_editable_actor = clutter_text_new_full ("Sans Bold 32px",
"consectetur adipisicing elit",
&color_text);
clutter_actor_set_position (text_editable_actor, 20, 100);
clutter_text_set_editable (CLUTTER_TEXT (text_editable_actor), TRUE);
clutter_text_set_selectable (CLUTTER_TEXT (text_editable_actor), TRUE);
clutter_text_set_selection_color (CLUTTER_TEXT (text_editable_actor),
&color_sel);
clutter_text_set_line_wrap (CLUTTER_TEXT (text_editable_actor), TRUE);
clutter_actor_grab_key_focus (text_editable_actor);
clutter_actor_set_reactive (text_editable_actor, TRUE);
dump_actor_default_atk_attributes (text_editable_actor);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), text_editable_actor);
/* test button */
button = clutter_group_new ();
rectangle = clutter_rectangle_new_with_color (&color_rect);
clutter_actor_set_size (rectangle, 75, 35);
label = clutter_text_new_full ("Sans Bold 32px",
"Test", &color_label);
clutter_actor_set_position (button, 100, 200);
clutter_container_add_actor (CLUTTER_CONTAINER (button), rectangle);
clutter_container_add_actor (CLUTTER_CONTAINER (button), label);
clutter_actor_set_reactive (button, TRUE);
g_signal_connect_after (button, "button-press-event",
G_CALLBACK (button_press_cb), NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
}
int
main (int argc, char *argv[])
{
ClutterActor *stage;
g_set_application_name ("AtkText");
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
cally_util_a11y_init (&argc, &argv);
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - AtkText Test");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
make_ui (stage);
clutter_actor_show_all (stage);
test_atk_text (text_actor);
test_atk_text (text_editable_actor);
clutter_main ();
return 0;
}

View File

@ -0,0 +1,116 @@
/* 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.
*/
#include <atk/atk.h>
#include <clutter/clutter.h>
#include "cally-examples-util.h"
#define WIDTH 800
#define HEIGHT 600
#define HEIGHT_STEP 100
#define NUM_ENTRIES 3
static void
make_ui (ClutterActor *stage)
{
ClutterActor *editable = NULL;
ClutterActor *rectangle = NULL;
ClutterActor *label = NULL;
ClutterColor color_stage = { 0x00, 0x00, 0x00, 0xff };
ClutterColor color_text = { 0xff, 0x00, 0x00, 0xff };
ClutterColor color_sel = { 0x00, 0xff, 0x00, 0x55 };
ClutterColor color_label = { 0x00, 0xff, 0x55, 0xff };
ClutterColor color_rect = { 0x00, 0xff, 0xff, 0x55 };
ClutterActor *full_entry = NULL;
ClutterActor *cloned_entry = NULL;
clutter_stage_set_color (CLUTTER_STAGE (stage), &color_stage);
clutter_actor_set_size (stage, WIDTH, HEIGHT);
label = clutter_text_new_full ("Sans Bold 32px",
"Entry",
&color_label);
clutter_actor_set_position (label, 0, 50);
/* editable */
editable = clutter_text_new_full ("Sans Bold 32px",
"ddd",
&color_text);
clutter_actor_set_position (editable, 150, 50);
clutter_text_set_editable (CLUTTER_TEXT (editable), TRUE);
clutter_text_set_selectable (CLUTTER_TEXT (editable), TRUE);
clutter_text_set_selection_color (CLUTTER_TEXT (editable),
&color_sel);
clutter_actor_grab_key_focus (editable);
clutter_actor_set_reactive (editable, TRUE);
/* rectangle: to create a entry "feeling" */
rectangle = clutter_rectangle_new_with_color (&color_rect);
clutter_actor_set_position (rectangle, 150, 50);
clutter_actor_add_constraint (rectangle, clutter_bind_constraint_new (editable, CLUTTER_BIND_SIZE, 0));
full_entry = clutter_group_new ();
clutter_actor_set_position (full_entry, 0, 50);
clutter_actor_set_size (full_entry, 100, 75);
clutter_container_add_actor (CLUTTER_CONTAINER (full_entry), label);
clutter_container_add_actor (CLUTTER_CONTAINER (full_entry), editable);
clutter_container_add_actor (CLUTTER_CONTAINER (full_entry), rectangle);
clutter_actor_show_all (full_entry);
clutter_actor_set_scale (full_entry, 2, 1);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), full_entry);
/* Cloning! */
cloned_entry = clutter_clone_new (full_entry);
clutter_actor_set_position (cloned_entry, 50, 200);
clutter_actor_set_scale (cloned_entry, 1, 2);
clutter_actor_show_all (cloned_entry);
clutter_actor_set_reactive (cloned_entry, TRUE);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), cloned_entry);
}
int
main (int argc, char *argv[])
{
ClutterActor *stage;
g_set_application_name ("Clone Example");
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
cally_util_a11y_init (&argc, &argv);
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cally - Clone Test");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
make_ui (stage);
clutter_actor_show_all (stage);
clutter_main ();
return 0;
}

View File

@ -0,0 +1,146 @@
/* 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.
*/
#include <gmodule.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#include "cally-examples-util.h"
/* Checking the at-spi sources, the module directory is
* $(libdir)/gtk-2.0/modules
*
* It is supposed cally would be installed on the same libdir.
*
* You could use the option atk-bridge-dir to use other directory.
*/
#define ATK_BRIDGE_DEFAULT_MODULE_DIRECTORY PREFIXDIR"/gtk-2.0/modules"
static gchar *
_search_for_bridge_module (const gchar *module_name)
{
/* We simplify the search for the atk bridge, see see the definition
* of the macro for more information*/
return g_strdup (ATK_BRIDGE_DEFAULT_MODULE_DIRECTORY);
}
static gchar*
_a11y_check_custom_bridge (int *argc,
char ***argv)
{
GError *error = NULL;
GOptionContext *context;
static gchar *bridge_dir = NULL;
static GOptionEntry entries [] =
{
{"atk-bridge-dir", 'd', 0, G_OPTION_ARG_STRING, &bridge_dir, "atk-bridge module directory", NULL}
};
context = g_option_context_new ("- cally examples");
g_option_context_add_main_entries (context, entries, NULL);
if (!g_option_context_parse (context, argc, argv, &error))
{
g_print ("%s\n", error->message);
g_print ("Use --help for more information.\n");
exit (0);
}
return bridge_dir;
}
static gboolean
_a11y_invoke_module (const gchar *module_path,
gboolean init)
{
GModule *handle;
void (*invoke_fn) (void);
const char *method;
if (init)
method = "gnome_accessibility_module_init";
else
method = "gnome_accessibility_module_shutdown";
if (!module_path)
return FALSE;
if (!(handle = g_module_open (module_path, G_MODULE_BIND_LAZY)))
{
g_warning ("Accessibility: failed to load module '%s': '%s'",
module_path, g_module_error ());
return FALSE;
}
if (!g_module_symbol (handle, method, (gpointer *)&invoke_fn))
{
g_warning ("Accessibility: error library '%s' does not include "
"method '%s' required for accessibility support",
module_path, method);
g_module_close (handle);
return FALSE;
}
g_debug ("Module %s loaded successfully", module_path);
invoke_fn ();
return TRUE;
}
/**
* This method will initialize the accessibility support provided by cally.
*
* Basically it will load the cally module using gmodule functions.
*
* Returns if it was able to init the a11y support or not.
*/
gboolean
cally_util_a11y_init (int *argc, char ***argv)
{
gchar *bridge_dir = NULL;
gchar *bridge_path = NULL;
gboolean result = FALSE;
if (clutter_get_accessibility_enabled () == FALSE)
{
g_warning ("Accessibility: clutter has no accessibility enabled"
" skipping the atk-bridge load");
return FALSE;
}
bridge_dir = _a11y_check_custom_bridge (argc, argv);
if (bridge_dir == NULL)
bridge_dir = _search_for_bridge_module ("atk-bridge");
bridge_path = g_module_build_path (bridge_dir, "libatk-bridge");
result = _a11y_invoke_module (bridge_path, TRUE);
g_free (bridge_dir);
g_free (bridge_path);
return result;
}

View File

@ -0,0 +1,24 @@
/* 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.
*/
gboolean
cally_util_a11y_init (int *argc, char ***argv);

View File

@ -0,0 +1,38 @@
clutter_test_accessibility_common_sources = [
'cally-examples-util.c',
'cally-examples-util.h',
]
clutter_test_accessibility_c_args = [
'-DPREFIXDIR="@0@"'.format(libdir),
'-DCLUTTER_DISABLE_DEPRECATION_WARNINGS',
'-DGLIB_DISABLE_DEPRECATION_WARNINGS',
]
clutter_test_accessibility_c_args += clutter_debug_c_args
clutter_accessibility_tests_dependencies = [
clutter_deps,
libmutter_clutter_dep,
]
clutter_accessibility_tests = [
'cally-atkcomponent-example',
'cally-atktext-example',
'cally-atkevents-example',
'cally-atkeditabletext-example',
'cally-clone-example',
]
foreach test : clutter_accessibility_tests
executable(test,
sources: [
clutter_test_accessibility_common_sources,
test + '.c',
],
include_directories: clutter_includes,
c_args: clutter_test_accessibility_c_args,
dependencies: [clutter_accessibility_tests_dependencies],
install: false,
)
endforeach

View File

@ -0,0 +1,173 @@
{
ioctl_1
Memcheck:Param
ioctl(generic)
fun:ioctl
fun:driDrawableInitVBlank
fun:intelMakeCurrent
fun:glXMakeContextCurrent
}
{
ioctl_2
Memcheck:Param
ioctl(generic)
fun:ioctl
fun:driDrawableGetMSC32
fun:clutter_backend_glx_redraw
}
{
ioctl_3
Memcheck:Param
ioctl(generic)
fun:ioctl
fun:driWaitForMSC32
fun:clutter_backend_glx_redraw
}
{
mesa_init_context
Memcheck:Leak
fun:*alloc
...
fun:glXCreateNewContext
}
{
type_register
Memcheck:Leak
fun:*alloc
...
fun:g_type_register_*
}
{
type_ref
Memcheck:Leak
fun:*alloc
...
fun:g_type_class_ref
}
{
type_interface_prereq
Memcheck:Leak
fun:*alloc
...
fun:g_type_interface_add_prerequisite
}
{
get_charset
Memcheck:Leak
fun:*alloc
...
fun:g_get_charset
}
{
cogl_features
Memcheck:Leak
fun:*alloc
...
fun:cogl_get_features
}
{
glx_query_version
Memcheck:Leak
fun:*alloc
...
fun:glXQueryVersion
}
{
glx_create_context
Memcheck:Leak
fun:*alloc
...
fun:glXCreateNewContext
}
{
glx_make_current
Memcheck:Leak
fun:*alloc
...
fun:glXMakeContextCurrent
}
{
gl_draw_arrays
Memcheck:Leak
fun:*malloc
...
fun:glDrawArrays
}
{
cogl_clear
Memcheck:Leak
fun:*alloc
...
fun:cogl_clear
}
{
default_font
Memcheck:Leak
fun:*alloc
...
fun:clutter_backend_get_font_name
}
{
id_pool
Memcheck:Leak
fun:*alloc
...
fun:clutter_id_pool_new
}
{
x_open_display
Memcheck:Leak
fun:*alloc
...
fun:XOpenDisplay
}
# ... and font descriptions from every "sans 12" type string
{
pango_font_description_from_string
Memcheck:Leak
fun:*alloc
...
fun:pango_font_description_from_string
}
# other lib init
{
fontconfig_init
Memcheck:Leak
fun:*alloc
...
fun:FcConfigParseAndLoad
}
{
freetype_init
Memcheck:Leak
fun:*alloc
...
fun:FT_Open_Face
}
{
x_init_ext
Memcheck:Leak
fun:*alloc
...
fun:XInitExtension
}

View File

@ -0,0 +1,740 @@
#include <stdlib.h>
#include <string.h>
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#define NOTIFY_ANCHOR_X (1 << 0)
#define NOTIFY_ANCHOR_Y (1 << 1)
#define NOTIFY_ANCHOR_GRAVITY (1 << 2)
#define NOTIFY_SCALE_X (1 << 3)
#define NOTIFY_SCALE_Y (1 << 4)
#define NOTIFY_SCALE_CENTER_X (1 << 5)
#define NOTIFY_SCALE_CENTER_Y (1 << 6)
#define NOTIFY_SCALE_GRAVITY (1 << 7)
#define NOTIFY_ROTATION_ANGLE_X (1 << 8)
#define NOTIFY_ROTATION_ANGLE_Y (1 << 9)
#define NOTIFY_ROTATION_ANGLE_Z (1 << 10)
#define NOTIFY_ROTATION_CENTER_X (1 << 11)
#define NOTIFY_ROTATION_CENTER_Y (1 << 12)
#define NOTIFY_ROTATION_CENTER_Z (1 << 13)
#define NOTIFY_ROTATION_CENTER_Z_GRAVITY (1 << 14)
#define RECT_WIDTH 100.0
#define RECT_HEIGHT 80.0
/* Allow the transformed position by off by a certain number of
pixels */
#define POSITION_TOLERANCE 2
typedef struct _TestState
{
gulong notifications;
ClutterActor *rect;
} TestState;
static const struct
{
ClutterGravity gravity;
gfloat x_pos;
gfloat y_pos;
} gravities[] =
{
{ CLUTTER_GRAVITY_NORTH, RECT_WIDTH / 2, 0 },
{ CLUTTER_GRAVITY_NORTH_EAST, RECT_WIDTH, 0 },
{ CLUTTER_GRAVITY_EAST, RECT_WIDTH, RECT_HEIGHT / 2 },
{ CLUTTER_GRAVITY_SOUTH_EAST, RECT_WIDTH, RECT_HEIGHT },
{ CLUTTER_GRAVITY_SOUTH, RECT_WIDTH / 2, RECT_HEIGHT },
{ CLUTTER_GRAVITY_SOUTH_WEST, 0, RECT_HEIGHT },
{ CLUTTER_GRAVITY_WEST, 0, RECT_HEIGHT / 2 },
{ CLUTTER_GRAVITY_NORTH_WEST, 0, 0 },
{ CLUTTER_GRAVITY_CENTER, RECT_WIDTH / 2, RECT_HEIGHT / 2 }
};
static const char * const properties[] = {
"anchor-x",
"anchor-y",
"anchor-gravity",
"scale-x",
"scale-y",
"scale-center-x",
"scale-center-y",
"scale-gravity",
"rotation-angle-x",
"rotation-angle-y",
"rotation-angle-z",
"rotation-center-x",
"rotation-center-y",
"rotation-center-z",
"rotation-center-z-gravity"
};
static const int n_properties = G_N_ELEMENTS (properties);
static void
notify_cb (GObject *object, GParamSpec *pspec, TestState *state)
{
int i;
int new_flags = 0;
int flag = 1;
for (i = 0; i < n_properties; i++)
{
if (!strcmp (properties[i], pspec->name))
new_flags |= flag;
flag <<= 1;
}
g_assert ((new_flags & state->notifications) == 0);
state->notifications |= new_flags;
}
#define assert_notifications(flags) G_STMT_START { \
g_assert (state->notifications == (flags)); \
state->notifications = 0; } G_STMT_END
/* Helper macro to assert the transformed position. This needs to be a
macro so that the assertion failure will report the right line
number */
#define assert_coords(state, x_1, y_1, x_2, y_2) G_STMT_START { \
ClutterVertex verts[4]; \
clutter_actor_get_abs_allocation_vertices ((state)->rect, verts); \
check_coords ((state), (x_1), (y_1), (x_2), (y_2), verts); \
g_assert (approx_equal ((x_1), verts[0].x)); \
g_assert (approx_equal ((y_1), verts[0].y)); \
g_assert (approx_equal ((x_2), verts[3].x)); \
g_assert (approx_equal ((y_2), verts[3].y)); } G_STMT_END
#define assert_position(state, x, y) \
assert_coords((state), (x), (y), (x) + RECT_WIDTH, (y) + RECT_HEIGHT)
#define assert_vertex_and_free(v, xc, yc, zc) G_STMT_START { \
g_assert (approx_equal (v->x, xc) && \
approx_equal (v->y, yc) && \
approx_equal (v->z, zc)); \
g_boxed_free (CLUTTER_TYPE_VERTEX, v); } G_STMT_END
static inline gboolean
approx_equal (int a, int b)
{
return abs (a - b) <= POSITION_TOLERANCE;
}
static void
check_coords (TestState *state,
gint x_1,
gint y_1,
gint x_2,
gint y_2,
const ClutterVertex *verts)
{
if (g_test_verbose ())
g_print ("checking that (%i,%i,%i,%i) \xe2\x89\x88 (%i,%i,%i,%i): %s\n",
x_1, y_1, x_2, y_2,
(int) (verts[0].x),
(int) (verts[0].y),
(int) (verts[3].x),
(int) (verts[3].y),
approx_equal (x_1, verts[0].x) &&
approx_equal (y_1, verts[0].y) &&
approx_equal (x_2, verts[3].x) &&
approx_equal (y_2, verts[3].y) ? "yes"
: "NO");
}
static void
test_anchor_point (TestState *state)
{
ClutterActor *rect = state->rect;
gfloat anchor_x, anchor_y;
ClutterGravity anchor_gravity;
int i;
/* Assert the default settings */
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"anchor-x", &anchor_x,
"anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 0);
g_assert (anchor_y == 0);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
/* Change the anchor point */
clutter_actor_set_anchor_point (rect, 20, 30);
g_object_get (rect,
"anchor-x", &anchor_x,
"anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 20);
g_assert (anchor_y == 30);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
assert_position (state, 80, 170);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y);
/* Move the anchor point */
clutter_actor_move_anchor_point (rect, 40, 50);
g_object_get (rect,
"anchor-x", &anchor_x,
"anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 40);
g_assert (anchor_y == 50);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
assert_position (state, 80, 170);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y);
/* Put the actor back to its default position */
clutter_actor_set_position (rect, 100, 200);
/* Change the anchor point with each of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,
gravities[i].gravity);
g_print ("Setting gravity to %s\n",
value ? value->value_name : "?");
g_type_class_unref (gravity_class);
}
g_object_set (rect, "anchor-gravity", gravities[i].gravity, NULL);
g_object_get (rect,
"anchor-x", &anchor_x,
"anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == gravities[i].x_pos);
g_assert (anchor_y == gravities[i].y_pos);
g_assert (anchor_gravity == gravities[i].gravity);
assert_position (state,
100 - gravities[i].x_pos,
200 - gravities[i].y_pos);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y
| NOTIFY_ANCHOR_GRAVITY);
}
/* Verify that the anchor point moves if the actor changes size when
it is set from the gravity */
clutter_actor_set_size (rect, RECT_WIDTH * 2, RECT_HEIGHT * 2);
g_object_get (rect,
"anchor-x", &anchor_x,
"anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == RECT_WIDTH);
g_assert (anchor_y == RECT_HEIGHT);
g_assert (anchor_gravity == CLUTTER_GRAVITY_CENTER);
assert_coords (state, 100 - RECT_WIDTH, 200 - RECT_HEIGHT,
100 + RECT_WIDTH, 200 + RECT_HEIGHT);
assert_notifications (0);
clutter_actor_set_size (rect, RECT_WIDTH, RECT_HEIGHT);
/* Change the anchor point using units again to assert that the
gravity property changes */
clutter_actor_set_anchor_point (rect, 20, 30);
g_object_get (rect,
"anchor-x", &anchor_x, "anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 20);
g_assert (anchor_y == 30);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
assert_position (state, 80, 170);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y
| NOTIFY_ANCHOR_GRAVITY);
/* Verify that the anchor point doesn't move if the actor changes
size when it is set from units */
clutter_actor_set_size (rect, RECT_WIDTH * 2, RECT_HEIGHT * 2);
g_object_get (rect,
"anchor-x", &anchor_x,
"anchor-y", &anchor_y,
"anchor-gravity", &anchor_gravity,
NULL);
g_assert (anchor_x == 20);
g_assert (anchor_y == 30);
g_assert (anchor_gravity == CLUTTER_GRAVITY_NONE);
assert_coords (state, 80, 170, 80 + RECT_WIDTH * 2, 170 + RECT_HEIGHT * 2);
assert_notifications (0);
clutter_actor_set_size (rect, RECT_WIDTH, RECT_HEIGHT);
/* Put the anchor back */
clutter_actor_set_anchor_point_from_gravity (rect, CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_ANCHOR_X | NOTIFY_ANCHOR_Y);
}
static void
test_scale_center (TestState *state)
{
ClutterActor *rect = state->rect;
gdouble scale_x, scale_y;
gfloat center_x, center_y;
ClutterGravity gravity;
int i;
/* Assert the default settings */
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"scale-center-x", &center_x,
"scale-center-y", &center_y,
"scale-x", &scale_x,
"scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == 0);
g_assert (center_y == 0);
g_assert (scale_x == 1.0);
g_assert (scale_y == 1.0);
g_assert (gravity == CLUTTER_GRAVITY_NONE);
/* Try changing the scale without affecting the center */
g_object_set (rect, "scale-x", 2.0, "scale-y", 3.0, NULL);
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"scale-center-x", &center_x,
"scale-center-y", &center_y,
"scale-x", &scale_x,
"scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == 0);
g_assert (center_y == 0);
g_assert (scale_x == 2.0);
g_assert (scale_y == 3.0);
g_assert (gravity == CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y);
assert_coords (state, 100, 200, 100 + RECT_WIDTH * 2, 200 + RECT_HEIGHT * 3);
/* Change the scale and center */
g_object_set (rect,
"scale-x", 4.0,
"scale-y", 2.0,
"scale-center-x", 10.0,
"scale-center-y", 20.0,
NULL);
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"scale-center-x", &center_x, "scale-center-y", &center_y,
"scale-x", &scale_x, "scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == 10);
g_assert (center_y == 20);
g_assert (scale_x == 4.0);
g_assert (scale_y == 2.0);
g_assert (gravity == CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y
| NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y);
assert_coords (state, 100 + 10 - 10 * 4, 200 + 20 - 20 * 2,
100 + 10 + (RECT_WIDTH - 10) * 4,
200 + 20 + (RECT_HEIGHT - 20) * 2);
/* Change the anchor point with each of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,
gravities[i].gravity);
g_print ("Setting scale center to %s\n",
value ? value->value_name : "?");
g_type_class_unref (gravity_class);
}
g_object_set (rect, "scale-gravity", gravities[i].gravity, NULL);
g_assert (clutter_actor_get_x (rect) == 100);
g_assert (clutter_actor_get_y (rect) == 200);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"scale-center-x", &center_x, "scale-center-y", &center_y,
"scale-x", &scale_x, "scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == gravities[i].x_pos);
g_assert (center_y == gravities[i].y_pos);
g_assert (scale_x == 4.0);
g_assert (scale_y == 2.0);
g_assert (gravity == gravities[i].gravity);
assert_notifications (NOTIFY_SCALE_CENTER_X |
NOTIFY_SCALE_CENTER_Y |
NOTIFY_SCALE_GRAVITY);
assert_coords (state,
100 - gravities[i].x_pos * 3,
200 - gravities[i].y_pos,
100 + (gravities[i].x_pos
+ (RECT_WIDTH - gravities[i].x_pos) * 4),
200 + (gravities[i].y_pos
+ (RECT_HEIGHT - gravities[i].y_pos) * 2));
}
/* Change the scale center using units again to assert that the
gravity property changes */
clutter_actor_set_scale_full (rect, 4, 2, 10, 20);
g_object_get (rect,
"scale-center-x", &center_x,
"scale-center-y", &center_y,
"scale-x", &scale_x,
"scale-y", &scale_y,
"scale-gravity", &gravity,
NULL);
g_assert (center_x == 10);
g_assert (center_y == 20);
g_assert (scale_x == 4.0);
g_assert (scale_y == 2.0);
g_assert (gravity == CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y
| NOTIFY_SCALE_GRAVITY);
assert_coords (state, 100 + 10 - 10 * 4, 200 + 20 - 20 * 2,
100 + 10 + (RECT_WIDTH - 10) * 4,
200 + 20 + (RECT_HEIGHT - 20) * 2);
/* Put the scale back to normal */
clutter_actor_set_scale_full (rect, 1, 1, 0, 0);
assert_notifications (NOTIFY_SCALE_X | NOTIFY_SCALE_Y
| NOTIFY_SCALE_CENTER_X | NOTIFY_SCALE_CENTER_Y);
}
static void
test_rotate_center (TestState *state)
{
ClutterActor *rect = state->rect;
gdouble angle_x, angle_y, angle_z;
ClutterVertex *center_x, *center_y, *center_z;
ClutterGravity z_center_gravity;
gfloat stage_width, stage_height;
gfloat rect_x, rect_y;
int i;
/* Position the rectangle at the center of the stage so that
rotations by 90° along the X or Y axis will cause the actor to be
appear as a flat line. This makes verifying the transformations
easier */
clutter_actor_get_size (clutter_actor_get_stage (rect),
&stage_width,
&stage_height);
rect_x = stage_width / 2;
rect_y = stage_height / 2;
clutter_actor_set_position (rect, rect_x, rect_y);
/* Assert the default settings */
g_assert_cmpfloat (clutter_actor_get_x (rect), ==, rect_x);
g_assert_cmpfloat (clutter_actor_get_y (rect), ==, rect_y);
g_assert_cmpfloat (clutter_actor_get_width (rect), ==, RECT_WIDTH);
g_assert_cmpfloat (clutter_actor_get_height (rect), ==, RECT_HEIGHT);
g_object_get (rect,
"rotation-angle-x", &angle_x,
"rotation-angle-y", &angle_y,
"rotation-angle-z", &angle_z,
"rotation-center-x", &center_x,
"rotation-center-y", &center_y,
"rotation-center-z", &center_z,
"rotation-center-z-gravity", &z_center_gravity,
NULL);
g_assert (angle_x == 0.0);
g_assert (angle_y == 0.0);
g_assert (angle_z == 0.0);
assert_vertex_and_free (center_x, 0, 0, 0);
assert_vertex_and_free (center_y, 0, 0, 0);
assert_vertex_and_free (center_z, 0, 0, 0);
g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE);
/* Change each of the rotation angles without affecting the center
point */
for (i = CLUTTER_X_AXIS; i <= CLUTTER_Z_AXIS; i++)
{
char prop_name[] = "rotation-angle- ";
prop_name[sizeof (prop_name) - 2] = i - CLUTTER_X_AXIS + 'x';
if (g_test_verbose ())
g_print ("Setting %s to 90 degrees\n", prop_name);
g_object_set (rect, prop_name, 90.0, NULL);
assert_notifications (NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS));
g_assert (clutter_actor_get_x (rect) == rect_x);
g_assert (clutter_actor_get_y (rect) == rect_y);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"rotation-angle-x", &angle_x,
"rotation-angle-y", &angle_y,
"rotation-angle-z", &angle_z,
"rotation-center-x", &center_x,
"rotation-center-y", &center_y,
"rotation-center-z", &center_z,
"rotation-center-z-gravity", &z_center_gravity,
NULL);
if (i == CLUTTER_X_AXIS)
{
g_assert (angle_x == 90.0);
assert_coords (state, rect_x, rect_y, verts[3].x, rect_y);
}
else
g_assert (angle_x == 0.0);
if (i == CLUTTER_Y_AXIS)
{
g_assert (angle_y == 90.0);
assert_coords (state, rect_x, rect_y, rect_x, verts[3].y);
}
else
g_assert (angle_y == 0.0);
if (i == CLUTTER_Z_AXIS)
{
g_assert (angle_z == 90.0);
assert_coords (state, rect_x, rect_y,
rect_x - RECT_HEIGHT,
rect_y + RECT_WIDTH);
}
else
g_assert (angle_z == 0.0);
assert_vertex_and_free (center_x, 0, 0, 0);
assert_vertex_and_free (center_y, 0, 0, 0);
assert_vertex_and_free (center_z, 0, 0, 0);
g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE);
g_object_set (rect, prop_name, 0.0, NULL);
assert_notifications (NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS));
}
clutter_actor_set_position (rect, rect_x -= 10, rect_y -= 20);
/* Same test but also change the center position */
for (i = CLUTTER_X_AXIS; i <= CLUTTER_Z_AXIS; i++)
{
char prop_name[] = "rotation-angle- ";
prop_name[sizeof (prop_name) - 2] = i - CLUTTER_X_AXIS + 'x';
if (g_test_verbose ())
g_print ("Setting %s to 90 degrees with center 10,20,0\n", prop_name);
clutter_actor_set_rotation (rect, i, 90.0, 10, 20, 0);
assert_notifications ((NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS))
| (NOTIFY_ROTATION_CENTER_X
<< (i - CLUTTER_X_AXIS)));
g_assert (clutter_actor_get_x (rect) == rect_x);
g_assert (clutter_actor_get_y (rect) == rect_y);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"rotation-angle-x", &angle_x,
"rotation-angle-y", &angle_y,
"rotation-angle-z", &angle_z,
"rotation-center-x", &center_x,
"rotation-center-y", &center_y,
"rotation-center-z", &center_z,
"rotation-center-z-gravity", &z_center_gravity,
NULL);
if (i == CLUTTER_X_AXIS)
{
g_assert (angle_x == 90.0);
assert_coords (state,
verts[0].x, rect_y + 20,
verts[3].x, rect_y + 20);
assert_vertex_and_free (center_x, 10, 20, 0);
}
else
{
g_assert (angle_x == 0.0);
assert_vertex_and_free (center_x, 0, 0, 0);
}
if (i == CLUTTER_Y_AXIS)
{
g_assert (angle_y == 90.0);
assert_coords (state,
rect_x + 10, verts[0].y,
rect_x + 10, verts[3].y);
assert_vertex_and_free (center_y, 10, 20, 0);
}
else
{
g_assert (angle_y == 0.0);
assert_vertex_and_free (center_y, 0, 0, 0);
}
if (i == CLUTTER_Z_AXIS)
{
g_assert (angle_z == 90.0);
assert_coords (state,
rect_x + 10 + 20,
rect_y + 20 - 10,
rect_x + 10 + 20 - RECT_HEIGHT,
rect_y + 20 + RECT_WIDTH - 10);
assert_vertex_and_free (center_z, 10, 20, 0);
}
else
{
g_assert (angle_z == 0.0);
assert_vertex_and_free (center_z, 0, 0, 0);
}
g_assert (z_center_gravity == CLUTTER_GRAVITY_NONE);
clutter_actor_set_rotation (rect, i, 0, 0, 0, 0);
assert_notifications ((NOTIFY_ROTATION_ANGLE_X << (i - CLUTTER_X_AXIS))
| (NOTIFY_ROTATION_CENTER_X
<< (i - CLUTTER_X_AXIS)));
}
/* Try rotating the z with all of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,
gravities[i].gravity);
g_print ("Setting z rotation to 90 degrees with center at %s\n",
value ? value->value_name : "?");
g_type_class_unref (gravity_class);
}
clutter_actor_set_z_rotation_from_gravity (rect, 90,
gravities[i].gravity);
assert_notifications (NOTIFY_ROTATION_ANGLE_Z
| NOTIFY_ROTATION_CENTER_Z
| NOTIFY_ROTATION_CENTER_Z_GRAVITY);
g_assert (clutter_actor_get_x (rect) == rect_x);
g_assert (clutter_actor_get_y (rect) == rect_y);
g_assert (clutter_actor_get_width (rect) == RECT_WIDTH);
g_assert (clutter_actor_get_height (rect) == RECT_HEIGHT);
g_object_get (rect,
"rotation-angle-x", &angle_x,
"rotation-angle-y", &angle_y,
"rotation-angle-z", &angle_z,
"rotation-center-x", &center_x,
"rotation-center-y", &center_y,
"rotation-center-z", &center_z,
"rotation-center-z-gravity", &z_center_gravity,
NULL);
g_assert (angle_x == 0.0);
g_assert (angle_y == 0.0);
g_assert (angle_z == 90.0);
assert_vertex_and_free (center_x, 0, 0, 0);
assert_vertex_and_free (center_y, 0, 0, 0);
assert_vertex_and_free (center_z,
gravities[i].x_pos, gravities[i].y_pos, 0);
assert_coords (state,
rect_x + gravities[i].x_pos + gravities[i].y_pos,
rect_y + gravities[i].y_pos - gravities[i].x_pos,
rect_x + gravities[i].x_pos + gravities[i].y_pos
- RECT_HEIGHT,
rect_y + gravities[i].y_pos + RECT_WIDTH
- gravities[i].x_pos);
g_assert (z_center_gravity == gravities[i].gravity);
g_assert (clutter_actor_get_z_rotation_gravity (rect)
== gravities[i].gravity);
/* Put the rotation back */
clutter_actor_set_z_rotation_from_gravity (rect, 0, CLUTTER_GRAVITY_NONE);
assert_notifications (NOTIFY_ROTATION_ANGLE_Z
| NOTIFY_ROTATION_CENTER_Z
| NOTIFY_ROTATION_CENTER_Z_GRAVITY);
}
}
static gboolean
idle_cb (gpointer data)
{
test_anchor_point (data);
test_scale_center (data);
test_rotate_center (data);
clutter_main_quit ();
return G_SOURCE_REMOVE;
}
static void
actor_anchors (void)
{
TestState state;
ClutterActor *stage;
stage = clutter_test_get_stage ();
state.rect = clutter_actor_new ();
clutter_actor_add_child (stage, state.rect);
clutter_actor_set_position (state.rect, 100, 200);
clutter_actor_set_size (state.rect, RECT_WIDTH, RECT_HEIGHT);
/* Record notifications on the actor properties */
state.notifications = 0;
g_signal_connect (state.rect, "notify",
G_CALLBACK (notify_cb), &state);
/* Run the tests in a low priority idle function so that we can be
sure the stage is correctly setup */
clutter_threads_add_idle_full (G_PRIORITY_LOW, idle_cb, &state, NULL);
clutter_actor_show (stage);
clutter_main ();
}
static void
actor_pivot (void)
{
ClutterActor *stage, *actor_implicit, *actor_explicit;
ClutterMatrix transform, result_implicit, result_explicit;
ClutterActorBox allocation = CLUTTER_ACTOR_BOX_INIT (0, 0, 90, 30);
gfloat angle = 30;
stage = clutter_test_get_stage ();
actor_implicit = clutter_actor_new ();
actor_explicit = clutter_actor_new ();
clutter_actor_add_child (stage, actor_implicit);
clutter_actor_add_child (stage, actor_explicit);
/* Fake allocation or pivot-point will not have any effect */
clutter_actor_allocate (actor_implicit, &allocation, CLUTTER_ALLOCATION_NONE);
clutter_actor_allocate (actor_explicit, &allocation, CLUTTER_ALLOCATION_NONE);
clutter_actor_set_pivot_point (actor_implicit, 0.5, 0.5);
clutter_actor_set_pivot_point (actor_explicit, 0.5, 0.5);
/* Implict transformation */
clutter_actor_set_rotation_angle (actor_implicit, CLUTTER_Z_AXIS, angle);
/* Explict transformation */
clutter_matrix_init_identity(&transform);
cogl_matrix_rotate (&transform, angle, 0, 0, 1.0);
clutter_actor_set_transform (actor_explicit, &transform);
clutter_actor_get_transform (actor_implicit, &result_implicit);
clutter_actor_get_transform (actor_explicit, &result_explicit);
g_assert (cogl_matrix_equal (&result_implicit, &result_explicit));
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/transforms/anchor-point", actor_anchors)
CLUTTER_TEST_UNIT ("/actor/transforms/pivot-point", actor_pivot)
)

View File

@ -0,0 +1,195 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#define TEST_TYPE_DESTROY (test_destroy_get_type ())
#define TEST_DESTROY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_DESTROY, TestDestroy))
#define TEST_IS_DESTROY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_DESTROY))
typedef struct _TestDestroy TestDestroy;
typedef struct _TestDestroyClass TestDestroyClass;
struct _TestDestroy
{
ClutterActor parent_instance;
ClutterActor *bg;
ClutterActor *label;
ClutterActor *tex;
GList *children;
};
struct _TestDestroyClass
{
ClutterActorClass parent_class;
};
static void clutter_container_init (ClutterContainerIface *iface);
GType test_destroy_get_type (void);
G_DEFINE_TYPE_WITH_CODE (TestDestroy, test_destroy, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_init));
static void
test_destroy_add (ClutterContainer *container,
ClutterActor *actor)
{
TestDestroy *self = TEST_DESTROY (container);
if (g_test_verbose ())
g_print ("Adding '%s' (type:%s)\n",
clutter_actor_get_name (actor),
G_OBJECT_TYPE_NAME (actor));
self->children = g_list_prepend (self->children, actor);
clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
}
static void
test_destroy_remove (ClutterContainer *container,
ClutterActor *actor)
{
TestDestroy *self = TEST_DESTROY (container);
if (g_test_verbose ())
g_print ("Removing '%s' (type:%s)\n",
clutter_actor_get_name (actor),
G_OBJECT_TYPE_NAME (actor));
g_assert (actor != self->bg);
g_assert (actor != self->label);
if (!g_list_find (self->children, actor))
g_assert (actor == self->tex);
else
self->children = g_list_remove (self->children, actor);
clutter_actor_unparent (actor);
}
static void
clutter_container_init (ClutterContainerIface *iface)
{
iface->add = test_destroy_add;
iface->remove = test_destroy_remove;
}
static void
test_destroy_destroy (ClutterActor *self)
{
TestDestroy *test = TEST_DESTROY (self);
if (test->bg != NULL)
{
if (g_test_verbose ())
g_print ("Destroying '%s' (type:%s)\n",
clutter_actor_get_name (test->bg),
G_OBJECT_TYPE_NAME (test->bg));
clutter_actor_destroy (test->bg);
test->bg = NULL;
}
if (test->label != NULL)
{
if (g_test_verbose ())
g_print ("Destroying '%s' (type:%s)\n",
clutter_actor_get_name (test->label),
G_OBJECT_TYPE_NAME (test->label));
clutter_actor_destroy (test->label);
test->label = NULL;
}
if (test->tex != NULL)
{
if (g_test_verbose ())
g_print ("Destroying '%s' (type:%s)\n",
clutter_actor_get_name (test->tex),
G_OBJECT_TYPE_NAME (test->tex));
clutter_actor_destroy (test->tex);
test->tex = NULL;
}
g_assert_nonnull (test->children);
if (CLUTTER_ACTOR_CLASS (test_destroy_parent_class)->destroy)
CLUTTER_ACTOR_CLASS (test_destroy_parent_class)->destroy (self);
g_assert_null (test->children);
}
static void
test_destroy_class_init (TestDestroyClass *klass)
{
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->destroy = test_destroy_destroy;
}
static void
test_destroy_init (TestDestroy *self)
{
clutter_actor_push_internal (CLUTTER_ACTOR (self));
if (g_test_verbose ())
g_print ("Adding internal children...\n");
self->bg = clutter_rectangle_new ();
clutter_actor_set_parent (self->bg, CLUTTER_ACTOR (self));
clutter_actor_set_name (self->bg, "Background");
self->label = clutter_text_new ();
clutter_actor_set_parent (self->label, CLUTTER_ACTOR (self));
clutter_actor_set_name (self->label, "Label");
clutter_actor_pop_internal (CLUTTER_ACTOR (self));
self->tex = clutter_texture_new ();
clutter_actor_set_parent (self->tex, CLUTTER_ACTOR (self));
clutter_actor_set_name (self->tex, "Texture");
}
static void
on_destroy (ClutterActor *actor,
gpointer data)
{
gboolean *destroy_called = data;
*destroy_called = TRUE;
}
static void
actor_destruction (void)
{
ClutterActor *test = g_object_new (TEST_TYPE_DESTROY, NULL);
ClutterActor *child = clutter_rectangle_new ();
gboolean destroy_called = FALSE;
g_object_ref_sink (test);
g_object_add_weak_pointer (G_OBJECT (test), (gpointer *) &test);
g_object_add_weak_pointer (G_OBJECT (child), (gpointer *) &child);
if (g_test_verbose ())
g_print ("Adding external child...\n");
clutter_actor_set_name (child, "Child");
clutter_container_add_actor (CLUTTER_CONTAINER (test), child);
g_signal_connect (child, "destroy", G_CALLBACK (on_destroy), &destroy_called);
if (g_test_verbose ())
g_print ("Calling destroy()...\n");
clutter_actor_destroy (test);
g_assert (destroy_called);
g_assert_null (child);
g_assert_null (test);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/destruction", actor_destruction)
)

View File

@ -0,0 +1,550 @@
#include <clutter/clutter.h>
static void
actor_add_child (void)
{
ClutterActor *actor = clutter_actor_new ();
ClutterActor *iter;
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "baz",
NULL));
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 3);
iter = clutter_actor_get_first_child (actor);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo");
iter = clutter_actor_get_next_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
iter = clutter_actor_get_next_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz");
g_assert (iter == clutter_actor_get_last_child (actor));
g_assert (clutter_actor_get_next_sibling (iter) == NULL);
iter = clutter_actor_get_last_child (actor);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz");
iter = clutter_actor_get_previous_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
iter = clutter_actor_get_previous_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo");
g_assert (iter == clutter_actor_get_first_child (actor));
g_assert (clutter_actor_get_previous_sibling (iter) == NULL);
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_insert_child (void)
{
ClutterActor *actor = clutter_actor_new ();
ClutterActor *iter;
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_insert_child_at_index (actor,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
NULL),
0);
iter = clutter_actor_get_first_child (actor);
g_assert (iter != NULL);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo");
g_assert (iter == clutter_actor_get_child_at_index (actor, 0));
clutter_actor_insert_child_below (actor,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
NULL),
iter);
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 2);
iter = clutter_actor_get_first_child (actor);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
iter = clutter_actor_get_next_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo");
g_assert (iter == clutter_actor_get_child_at_index (actor, 1));
iter = clutter_actor_get_first_child (actor);
clutter_actor_insert_child_above (actor,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "baz",
NULL),
iter);
iter = clutter_actor_get_last_child (actor);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo");
iter = clutter_actor_get_previous_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz");
iter = clutter_actor_get_previous_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
clutter_actor_remove_all_children (actor);
clutter_actor_insert_child_at_index (actor,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "1",
NULL),
0);
iter = clutter_actor_get_child_at_index (actor, 0);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "1");
g_assert (clutter_actor_get_first_child (actor) == iter);
g_assert (clutter_actor_get_last_child (actor) == iter);
clutter_actor_insert_child_at_index (actor,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "2",
NULL),
0);
iter = clutter_actor_get_child_at_index (actor, 0);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "2");
g_assert (clutter_actor_get_first_child (actor) == iter);
iter = clutter_actor_get_child_at_index (actor, 1);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "1");
g_assert (clutter_actor_get_last_child (actor) == iter);
clutter_actor_insert_child_at_index (actor,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "3",
NULL),
-1);
iter = clutter_actor_get_child_at_index (actor, 2);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "3");
g_assert (clutter_actor_get_last_child (actor) == iter);
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_remove_child (void)
{
ClutterActor *actor = clutter_actor_new ();
ClutterActor *iter;
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
NULL));
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 2);
g_assert (clutter_actor_get_first_child (actor) != clutter_actor_get_last_child (actor));
iter = clutter_actor_get_first_child (actor);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo");
iter = clutter_actor_get_last_child (actor);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
clutter_actor_remove_child (actor, clutter_actor_get_first_child (actor));
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 1);
iter = clutter_actor_get_first_child (actor);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
g_assert (clutter_actor_get_first_child (actor) == clutter_actor_get_last_child (actor));
clutter_actor_remove_child (actor, clutter_actor_get_first_child (actor));
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 0);
g_assert (clutter_actor_get_first_child (actor) == NULL);
g_assert (clutter_actor_get_last_child (actor) == NULL);
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_raise_child (void)
{
ClutterActor *actor = clutter_actor_new ();
ClutterActor *iter;
gboolean show_on_set_parent;
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
"visible", FALSE,
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
"visible", FALSE,
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "baz",
"visible", FALSE,
NULL));
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 3);
iter = clutter_actor_get_child_at_index (actor, 1);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
clutter_actor_set_child_above_sibling (actor, iter,
clutter_actor_get_child_at_index (actor, 2));
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 0)),
==,
"foo");
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 1)),
==,
"baz");
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 2)),
==,
"bar");
g_assert (!clutter_actor_is_visible (iter));
g_object_get (iter, "show-on-set-parent", &show_on_set_parent, NULL);
g_assert (!show_on_set_parent);
iter = clutter_actor_get_child_at_index (actor, 0);
clutter_actor_set_child_above_sibling (actor, iter, NULL);
g_object_add_weak_pointer (G_OBJECT (iter), (gpointer *) &iter);
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 0)),
==,
"baz");
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 1)),
==,
"bar");
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 2)),
==,
"foo");
g_assert (!clutter_actor_is_visible (iter));
g_object_get (iter, "show-on-set-parent", &show_on_set_parent, NULL);
g_assert (!show_on_set_parent);
clutter_actor_destroy (actor);
g_assert (actor == NULL);
g_assert (iter == NULL);
}
static void
actor_lower_child (void)
{
ClutterActor *actor = clutter_actor_new ();
ClutterActor *iter;
gboolean show_on_set_parent;
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
"visible", FALSE,
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
"visible", FALSE,
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "baz",
"visible", FALSE,
NULL));
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 3);
iter = clutter_actor_get_child_at_index (actor, 1);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
clutter_actor_set_child_below_sibling (actor, iter,
clutter_actor_get_child_at_index (actor, 0));
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 0)),
==,
"bar");
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 1)),
==,
"foo");
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 2)),
==,
"baz");
g_assert (!clutter_actor_is_visible (iter));
g_object_get (iter, "show-on-set-parent", &show_on_set_parent, NULL);
g_assert (!show_on_set_parent);
iter = clutter_actor_get_child_at_index (actor, 2);
clutter_actor_set_child_below_sibling (actor, iter, NULL);
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 0)),
==,
"baz");
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 1)),
==,
"bar");
g_assert_cmpstr (clutter_actor_get_name (clutter_actor_get_child_at_index (actor, 2)),
==,
"foo");
g_assert (!clutter_actor_is_visible (iter));
g_object_get (iter, "show-on-set-parent", &show_on_set_parent, NULL);
g_assert (!show_on_set_parent);
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_replace_child (void)
{
ClutterActor *actor = clutter_actor_new ();
ClutterActor *iter;
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
NULL));
iter = clutter_actor_get_child_at_index (actor, 0);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo");
clutter_actor_replace_child (actor, iter,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "baz",
NULL));
iter = clutter_actor_get_child_at_index (actor, 0);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz");
iter = clutter_actor_get_child_at_index (actor, 1);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
clutter_actor_replace_child (actor, iter,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "qux",
NULL));
iter = clutter_actor_get_child_at_index (actor, 0);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz");
iter = clutter_actor_get_child_at_index (actor, 1);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "qux");
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
NULL));
clutter_actor_replace_child (actor, iter,
g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
NULL));
iter = clutter_actor_get_last_child (actor);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "foo");
iter = clutter_actor_get_previous_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "bar");
iter = clutter_actor_get_previous_sibling (iter);
g_assert_cmpstr (clutter_actor_get_name (iter), ==, "baz");
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_remove_all (void)
{
ClutterActor *actor = clutter_actor_new ();
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
NULL));
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "baz",
NULL));
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 3);
clutter_actor_remove_all_children (actor);
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 0);
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_added (ClutterContainer *container,
ClutterActor *child,
gpointer data)
{
ClutterActor *actor = CLUTTER_ACTOR (container);
int *counter = data;
ClutterActor *old_child;
if (g_test_verbose ())
g_print ("Adding actor '%s'\n", clutter_actor_get_name (child));
old_child = clutter_actor_get_child_at_index (actor, 0);
if (old_child != child)
clutter_actor_remove_child (actor, old_child);
*counter += 1;
}
static void
actor_removed (ClutterContainer *container,
ClutterActor *child,
gpointer data)
{
int *counter = data;
if (g_test_verbose ())
g_print ("Removing actor '%s'\n", clutter_actor_get_name (child));
*counter += 1;
}
static void
actor_container_signals (void)
{
ClutterActor *actor = clutter_actor_new ();
int add_count, remove_count;
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
add_count = remove_count = 0;
g_signal_connect (actor,
"actor-added", G_CALLBACK (actor_added),
&add_count);
g_signal_connect (actor,
"actor-removed", G_CALLBACK (actor_removed),
&remove_count);
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "foo",
NULL));
g_assert_cmpint (add_count, ==, 1);
g_assert_cmpint (remove_count, ==, 0);
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 1);
clutter_actor_add_child (actor, g_object_new (CLUTTER_TYPE_ACTOR,
"name", "bar",
NULL));
g_assert_cmpint (add_count, ==, 2);
g_assert_cmpint (remove_count, ==, 1);
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, 1);
g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (actor_added),
&add_count);
g_signal_handlers_disconnect_by_func (actor, G_CALLBACK (actor_removed),
&remove_count);
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_contains (void)
{
/* This build up the following tree:
*
* a
* │ ╲
* │ ╲
* b c d
*
* e f g h i j
*/
struct {
ClutterActor *actor_a, *actor_b, *actor_c, *actor_d, *actor_e;
ClutterActor *actor_f, *actor_g, *actor_h, *actor_i, *actor_j;
} d;
int x, y;
ClutterActor **actor_array = &d.actor_a;
/* Matrix of expected results */
static const gboolean expected_results[] =
{ /* a, b, c, d, e, f, g, h, i, j */
/* a */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* b */ 0, 1, 0, 0, 1, 1, 0, 0, 0, 0,
/* c */ 0, 0, 1, 0, 0, 0, 1, 1, 0, 0,
/* d */ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1,
/* e */ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
/* f */ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
/* g */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
/* h */ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
/* i */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
/* j */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
};
d.actor_a = clutter_actor_new ();
d.actor_b = clutter_actor_new ();
d.actor_c = clutter_actor_new ();
d.actor_d = clutter_actor_new ();
d.actor_e = clutter_actor_new ();
d.actor_f = clutter_actor_new ();
d.actor_g = clutter_actor_new ();
d.actor_h = clutter_actor_new ();
d.actor_i = clutter_actor_new ();
d.actor_j = clutter_actor_new ();
clutter_actor_add_child (d.actor_a, d.actor_b);
clutter_actor_add_child (d.actor_a, d.actor_c);
clutter_actor_add_child (d.actor_a, d.actor_d);
clutter_actor_add_child (d.actor_b, d.actor_e);
clutter_actor_add_child (d.actor_b, d.actor_f);
clutter_actor_add_child (d.actor_c, d.actor_g);
clutter_actor_add_child (d.actor_c, d.actor_h);
clutter_actor_add_child (d.actor_d, d.actor_i);
clutter_actor_add_child (d.actor_d, d.actor_j);
for (y = 0; y < 10; y++)
for (x = 0; x < 10; x++)
g_assert_cmpint (clutter_actor_contains (actor_array[x],
actor_array[y]),
==,
expected_results[x * 10 + y]);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/graph/add-child", actor_add_child)
CLUTTER_TEST_UNIT ("/actor/graph/insert-child", actor_insert_child)
CLUTTER_TEST_UNIT ("/actor/graph/remove-child", actor_remove_child)
CLUTTER_TEST_UNIT ("/actor/graph/raise-child", actor_raise_child)
CLUTTER_TEST_UNIT ("/actor/graph/lower-child", actor_lower_child)
CLUTTER_TEST_UNIT ("/actor/graph/replace-child", actor_replace_child)
CLUTTER_TEST_UNIT ("/actor/graph/remove-all", actor_remove_all)
CLUTTER_TEST_UNIT ("/actor/graph/container-signals", actor_container_signals)
CLUTTER_TEST_UNIT ("/actor/graph/contains", actor_contains)
)

View File

@ -0,0 +1,371 @@
#include <stdlib.h>
#include <string.h>
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
static void
actor_initial_state (void)
{
ClutterActor *actor;
actor = clutter_actor_new ();
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
if (g_test_verbose ())
g_print ("initial state - visible: %s, realized: %s, mapped: %s\n",
CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_MAPPED (actor) ? "yes" : "no");
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor)));
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_shown_not_parented (void)
{
ClutterActor *actor;
actor = clutter_actor_new ();
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_show (actor);
if (g_test_verbose ())
g_print ("show without a parent - visible: %s, realized: %s, mapped: %s\n",
CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_MAPPED (actor) ? "yes" : "no");
g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor));
g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor));
g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor));
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
static void
actor_realized (void)
{
ClutterActor *actor;
ClutterActor *stage;
stage = clutter_test_get_stage ();
actor = clutter_actor_new ();
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor)));
clutter_actor_hide (actor); /* don't show, so won't map */
clutter_actor_add_child (stage, actor);
clutter_actor_realize (actor);
g_assert (CLUTTER_ACTOR_IS_REALIZED (actor));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor)));
}
static void
actor_mapped (void)
{
ClutterActor *actor;
ClutterActor *stage;
stage = clutter_test_get_stage ();
clutter_actor_show (stage);
actor = clutter_actor_new ();
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor)));
clutter_actor_add_child (stage, actor);
if (g_test_verbose ())
g_print ("adding to a container should map - "
"visible: %s, realized: %s, mapped: %s\n",
CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_MAPPED (actor) ? "yes" : "no");
g_assert (CLUTTER_ACTOR_IS_REALIZED (actor));
g_assert (CLUTTER_ACTOR_IS_MAPPED (actor));
g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor));
clutter_actor_hide (actor);
if (g_test_verbose ())
g_print ("hiding should unmap - "
"visible: %s, realized: %s, mapped: %s\n",
CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_MAPPED (actor) ? "yes" : "no");
g_assert (CLUTTER_ACTOR_IS_REALIZED (actor));
g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor));
g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor));
}
static void
actor_visibility_not_recursive (void)
{
ClutterActor *actor, *group;
ClutterActor *stage;
stage = clutter_test_get_stage ();
group = clutter_actor_new ();
actor = clutter_actor_new ();
clutter_actor_hide (group); /* don't show, so won't map */
clutter_actor_hide (actor); /* don't show, so won't map */
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (stage)));
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group)));
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor)));
clutter_actor_add_child (stage, group);
clutter_actor_add_child (group, actor);
clutter_actor_show (actor);
g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor));
g_assert (!CLUTTER_ACTOR_IS_VISIBLE (group));
g_assert (!CLUTTER_ACTOR_IS_VISIBLE (stage));
clutter_actor_show (stage);
g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor));
g_assert (!CLUTTER_ACTOR_IS_VISIBLE (group));
g_assert (CLUTTER_ACTOR_IS_VISIBLE (stage));
clutter_actor_hide (actor);
clutter_actor_hide (group);
clutter_actor_hide (stage);
g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor));
clutter_actor_show (stage);
g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor));
}
static void
actor_realize_not_recursive (void)
{
ClutterActor *actor, *group;
ClutterActor *stage;
stage = clutter_test_get_stage ();
clutter_actor_show (stage);
group = clutter_actor_new ();
actor = clutter_actor_new ();
clutter_actor_hide (group); /* don't show, so won't map */
clutter_actor_hide (actor); /* don't show, so won't map */
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group)));
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor)));
clutter_actor_add_child (stage, group);
clutter_actor_add_child (group, actor);
clutter_actor_realize (group);
g_assert (CLUTTER_ACTOR_IS_REALIZED (group));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group)));
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group)));
/* realizing group did not realize the child */
g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor)));
}
static void
actor_map_recursive (void)
{
ClutterActor *actor, *group;
ClutterActor *stage;
stage = clutter_test_get_stage ();
clutter_actor_show (stage);
group = clutter_actor_new ();
actor = clutter_actor_new ();
clutter_actor_hide (group); /* hide at first */
clutter_actor_show (actor); /* show at first */
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group)));
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group)));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group)));
g_assert ((CLUTTER_ACTOR_IS_VISIBLE (actor)));
clutter_actor_add_child (stage, group);
clutter_actor_add_child (group, actor);
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (group)));
g_assert (!(CLUTTER_ACTOR_IS_REALIZED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group)));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor)));
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group)));
g_assert ((CLUTTER_ACTOR_IS_VISIBLE (actor)));
/* show group, which should map and realize both
* group and child.
*/
clutter_actor_show (group);
g_assert (CLUTTER_ACTOR_IS_REALIZED (group));
g_assert (CLUTTER_ACTOR_IS_REALIZED (actor));
g_assert (CLUTTER_ACTOR_IS_MAPPED (group));
g_assert (CLUTTER_ACTOR_IS_MAPPED (actor));
g_assert (CLUTTER_ACTOR_IS_VISIBLE (group));
g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor));
}
static void
actor_show_on_set_parent (void)
{
ClutterActor *actor, *group;
gboolean show_on_set_parent;
ClutterActor *stage;
stage = clutter_test_get_stage ();
group = clutter_actor_new ();
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (group)));
clutter_actor_add_child (stage, group);
actor = clutter_actor_new ();
g_object_get (actor,
"show-on-set-parent", &show_on_set_parent,
NULL);
g_assert (!(CLUTTER_ACTOR_IS_VISIBLE (actor)));
g_assert (show_on_set_parent);
clutter_actor_add_child (group, actor);
g_object_get (actor,
"show-on-set-parent", &show_on_set_parent,
NULL);
g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor));
g_assert (show_on_set_parent);
g_object_ref (actor);
clutter_actor_remove_child (group, actor);
g_object_get (actor,
"show-on-set-parent", &show_on_set_parent,
NULL);
g_assert (!CLUTTER_ACTOR_IS_REALIZED (actor));
g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor));
g_assert (CLUTTER_ACTOR_IS_VISIBLE (actor));
g_assert (show_on_set_parent);
clutter_actor_destroy (actor);
clutter_actor_destroy (group);
actor = clutter_actor_new ();
clutter_actor_add_child (stage, actor);
clutter_actor_hide (actor);
g_object_get (actor,
"show-on-set-parent", &show_on_set_parent,
NULL);
g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor));
g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor));
g_assert (show_on_set_parent);
clutter_actor_destroy (actor);
actor = clutter_actor_new ();
clutter_actor_hide (actor);
clutter_actor_add_child (stage, actor);
g_object_get (actor,
"show-on-set-parent", &show_on_set_parent,
NULL);
g_assert (!CLUTTER_ACTOR_IS_VISIBLE (actor));
g_assert (!CLUTTER_ACTOR_IS_MAPPED (actor));
g_assert (!show_on_set_parent);
clutter_actor_destroy (actor);
}
static void
clone_no_map (void)
{
ClutterActor *stage;
ClutterActor *group;
ClutterActor *actor;
ClutterActor *clone;
stage = clutter_test_get_stage ();
clutter_actor_show (stage);
group = clutter_actor_new ();
actor = clutter_actor_new ();
clutter_actor_hide (group);
clutter_actor_add_child (group, actor);
clutter_actor_add_child (stage, group);
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group)));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor)));
clone = clutter_clone_new (group);
clutter_actor_add_child (stage, clone);
g_assert (CLUTTER_ACTOR_IS_MAPPED (clone));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (group)));
g_assert (!(CLUTTER_ACTOR_IS_MAPPED (actor)));
clutter_actor_destroy (CLUTTER_ACTOR (clone));
clutter_actor_destroy (CLUTTER_ACTOR (group));
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
default_stage (void)
{
ClutterActor *stage, *def_stage;
stage = clutter_test_get_stage ();
def_stage = clutter_stage_get_default ();
if (clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
g_assert (stage != def_stage);
else
g_assert (stage == def_stage);
g_assert (CLUTTER_ACTOR_IS_REALIZED (def_stage));
}
G_GNUC_END_IGNORE_DEPRECATIONS
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/invariants/initial-state", actor_initial_state)
CLUTTER_TEST_UNIT ("/actor/invariants/show-not-parented", actor_shown_not_parented)
CLUTTER_TEST_UNIT ("/actor/invariants/realized", actor_realized)
CLUTTER_TEST_UNIT ("/actor/invariants/mapped", actor_mapped)
CLUTTER_TEST_UNIT ("/actor/invariants/visibility-not-recursive", actor_visibility_not_recursive)
CLUTTER_TEST_UNIT ("/actor/invariants/realize-not-recursive", actor_realize_not_recursive)
CLUTTER_TEST_UNIT ("/actor/invariants/map-recursive", actor_map_recursive)
CLUTTER_TEST_UNIT ("/actor/invariants/show-on-set-parent", actor_show_on_set_parent)
CLUTTER_TEST_UNIT ("/actor/invariants/clone-no-map", clone_no_map)
CLUTTER_TEST_UNIT ("/actor/invariants/default-stage", default_stage)
)

View File

@ -0,0 +1,218 @@
#include <glib.h>
#include <clutter/clutter.h>
static void
actor_iter_traverse_children (void)
{
ClutterActorIter iter;
ClutterActor *actor;
ClutterActor *child;
int i, n_actors;
actor = clutter_actor_new ();
clutter_actor_set_name (actor, "root");
g_object_ref_sink (actor);
n_actors = g_random_int_range (10, 50);
for (i = 0; i < n_actors; i++)
{
char *name;
name = g_strdup_printf ("actor%d", i);
child = clutter_actor_new ();
clutter_actor_set_name (child, name);
clutter_actor_add_child (actor, child);
g_free (name);
}
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, n_actors);
i = 0;
clutter_actor_iter_init (&iter, actor);
g_assert (clutter_actor_iter_is_valid (&iter));
while (clutter_actor_iter_next (&iter, &child))
{
g_assert (CLUTTER_IS_ACTOR (child));
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child));
if (i == 0)
g_assert (child == clutter_actor_get_first_child (actor));
if (i == (n_actors - 1))
g_assert (child == clutter_actor_get_last_child (actor));
i += 1;
}
g_assert_cmpint (i, ==, n_actors);
i = 0;
clutter_actor_iter_init (&iter, actor);
g_assert (clutter_actor_iter_is_valid (&iter));
while (clutter_actor_iter_prev (&iter, &child))
{
g_assert (CLUTTER_IS_ACTOR (child));
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child));
if (i == 0)
g_assert (child == clutter_actor_get_last_child (actor));
if (i == (n_actors - 1))
g_assert (child == clutter_actor_get_first_child (actor));
i += 1;
}
g_object_unref (actor);
}
static void
actor_iter_traverse_remove (void)
{
ClutterActorIter iter;
ClutterActor *actor;
ClutterActor *child;
int i, n_actors;
actor = clutter_actor_new ();
clutter_actor_set_name (actor, "root");
g_object_ref_sink (actor);
n_actors = g_random_int_range (10, 50);
for (i = 0; i < n_actors; i++)
{
char *name;
name = g_strdup_printf ("actor%d", i);
child = clutter_actor_new ();
clutter_actor_set_name (child, name);
clutter_actor_add_child (actor, child);
g_free (name);
}
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, n_actors);
i = 0;
clutter_actor_iter_init (&iter, actor);
g_assert (clutter_actor_iter_is_valid (&iter));
while (clutter_actor_iter_next (&iter, &child))
{
g_assert (CLUTTER_IS_ACTOR (child));
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child));
if (i == 0)
g_assert (child == clutter_actor_get_first_child (actor));
if (i == (n_actors - 1))
g_assert (child == clutter_actor_get_last_child (actor));
clutter_actor_iter_remove (&iter);
g_assert (clutter_actor_iter_is_valid (&iter));
i += 1;
}
g_assert_cmpint (i, ==, n_actors);
g_assert_cmpint (0, ==, clutter_actor_get_n_children (actor));
}
static void
actor_iter_assignment (void)
{
ClutterActorIter iter_a, iter_b;
ClutterActor *actor;
ClutterActor *child;
int i, n_actors;
actor = clutter_actor_new ();
clutter_actor_set_name (actor, "root");
g_object_ref_sink (actor);
n_actors = g_random_int_range (10, 50);
for (i = 0; i < n_actors; i++)
{
char *name;
name = g_strdup_printf ("actor[%02d]", i);
child = clutter_actor_new ();
clutter_actor_set_name (child, name);
clutter_actor_add_child (actor, child);
g_free (name);
}
g_assert_cmpint (clutter_actor_get_n_children (actor), ==, n_actors);
i = 0;
clutter_actor_iter_init (&iter_a, actor);
iter_b = iter_a;
g_assert (clutter_actor_iter_is_valid (&iter_a));
g_assert (clutter_actor_iter_is_valid (&iter_b));
while (clutter_actor_iter_next (&iter_a, &child))
{
g_assert (CLUTTER_IS_ACTOR (child));
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
g_print ("actor %2d = '%s'\n", i, clutter_actor_get_name (child));
if (i == 0)
g_assert (child == clutter_actor_get_first_child (actor));
if (i == (n_actors - 1))
g_assert (child == clutter_actor_get_last_child (actor));
i += 1;
}
g_assert_cmpint (i, ==, n_actors);
i = n_actors - 1;
while (clutter_actor_iter_prev (&iter_b, &child))
{
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
g_print ("actor %2d = '%s'\n", i, clutter_actor_get_name (child));
if (i == n_actors - 1)
g_assert (child == clutter_actor_get_last_child (actor));
if (i == 0)
g_assert (child == clutter_actor_get_first_child (actor));
i -= 1;
}
g_assert_cmpint (i, ==, -1);
g_object_unref (actor);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/iter/traverse-children", actor_iter_traverse_children)
CLUTTER_TEST_UNIT ("/actor/iter/traverse-remove", actor_iter_traverse_remove)
CLUTTER_TEST_UNIT ("/actor/iter/assignment", actor_iter_assignment)
)

View File

@ -0,0 +1,92 @@
#include <clutter/clutter.h>
static void
actor_basic_layout (void)
{
ClutterActor *stage = clutter_test_get_stage ();
ClutterActor *vase;
ClutterActor *flower[3];
ClutterPoint p;
vase = clutter_actor_new ();
clutter_actor_set_name (vase, "Vase");
clutter_actor_set_layout_manager (vase, clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL));
clutter_actor_add_child (stage, vase);
flower[0] = clutter_actor_new ();
clutter_actor_set_background_color (flower[0], CLUTTER_COLOR_Red);
clutter_actor_set_size (flower[0], 100, 100);
clutter_actor_set_name (flower[0], "Red Flower");
clutter_actor_add_child (vase, flower[0]);
flower[1] = clutter_actor_new ();
clutter_actor_set_background_color (flower[1], CLUTTER_COLOR_Yellow);
clutter_actor_set_size (flower[1], 100, 100);
clutter_actor_set_name (flower[1], "Yellow Flower");
clutter_actor_add_child (vase, flower[1]);
flower[2] = clutter_actor_new ();
clutter_actor_set_background_color (flower[2], CLUTTER_COLOR_Green);
clutter_actor_set_size (flower[2], 100, 100);
clutter_actor_set_name (flower[2], "Green Flower");
clutter_actor_add_child (vase, flower[2]);
clutter_point_init (&p, 50, 50);
clutter_test_assert_actor_at_point (stage, &p, flower[0]);
clutter_point_init (&p, 150, 50);
clutter_test_assert_actor_at_point (stage, &p, flower[1]);
clutter_point_init (&p, 250, 50);
clutter_test_assert_actor_at_point (stage, &p, flower[2]);
}
static void
actor_margin_layout (void)
{
ClutterActor *stage = clutter_test_get_stage ();
ClutterActor *vase;
ClutterActor *flower[3];
ClutterPoint p;
vase = clutter_actor_new ();
clutter_actor_set_name (vase, "Vase");
clutter_actor_set_layout_manager (vase, clutter_box_layout_new ());
clutter_actor_add_child (stage, vase);
flower[0] = clutter_actor_new ();
clutter_actor_set_background_color (flower[0], CLUTTER_COLOR_Red);
clutter_actor_set_size (flower[0], 100, 100);
clutter_actor_set_name (flower[0], "Red Flower");
clutter_actor_add_child (vase, flower[0]);
flower[1] = clutter_actor_new ();
clutter_actor_set_background_color (flower[1], CLUTTER_COLOR_Yellow);
clutter_actor_set_size (flower[1], 100, 100);
clutter_actor_set_name (flower[1], "Yellow Flower");
clutter_actor_set_margin_right (flower[1], 6);
clutter_actor_set_margin_left (flower[1], 6);
clutter_actor_add_child (vase, flower[1]);
flower[2] = clutter_actor_new ();
clutter_actor_set_background_color (flower[2], CLUTTER_COLOR_Green);
clutter_actor_set_size (flower[2], 100, 100);
clutter_actor_set_name (flower[2], "Green Flower");
clutter_actor_set_margin_top (flower[2], 6);
clutter_actor_set_margin_bottom (flower[2], 6);
clutter_actor_add_child (vase, flower[2]);
clutter_point_init (&p, 0, 7);
clutter_test_assert_actor_at_point (stage, &p, flower[0]);
clutter_point_init (&p, 106, 50);
clutter_test_assert_actor_at_point (stage, &p, flower[1]);
clutter_point_init (&p, 212, 7);
clutter_test_assert_actor_at_point (stage, &p, flower[2]);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/layout/basic", actor_basic_layout)
CLUTTER_TEST_UNIT ("/actor/layout/margin", actor_margin_layout)
)

View File

@ -0,0 +1,40 @@
#include <stdlib.h>
#include <string.h>
#include <clutter/clutter.h>
static void
actor_meta_clear (void)
{
ClutterActor *actor, *stage;
stage = clutter_test_get_stage ();
actor = clutter_actor_new ();
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
clutter_actor_add_action (actor, clutter_click_action_new ());
clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_ALL, 0));
clutter_actor_add_effect (actor, clutter_blur_effect_new ());
g_assert (clutter_actor_has_actions (actor));
g_assert (clutter_actor_has_constraints (actor));
g_assert (clutter_actor_has_effects (actor));
clutter_actor_clear_actions (actor);
g_assert (!clutter_actor_has_actions (actor));
clutter_actor_clear_constraints (actor);
g_assert (!clutter_actor_has_constraints (actor));
clutter_actor_clear_effects (actor);
g_assert (!clutter_actor_has_effects (actor));
clutter_actor_destroy (actor);
g_assert (actor == NULL);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/meta/clear", actor_meta_clear)
)

View File

@ -0,0 +1,349 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
typedef struct _FooActor FooActor;
typedef struct _FooActorClass FooActorClass;
struct _FooActorClass
{
ClutterActorClass parent_class;
};
struct _FooActor
{
ClutterActor parent;
guint8 last_paint_opacity;
int paint_count;
};
typedef struct
{
ClutterActor *stage;
FooActor *foo_actor;
ClutterActor *parent_container;
ClutterActor *container;
ClutterActor *child;
ClutterActor *unrelated_actor;
gboolean was_painted;
} Data;
GType foo_actor_get_type (void) G_GNUC_CONST;
G_DEFINE_TYPE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR);
static gboolean group_has_overlaps;
static void
foo_actor_paint (ClutterActor *actor)
{
FooActor *foo_actor = (FooActor *) actor;
ClutterActorBox allocation;
foo_actor->last_paint_opacity = clutter_actor_get_paint_opacity (actor);
foo_actor->paint_count++;
clutter_actor_get_allocation_box (actor, &allocation);
/* Paint a red rectangle with the right opacity */
cogl_set_source_color4ub (255,
0,
0,
foo_actor->last_paint_opacity);
cogl_rectangle (allocation.x1,
allocation.y1,
allocation.x2,
allocation.y2);
}
static gboolean
foo_actor_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
return clutter_paint_volume_set_from_allocation (volume, actor);
}
static gboolean
foo_actor_has_overlaps (ClutterActor *actor)
{
return FALSE;
}
static void
foo_actor_class_init (FooActorClass *klass)
{
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
actor_class->paint = foo_actor_paint;
actor_class->get_paint_volume = foo_actor_get_paint_volume;
actor_class->has_overlaps = foo_actor_has_overlaps;
}
static void
foo_actor_init (FooActor *self)
{
}
typedef struct _FooGroup FooGroup;
typedef struct _FooGroupClass FooGroupClass;
struct _FooGroupClass
{
ClutterActorClass parent_class;
};
struct _FooGroup
{
ClutterActor parent;
};
GType foo_group_get_type (void);
G_DEFINE_TYPE (FooGroup, foo_group, CLUTTER_TYPE_ACTOR)
static gboolean
foo_group_has_overlaps (ClutterActor *actor)
{
return group_has_overlaps;
}
static void
foo_group_class_init (FooGroupClass *klass)
{
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
actor_class->has_overlaps = foo_group_has_overlaps;
}
static void
foo_group_init (FooGroup *self)
{
}
static void
verify_results (Data *data,
guint8 expected_color_red,
guint8 expected_color_green,
guint8 expected_color_blue,
int expected_paint_count,
int expected_paint_opacity)
{
guchar *pixel;
data->foo_actor->paint_count = 0;
/* Read a pixel at the center of the to determine what color it
painted. This should cause a redraw */
pixel = clutter_stage_read_pixels (CLUTTER_STAGE (data->stage),
50, 50, /* x/y */
1, 1 /* width/height */);
g_assert_cmpint (expected_paint_count, ==, data->foo_actor->paint_count);
g_assert_cmpint (expected_paint_opacity,
==,
data->foo_actor->last_paint_opacity);
g_assert_cmpint (ABS ((int) expected_color_red - (int) pixel[0]), <=, 2);
g_assert_cmpint (ABS ((int) expected_color_green - (int) pixel[1]), <=, 2);
g_assert_cmpint (ABS ((int) expected_color_blue - (int) pixel[2]), <=, 2);
g_free (pixel);
}
static void
verify_redraw (Data *data, int expected_paint_count)
{
GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
guint paint_handler;
paint_handler = g_signal_connect_data (data->stage,
"paint",
G_CALLBACK (g_main_loop_quit),
main_loop,
NULL,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
/* Queue a redraw on the stage */
clutter_actor_queue_redraw (data->stage);
data->foo_actor->paint_count = 0;
/* Wait for it to paint */
g_main_loop_run (main_loop);
g_signal_handler_disconnect (data->stage, paint_handler);
g_assert_cmpint (data->foo_actor->paint_count, ==, expected_paint_count);
}
static gboolean
verify_redraws (gpointer user_data)
{
Data *data = user_data;
/* Queueing a redraw on the actor should cause a redraw */
clutter_actor_queue_redraw (data->container);
verify_redraw (data, 1);
/* Queueing a redraw on a child should cause a redraw */
clutter_actor_queue_redraw (data->child);
verify_redraw (data, 1);
/* Modifying the transformation on the parent should not cause a redraw,
since the FBO stores pre-transformed rendering that can be reused with
any transformation. */
clutter_actor_set_anchor_point (data->parent_container, 0, 1);
verify_redraw (data, 0);
/* Redrawing an unrelated actor shouldn't cause a redraw */
clutter_actor_set_position (data->unrelated_actor, 0, 1);
verify_redraw (data, 0);
data->was_painted = TRUE;
return G_SOURCE_REMOVE;
}
static gboolean
run_verify (gpointer user_data)
{
Data *data = user_data;
group_has_overlaps = FALSE;
/* By default the actor shouldn't be redirected so the redraw should
cause the actor to be painted */
verify_results (data,
255, 0, 0,
1,
255);
/* Make the actor semi-transparent and verify the paint opacity */
clutter_actor_set_opacity (data->container, 127);
verify_results (data,
255, 127, 127,
1,
127);
/* With automatic redirect for opacity it shouldn't redirect if
* has_overlaps returns FALSE; */
clutter_actor_set_offscreen_redirect
(data->container, CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY);
verify_results (data,
255, 127, 127,
1,
127);
/* We do a double check here to verify that the actor wasn't cached
* during the last check. If it was cached then this check wouldn't
* result in any foo-actor re-paint. */
verify_results (data,
255, 127, 127,
1,
127);
/* With automatic redirect for opacity it should redirect if
* has_overlaps returns TRUE.
* The first paint will still cause the actor to draw because
* it needs to fill the cache first. It should be painted with full
* opacity */
group_has_overlaps = TRUE;
verify_results (data,
255, 127, 127,
1,
255);
/* The second time the actor is painted it should be cached */
verify_results (data,
255, 127, 127,
0,
255);
/* We should be able to change the opacity without causing the actor
to redraw */
clutter_actor_set_opacity (data->container, 64);
verify_results (data,
255, 191, 191,
0,
255);
/* Changing it back to fully opaque should cause it not to go
through the FBO so it will draw */
clutter_actor_set_opacity (data->container, 255);
verify_results (data,
255, 0, 0,
1,
255);
/* Tell it to always redirect through the FBO. This should cause a
paint of the actor because the last draw didn't go through the
FBO */
clutter_actor_set_offscreen_redirect (data->container,
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS);
verify_results (data,
255, 0, 0,
1,
255);
/* We should be able to change the opacity without causing the actor
to redraw */
clutter_actor_set_opacity (data->container, 64);
verify_results (data,
255, 191, 191,
0,
255);
/* Even changing it back to fully opaque shouldn't cause a redraw */
clutter_actor_set_opacity (data->container, 255);
verify_results (data,
255, 0, 0,
0,
255);
/* Check redraws */
g_idle_add (verify_redraws, data);
return G_SOURCE_REMOVE;
}
static void
actor_offscreen_redirect (void)
{
Data data = { 0 };
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
return;
data.stage = clutter_test_get_stage ();
data.parent_container = clutter_actor_new ();
data.container = g_object_new (foo_group_get_type (), NULL);
data.foo_actor = g_object_new (foo_actor_get_type (), NULL);
clutter_actor_set_size (CLUTTER_ACTOR (data.foo_actor), 100, 100);
clutter_actor_add_child (data.container, CLUTTER_ACTOR (data.foo_actor));
clutter_actor_add_child (data.parent_container, data.container);
clutter_actor_add_child (data.stage, data.parent_container);
data.child = clutter_actor_new ();
clutter_actor_set_size (data.child, 1, 1);
clutter_actor_add_child (data.container, data.child);
data.unrelated_actor = clutter_actor_new ();
clutter_actor_set_size (data.child, 1, 1);
clutter_actor_add_child (data.stage, data.unrelated_actor);
clutter_actor_show (data.stage);
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
run_verify,
&data,
NULL);
while (!data.was_painted)
g_main_context_iteration (NULL, FALSE);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/offscreen/redirect", actor_offscreen_redirect)
)

View File

@ -0,0 +1,141 @@
#include <clutter/clutter.h>
#include <stdlib.h>
static void
opacity_label (void)
{
ClutterActor *stage;
ClutterActor *label;
ClutterColor label_color = { 255, 0, 0, 128 };
ClutterColor color_check = { 0, };
stage = clutter_test_get_stage ();
label = clutter_text_new_with_text ("Sans 18px", "Label, 50% opacity");
clutter_text_set_color (CLUTTER_TEXT (label), &label_color);
if (g_test_verbose ())
g_print ("label 50%%.get_color()/1\n");
clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
clutter_actor_add_child (stage, label);
clutter_actor_set_position (label, 10, 10);
if (g_test_verbose ())
g_print ("label 50%%.get_color()/2\n");
clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
if (g_test_verbose ())
g_print ("label 50%%.get_paint_opacity()/1\n");
g_assert (clutter_actor_get_paint_opacity (label) == 255);
if (g_test_verbose ())
g_print ("label 50%%.get_paint_opacity()/2\n");
clutter_actor_set_opacity (label, 128);
g_assert (clutter_actor_get_paint_opacity (label) == 128);
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
opacity_rectangle (void)
{
ClutterActor *stage;
ClutterActor *rect;
ClutterColor rect_color = { 0, 0, 255, 255 };
ClutterColor color_check = { 0, };
stage = clutter_test_get_stage ();
rect = clutter_rectangle_new_with_color (&rect_color);
clutter_actor_set_size (rect, 128, 128);
clutter_actor_set_position (rect, 150, 90);
if (g_test_verbose ())
g_print ("rect 100%%.get_color()/1\n");
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
clutter_actor_add_child (stage, rect);
if (g_test_verbose ())
g_print ("rect 100%%.get_color()/2\n");
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
if (g_test_verbose ())
g_print ("rect 100%%.get_paint_opacity()\n");
g_assert (clutter_actor_get_paint_opacity (rect) == 255);
}
G_GNUC_END_IGNORE_DEPRECATIONS
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
opacity_paint (void)
{
ClutterActor *stage, *group1, *group2;
ClutterActor *label, *rect;
ClutterColor label_color = { 255, 0, 0, 128 };
ClutterColor rect_color = { 0, 0, 255, 255 };
ClutterColor color_check = { 0, };
stage = clutter_test_get_stage ();
group1 = clutter_group_new ();
clutter_actor_set_opacity (group1, 128);
clutter_container_add (CLUTTER_CONTAINER (stage), group1, NULL);
clutter_actor_set_position (group1, 10, 30);
clutter_actor_show (group1);
label = clutter_text_new_with_text ("Sans 18px", "Label+Group, 25% opacity");
clutter_text_set_color (CLUTTER_TEXT (label), &label_color);
if (g_test_verbose ())
g_print ("label 50%% + group 50%%.get_color()/1\n");
clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
clutter_container_add (CLUTTER_CONTAINER (group1), label, NULL);
if (g_test_verbose ())
g_print ("label 50%% + group 50%%.get_color()/2\n");
clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
if (g_test_verbose ())
g_print ("label 50%% + group 50%%.get_paint_opacity() = 128\n");
g_assert (clutter_actor_get_paint_opacity (label) == 128);
clutter_actor_destroy (label);
group2 = clutter_group_new ();
clutter_container_add (CLUTTER_CONTAINER (group1), group2, NULL);
clutter_actor_set_position (group2, 10, 60);
rect = clutter_rectangle_new_with_color (&rect_color);
clutter_actor_set_size (rect, 128, 128);
if (g_test_verbose ())
g_print ("rect 100%% + group 100%% + group 50%%.get_color()/1\n");
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
clutter_container_add (CLUTTER_CONTAINER (group2), rect, NULL);
if (g_test_verbose ())
g_print ("rect 100%% + group 100%% + group 50%%.get_color()/2\n");
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
if (g_test_verbose ())
g_print ("rect 100%%.get_paint_opacity()\n");
g_assert (clutter_actor_get_paint_opacity (rect) == 128);
}
G_GNUC_END_IGNORE_DEPRECATIONS
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/opacity/text", opacity_label)
CLUTTER_TEST_UNIT ("/actor/opacity/rectangle", opacity_rectangle)
CLUTTER_TEST_UNIT ("/actor/opacity/paint", opacity_paint)
)

View File

@ -0,0 +1,311 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#define STAGE_WIDTH 640
#define STAGE_HEIGHT 480
#define ACTORS_X 12
#define ACTORS_Y 16
#define SHIFT_STEP STAGE_WIDTH / ACTORS_X
typedef struct _State State;
struct _State
{
ClutterActor *stage;
int y, x;
ClutterActor *actors[ACTORS_X * ACTORS_Y];
guint actor_width, actor_height;
guint failed_pass;
guint failed_idx;
gboolean pass;
};
struct _ShiftEffect
{
ClutterShaderEffect parent_instance;
};
struct _ShiftEffectClass
{
ClutterShaderEffectClass parent_class;
};
typedef struct _ShiftEffect ShiftEffect;
typedef struct _ShiftEffectClass ShiftEffectClass;
#define TYPE_SHIFT_EFFECT (shift_effect_get_type ())
GType shift_effect_get_type (void);
G_DEFINE_TYPE (ShiftEffect,
shift_effect,
CLUTTER_TYPE_SHADER_EFFECT);
static void
shader_paint (ClutterEffect *effect,
ClutterEffectPaintFlags flags)
{
ClutterShaderEffect *shader = CLUTTER_SHADER_EFFECT (effect);
float tex_width;
ClutterActor *actor =
clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
if (g_test_verbose ())
g_debug ("shader_paint");
clutter_shader_effect_set_shader_source (shader,
"uniform sampler2D tex;\n"
"uniform float step;\n"
"void main (void)\n"
"{\n"
" cogl_color_out = texture2D(tex, vec2 (cogl_tex_coord_in[0].s + step,\n"
" cogl_tex_coord_in[0].t));\n"
"}\n");
tex_width = clutter_actor_get_width (actor);
clutter_shader_effect_set_uniform (shader, "tex", G_TYPE_INT, 1, 0);
clutter_shader_effect_set_uniform (shader, "step", G_TYPE_FLOAT, 1,
SHIFT_STEP / tex_width);
CLUTTER_EFFECT_CLASS (shift_effect_parent_class)->paint (effect, flags);
}
static void
shader_pick (ClutterEffect *effect,
ClutterEffectPaintFlags flags)
{
shader_paint (effect, flags);
}
static void
shift_effect_class_init (ShiftEffectClass *klass)
{
ClutterEffectClass *shader_class = CLUTTER_EFFECT_CLASS (klass);
shader_class->paint = shader_paint;
shader_class->pick = shader_pick;
}
static void
shift_effect_init (ShiftEffect *self)
{
}
static const char *test_passes[] = {
"No covering actor",
"Invisible covering actor",
"Clipped covering actor",
"Blur effect",
"Shift effect",
};
static gboolean
on_timeout (gpointer data)
{
State *state = data;
int test_num = 0;
int y, x;
ClutterActor *over_actor = NULL;
/* This will cause an unclipped pick redraw that will get buffered.
We'll check below that this buffer is discarded because we also need
to pick non-reactive actors */
clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage),
CLUTTER_PICK_REACTIVE, 10, 10);
clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage),
CLUTTER_PICK_REACTIVE, 10, 10);
for (test_num = 0; test_num < G_N_ELEMENTS (test_passes); test_num++)
{
if (test_num == 0)
{
if (g_test_verbose ())
g_print ("No covering actor:\n");
}
if (test_num == 1)
{
static const ClutterColor red = { 0xff, 0x00, 0x00, 0xff };
/* Create an actor that covers the whole stage but that
isn't visible so it shouldn't affect the picking */
over_actor = clutter_rectangle_new_with_color (&red);
clutter_actor_set_size (over_actor, STAGE_WIDTH, STAGE_HEIGHT);
clutter_actor_add_child (state->stage, over_actor);
clutter_actor_hide (over_actor);
if (g_test_verbose ())
g_print ("Invisible covering actor:\n");
}
else if (test_num == 2)
{
/* Make the actor visible but set a clip so that only some
of the actors are accessible */
clutter_actor_show (over_actor);
clutter_actor_set_clip (over_actor,
state->actor_width * 2,
state->actor_height * 2,
state->actor_width * (ACTORS_X - 4),
state->actor_height * (ACTORS_Y - 4));
if (g_test_verbose ())
g_print ("Clipped covering actor:\n");
}
else if (test_num == 3)
{
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
continue;
clutter_actor_hide (over_actor);
clutter_actor_add_effect_with_name (CLUTTER_ACTOR (state->stage),
"blur",
clutter_blur_effect_new ());
if (g_test_verbose ())
g_print ("With blur effect:\n");
}
else if (test_num == 4)
{
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
continue;
clutter_actor_hide (over_actor);
clutter_actor_remove_effect_by_name (CLUTTER_ACTOR (state->stage),
"blur");
clutter_actor_add_effect_with_name (CLUTTER_ACTOR (state->stage),
"shift",
g_object_new (TYPE_SHIFT_EFFECT,
NULL));
if (g_test_verbose ())
g_print ("With shift effect:\n");
}
for (y = 0; y < ACTORS_Y; y++)
{
if (test_num == 4)
x = 1;
else
x = 0;
for (; x < ACTORS_X; x++)
{
gboolean pass = FALSE;
gfloat pick_x;
ClutterActor *actor;
pick_x = x * state->actor_width + state->actor_width / 2;
if (test_num == 4)
pick_x -= SHIFT_STEP;
actor =
clutter_stage_get_actor_at_pos (CLUTTER_STAGE (state->stage),
CLUTTER_PICK_ALL,
pick_x,
y * state->actor_height
+ state->actor_height / 2);
if (g_test_verbose ())
g_print ("% 3i,% 3i / %p -> ",
x, y, state->actors[y * ACTORS_X + x]);
if (actor == NULL)
{
if (g_test_verbose ())
g_print ("NULL: FAIL\n");
}
else if (actor == over_actor)
{
if (test_num == 2
&& x >= 2 && x < ACTORS_X - 2
&& y >= 2 && y < ACTORS_Y - 2)
pass = TRUE;
if (g_test_verbose ())
g_print ("over_actor: %s\n", pass ? "pass" : "FAIL");
}
else
{
if (actor == state->actors[y * ACTORS_X + x]
&& (test_num != 2
|| x < 2 || x >= ACTORS_X - 2
|| y < 2 || y >= ACTORS_Y - 2))
pass = TRUE;
if (g_test_verbose ())
g_print ("%p: %s\n", actor, pass ? "pass" : "FAIL");
}
if (!pass)
{
state->failed_pass = test_num;
state->failed_idx = y * ACTORS_X + x;
state->pass = FALSE;
}
}
}
}
clutter_main_quit ();
return G_SOURCE_REMOVE;
}
static void
actor_pick (void)
{
int y, x;
State state;
state.pass = TRUE;
state.stage = clutter_test_get_stage ();
state.actor_width = STAGE_WIDTH / ACTORS_X;
state.actor_height = STAGE_HEIGHT / ACTORS_Y;
for (y = 0; y < ACTORS_Y; y++)
for (x = 0; x < ACTORS_X; x++)
{
ClutterColor color = { x * 255 / (ACTORS_X - 1),
y * 255 / (ACTORS_Y - 1),
128, 255 };
ClutterActor *rect = clutter_rectangle_new_with_color (&color);
clutter_actor_set_position (rect,
x * state.actor_width,
y * state.actor_height);
clutter_actor_set_size (rect,
state.actor_width,
state.actor_height);
clutter_actor_add_child (state.stage, rect);
state.actors[y * ACTORS_X + x] = rect;
}
clutter_actor_show (state.stage);
clutter_threads_add_idle (on_timeout, &state);
clutter_main ();
if (g_test_verbose ())
{
if (!state.pass)
g_test_message ("Failed pass: %s[%d], actor index: %d [%p]\n",
test_passes[state.failed_pass],
state.failed_pass,
state.failed_idx,
state.actors[state.failed_idx]);
}
g_assert (state.pass);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/pick", actor_pick)
)

View File

@ -0,0 +1,288 @@
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
/****************************************************************
Old style shader effect
This uses clutter_shader_effect_set_source
****************************************************************/
static const gchar
old_shader_effect_source[] =
"uniform vec3 override_color;\n"
"\n"
"void\n"
"main ()\n"
"{\n"
" cogl_color_out = vec4 (override_color, 1.0);\n"
"}";
typedef struct _FooOldShaderEffectClass
{
ClutterShaderEffectClass parent_class;
} FooOldShaderEffectClass;
typedef struct _FooOldShaderEffect
{
ClutterShaderEffect parent;
} FooOldShaderEffect;
GType foo_old_shader_effect_get_type (void);
G_DEFINE_TYPE (FooOldShaderEffect,
foo_old_shader_effect,
CLUTTER_TYPE_SHADER_EFFECT);
static void
foo_old_shader_effect_paint_target (ClutterOffscreenEffect *effect)
{
clutter_shader_effect_set_shader_source (CLUTTER_SHADER_EFFECT (effect),
old_shader_effect_source);
clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect),
"override_color",
G_TYPE_FLOAT, 3,
1.0f, 0.0f, 0.0f);
CLUTTER_OFFSCREEN_EFFECT_CLASS (foo_old_shader_effect_parent_class)->
paint_target (effect);
}
static void
foo_old_shader_effect_class_init (FooOldShaderEffectClass *klass)
{
ClutterOffscreenEffectClass *offscreen_effect_class =
CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_effect_class->paint_target = foo_old_shader_effect_paint_target;
}
static void
foo_old_shader_effect_init (FooOldShaderEffect *self)
{
}
/****************************************************************
New style shader effect
This overrides get_static_shader_source()
****************************************************************/
static const gchar
new_shader_effect_source[] =
"uniform vec3 override_color;\n"
"\n"
"void\n"
"main ()\n"
"{\n"
" cogl_color_out = (vec4 (override_color, 1.0) +\n"
" vec4 (0.0, 0.0, 1.0, 0.0));\n"
"}";
typedef struct _FooNewShaderEffectClass
{
ClutterShaderEffectClass parent_class;
} FooNewShaderEffectClass;
typedef struct _FooNewShaderEffect
{
ClutterShaderEffect parent;
} FooNewShaderEffect;
GType foo_new_shader_effect_get_type (void);
G_DEFINE_TYPE (FooNewShaderEffect,
foo_new_shader_effect,
CLUTTER_TYPE_SHADER_EFFECT);
static gchar *
foo_new_shader_effect_get_static_source (ClutterShaderEffect *effect)
{
static gboolean already_called = FALSE;
/* This should only be called once even though we have two actors
using this effect */
g_assert (!already_called);
already_called = TRUE;
return g_strdup (new_shader_effect_source);
}
static void
foo_new_shader_effect_paint_target (ClutterOffscreenEffect *effect)
{
clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect),
"override_color",
G_TYPE_FLOAT, 3,
0.0f, 1.0f, 0.0f);
CLUTTER_OFFSCREEN_EFFECT_CLASS (foo_new_shader_effect_parent_class)->
paint_target (effect);
}
static void
foo_new_shader_effect_class_init (FooNewShaderEffectClass *klass)
{
ClutterOffscreenEffectClass *offscreen_effect_class =
CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
ClutterShaderEffectClass *shader_effect_class =
CLUTTER_SHADER_EFFECT_CLASS (klass);
offscreen_effect_class->paint_target = foo_new_shader_effect_paint_target;
shader_effect_class->get_static_shader_source =
foo_new_shader_effect_get_static_source;
}
static void
foo_new_shader_effect_init (FooNewShaderEffect *self)
{
}
/****************************************************************
Another new style shader effect
This is the same but with a different shader. This is just
sanity check that each class gets its own copy of the private
data
****************************************************************/
static const gchar
another_new_shader_effect_source[] =
"\n"
"void\n"
"main ()\n"
"{\n"
" cogl_color_out = vec4 (1.0, 0.0, 1.0, 1.0);\n"
"}";
typedef struct _FooAnotherNewShaderEffectClass
{
ClutterShaderEffectClass parent_class;
} FooAnotherNewShaderEffectClass;
typedef struct _FooAnotherNewShaderEffect
{
ClutterShaderEffect parent;
} FooAnotherNewShaderEffect;
GType foo_another_new_shader_effect_get_type (void);
G_DEFINE_TYPE (FooAnotherNewShaderEffect,
foo_another_new_shader_effect,
CLUTTER_TYPE_SHADER_EFFECT);
static gchar *
foo_another_new_shader_effect_get_static_source (ClutterShaderEffect *effect)
{
return g_strdup (another_new_shader_effect_source);
}
static void
foo_another_new_shader_effect_class_init (FooAnotherNewShaderEffectClass *klass)
{
ClutterShaderEffectClass *shader_effect_class =
CLUTTER_SHADER_EFFECT_CLASS (klass);
shader_effect_class->get_static_shader_source =
foo_another_new_shader_effect_get_static_source;
}
static void
foo_another_new_shader_effect_init (FooAnotherNewShaderEffect *self)
{
}
/****************************************************************/
static ClutterActor *
make_actor (GType shader_type)
{
ClutterActor *rect;
const ClutterColor white = { 0xff, 0xff, 0xff, 0xff };
rect = clutter_rectangle_new ();
clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &white);
clutter_actor_set_size (rect, 50, 50);
clutter_actor_add_effect (rect, g_object_new (shader_type, NULL));
return rect;
}
static guint32
get_pixel (CoglFramebuffer *fb,
int x,
int y)
{
guint8 data[4];
cogl_framebuffer_read_pixels (fb,
x, y, 1, 1,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
data);
return (((guint32) data[0] << 16) |
((guint32) data[1] << 8) |
data[2]);
}
static void
view_painted_cb (ClutterStage *stage,
ClutterStageView *view,
gpointer data)
{
CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
gboolean *was_painted = data;
/* old shader effect */
g_assert_cmpint (get_pixel (fb, 0, 25), ==, 0xff0000);
/* new shader effect */
g_assert_cmpint (get_pixel (fb, 100, 25), ==, 0x00ffff);
/* another new shader effect */
g_assert_cmpint (get_pixel (fb, 200, 25), ==, 0xff00ff);
/* new shader effect */
g_assert_cmpint (get_pixel (fb, 300, 25), ==, 0x00ffff);
*was_painted = TRUE;
}
static void
actor_shader_effect (void)
{
ClutterActor *stage;
ClutterActor *rect;
gboolean was_painted;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
return;
stage = clutter_stage_new ();
rect = make_actor (foo_old_shader_effect_get_type ());
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
rect = make_actor (foo_new_shader_effect_get_type ());
clutter_actor_set_x (rect, 100);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
rect = make_actor (foo_another_new_shader_effect_get_type ());
clutter_actor_set_x (rect, 200);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
rect = make_actor (foo_new_shader_effect_get_type ());
clutter_actor_set_x (rect, 300);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
clutter_actor_show (stage);
was_painted = FALSE;
g_signal_connect_after (stage, "paint-view",
G_CALLBACK (view_painted_cb),
&was_painted);
while (!was_painted)
g_main_context_iteration (NULL, FALSE);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/shader-effect", actor_shader_effect)
)

View File

@ -0,0 +1,216 @@
#include <stdlib.h>
#include <string.h>
#include <clutter/clutter.h>
#define TEST_TYPE_ACTOR (test_actor_get_type ())
typedef struct _TestActor TestActor;
typedef struct _ClutterActorClass TestActorClass;
struct _TestActor
{
ClutterActor parent_instance;
guint preferred_width_called : 1;
guint preferred_height_called : 1;
};
GType test_actor_get_type (void);
G_DEFINE_TYPE (TestActor, test_actor, CLUTTER_TYPE_ACTOR);
static void
test_actor_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *nat_width_p)
{
TestActor *test = (TestActor *) self;
test->preferred_width_called = TRUE;
if (for_height == 10)
{
*min_width_p = 10;
*nat_width_p = 100;
}
else
{
*min_width_p = 100;
*nat_width_p = 100;
}
}
static void
test_actor_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *nat_height_p)
{
TestActor *test = (TestActor *) self;
test->preferred_height_called = TRUE;
if (for_width == 10)
{
*min_height_p = 50;
*nat_height_p = 100;
}
else
{
*min_height_p = 100;
*nat_height_p = 100;
}
}
static void
test_actor_class_init (TestActorClass *klass)
{
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->get_preferred_width = test_actor_get_preferred_width;
actor_class->get_preferred_height = test_actor_get_preferred_height;
}
static void
test_actor_init (TestActor *self)
{
}
static void
actor_preferred_size (void)
{
ClutterActor *test;
TestActor *self;
gfloat min_width, min_height;
gfloat nat_width, nat_height;
test = g_object_new (TEST_TYPE_ACTOR, NULL);
self = (TestActor *) test;
if (g_test_verbose ())
g_print ("Preferred size\n");
clutter_actor_get_preferred_size (test,
&min_width, &min_height,
&nat_width, &nat_height);
g_assert (self->preferred_width_called);
g_assert (self->preferred_height_called);
g_assert_cmpfloat (min_width, ==, 100);
g_assert_cmpfloat (min_height, ==, 100);
g_assert_cmpfloat (nat_width, ==, min_width);
g_assert_cmpfloat (nat_height, ==, min_height);
if (g_test_verbose ())
g_print ("Preferred width\n");
self->preferred_width_called = FALSE;
clutter_actor_get_preferred_width (test, 10, &min_width, &nat_width);
g_assert (self->preferred_width_called);
g_assert_cmpfloat (min_width, ==, 10);
g_assert_cmpfloat (nat_width, ==, 100);
if (g_test_verbose ())
g_print ("Preferred height\n");
self->preferred_height_called = FALSE;
clutter_actor_get_preferred_height (test, 200, &min_height, &nat_height);
g_assert (self->preferred_height_called);
g_assert_cmpfloat (min_height, !=, 10);
g_assert_cmpfloat (nat_height, ==, 100);
if (g_test_verbose ())
g_print ("Preferred width (cached)\n");
self->preferred_width_called = FALSE;
clutter_actor_get_preferred_width (test, 10, &min_width, &nat_width);
g_assert (!self->preferred_width_called);
g_assert_cmpfloat (min_width, ==, 10);
g_assert_cmpfloat (nat_width, ==, 100);
if (g_test_verbose ())
g_print ("Preferred height (cache eviction)\n");
self->preferred_height_called = FALSE;
clutter_actor_get_preferred_height (test, 10, &min_height, &nat_height);
g_assert (self->preferred_height_called);
g_assert_cmpfloat (min_height, ==, 50);
g_assert_cmpfloat (nat_height, ==, 100);
clutter_actor_destroy (test);
}
static void
actor_fixed_size (void)
{
ClutterActor *rect;
gboolean min_width_set, nat_width_set;
gboolean min_height_set, nat_height_set;
gfloat min_width, min_height;
gfloat nat_width, nat_height;
rect = clutter_actor_new ();
g_object_ref_sink (rect);
if (g_test_verbose ())
g_print ("Initial size is 0\n");
g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 0);
g_assert_cmpfloat (clutter_actor_get_height (rect), ==, 0);
clutter_actor_set_size (rect, 100, 100);
if (g_test_verbose ())
g_print ("Explicit size set\n");
g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 100);
g_assert_cmpfloat (clutter_actor_get_height (rect), ==, 100);
g_object_get (G_OBJECT (rect),
"min-width-set", &min_width_set,
"min-height-set", &min_height_set,
"natural-width-set", &nat_width_set,
"natural-height-set", &nat_height_set,
NULL);
if (g_test_verbose ())
g_print ("Notification properties\n");
g_assert (min_width_set && nat_width_set);
g_assert (min_height_set && nat_height_set);
clutter_actor_get_preferred_size (rect,
&min_width, &min_height,
&nat_width, &nat_height);
if (g_test_verbose ())
g_print ("Preferred size\n");
g_assert_cmpfloat (min_width, ==, 100);
g_assert_cmpfloat (min_height, ==, 100);
g_assert_cmpfloat (min_width, ==, nat_width);
g_assert_cmpfloat (min_height, ==, nat_height);
clutter_actor_set_size (rect, -1, -1);
if (g_test_verbose ())
g_print ("Explicit size unset\n");
g_object_get (G_OBJECT (rect),
"min-width-set", &min_width_set,
"min-height-set", &min_height_set,
"natural-width-set", &nat_width_set,
"natural-height-set", &nat_height_set,
NULL);
g_assert (!min_width_set && !nat_width_set);
g_assert (!min_height_set && !nat_height_set);
g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 0);
g_assert_cmpfloat (clutter_actor_get_height (rect), ==, 0);
clutter_actor_destroy (rect);
g_object_unref (rect);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/actor/size/preferred", actor_preferred_size)
CLUTTER_TEST_UNIT ("/actor/size/fixed", actor_fixed_size)
)

View File

@ -0,0 +1,80 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
static void
behaviour_opacity (void)
{
ClutterBehaviour *behaviour;
ClutterTimeline *timeline;
ClutterAlpha *alpha;
guint8 start, end;
guint starti;
timeline = clutter_timeline_new (500);
alpha = clutter_alpha_new_full (timeline, CLUTTER_LINEAR);
behaviour = clutter_behaviour_opacity_new (alpha, 0, 255);
g_assert (CLUTTER_IS_BEHAVIOUR_OPACITY (behaviour));
g_object_add_weak_pointer (G_OBJECT (behaviour), (gpointer *) &behaviour);
g_object_add_weak_pointer (G_OBJECT (timeline), (gpointer *) &timeline);
clutter_behaviour_opacity_get_bounds (CLUTTER_BEHAVIOUR_OPACITY (behaviour),
&start,
&end);
if (g_test_verbose ())
g_print ("BehaviourOpacity:bounds = %d, %d (expected: 0, 255)\n",
start,
end);
g_assert_cmpint (start, ==, 0);
g_assert_cmpint (end, ==, 255);
clutter_behaviour_opacity_set_bounds (CLUTTER_BEHAVIOUR_OPACITY (behaviour),
255,
0);
/* XXX: The gobject property is actually a unsigned int not unsigned char
* property so we have to be careful not to corrupt the stack by passing
* a guint8 pointer here... */
starti = 0;
g_object_get (G_OBJECT (behaviour), "opacity-start", &starti, NULL);
if (g_test_verbose ())
g_print ("BehaviourOpacity:start = %d (expected: 255)\n", start);
g_assert_cmpint (starti, ==, 255);
g_object_unref (behaviour);
g_object_unref (timeline);
g_assert_null (behaviour);
g_assert_null (timeline);
}
static struct
{
const gchar *path;
GTestFunc func;
} behaviour_tests[] = {
{ "opacity", behaviour_opacity },
};
static const int n_behaviour_tests = G_N_ELEMENTS (behaviour_tests);
int
main (int argc, char *argv[])
{
int i;
clutter_test_init (&argc, &argv);
for (i = 0; i < n_behaviour_tests; i++)
{
char *path = g_strconcat ("/behaviours/", behaviour_tests[i].path, NULL);
clutter_test_add (path, behaviour_tests[i].func);
g_free (path);
}
return clutter_test_run ();
}

View File

@ -0,0 +1,297 @@
#include <string.h>
#include <clutter/clutter.h>
#define TYPE_KEY_GROUP (key_group_get_type ())
#define KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_KEY_GROUP, KeyGroup))
#define IS_KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_KEY_GROUP))
#define KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_KEY_GROUP, KeyGroupClass))
#define IS_KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_KEY_GROUP))
typedef struct _KeyGroup KeyGroup;
typedef struct _KeyGroupClass KeyGroupClass;
struct _KeyGroup
{
ClutterActor parent_instance;
gint selected_index;
};
struct _KeyGroupClass
{
ClutterActorClass parent_class;
void (* activate) (KeyGroup *group,
ClutterActor *child);
};
GType key_group_get_type (void);
G_DEFINE_TYPE (KeyGroup, key_group, CLUTTER_TYPE_ACTOR)
enum
{
ACTIVATE,
LAST_SIGNAL
};
static guint group_signals[LAST_SIGNAL] = { 0, };
static gboolean
key_group_action_move_left (KeyGroup *self,
const gchar *action_name,
guint key_val,
ClutterModifierType modifiers)
{
gint n_children;
g_assert_cmpstr (action_name, ==, "move-left");
g_assert_cmpint (key_val, ==, CLUTTER_KEY_Left);
n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self));
self->selected_index -= 1;
if (self->selected_index < 0)
self->selected_index = n_children - 1;
return TRUE;
}
static gboolean
key_group_action_move_right (KeyGroup *self,
const gchar *action_name,
guint key_val,
ClutterModifierType modifiers)
{
gint n_children;
g_assert_cmpstr (action_name, ==, "move-right");
g_assert_cmpint (key_val, ==, CLUTTER_KEY_Right);
n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self));
self->selected_index += 1;
if (self->selected_index >= n_children)
self->selected_index = 0;
return TRUE;
}
static gboolean
key_group_action_activate (KeyGroup *self,
const gchar *action_name,
guint key_val,
ClutterModifierType modifiers)
{
ClutterActor *child = NULL;
g_assert_cmpstr (action_name, ==, "activate");
g_assert (key_val == CLUTTER_KEY_Return ||
key_val == CLUTTER_KEY_KP_Enter ||
key_val == CLUTTER_KEY_ISO_Enter);
if (self->selected_index == -1)
return FALSE;
child = clutter_actor_get_child_at_index (CLUTTER_ACTOR (self), self->selected_index);
if (child != NULL)
{
g_signal_emit (self, group_signals[ACTIVATE], 0, child);
return TRUE;
}
else
return FALSE;
}
static gboolean
key_group_key_press (ClutterActor *actor,
ClutterKeyEvent *event)
{
ClutterBindingPool *pool;
gboolean res;
pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));
g_assert (pool != NULL);
res = clutter_binding_pool_activate (pool,
event->keyval,
event->modifier_state,
G_OBJECT (actor));
/* if we activate a key binding, redraw the actor */
if (res)
clutter_actor_queue_redraw (actor);
return res;
}
static void
key_group_paint (ClutterActor *actor)
{
KeyGroup *self = KEY_GROUP (actor);
ClutterActorIter iter;
ClutterActor *child;
gint i = 0;
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
{
/* paint the selection rectangle */
if (i == self->selected_index)
{
ClutterActorBox box = { 0, };
clutter_actor_get_allocation_box (child, &box);
box.x1 -= 2;
box.y1 -= 2;
box.x2 += 2;
box.y2 += 2;
cogl_set_source_color4ub (255, 255, 0, 224);
cogl_rectangle (box.x1, box.y1, box.x2, box.y2);
}
clutter_actor_paint (child);
}
}
static void
key_group_class_init (KeyGroupClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
ClutterBindingPool *binding_pool;
actor_class->paint = key_group_paint;
actor_class->key_press_event = key_group_key_press;
group_signals[ACTIVATE] =
g_signal_new (g_intern_static_string ("activate"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (KeyGroupClass, activate),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
CLUTTER_TYPE_ACTOR);
binding_pool = clutter_binding_pool_get_for_class (klass);
clutter_binding_pool_install_action (binding_pool, "move-right",
CLUTTER_KEY_Right, 0,
G_CALLBACK (key_group_action_move_right),
NULL, NULL);
clutter_binding_pool_install_action (binding_pool, "move-left",
CLUTTER_KEY_Left, 0,
G_CALLBACK (key_group_action_move_left),
NULL, NULL);
clutter_binding_pool_install_action (binding_pool, "activate",
CLUTTER_KEY_Return, 0,
G_CALLBACK (key_group_action_activate),
NULL, NULL);
clutter_binding_pool_install_action (binding_pool, "activate",
CLUTTER_KEY_KP_Enter, 0,
G_CALLBACK (key_group_action_activate),
NULL, NULL);
clutter_binding_pool_install_action (binding_pool, "activate",
CLUTTER_KEY_ISO_Enter, 0,
G_CALLBACK (key_group_action_activate),
NULL, NULL);
}
static void
key_group_init (KeyGroup *self)
{
self->selected_index = -1;
}
static void
init_event (ClutterKeyEvent *event)
{
event->type = CLUTTER_KEY_PRESS;
event->time = 0; /* not needed */
event->flags = CLUTTER_EVENT_FLAG_SYNTHETIC;
event->stage = NULL; /* not needed */
event->source = NULL; /* not needed */
event->modifier_state = 0;
event->hardware_keycode = 0; /* not needed */
}
static void
send_keyval (KeyGroup *group, int keyval)
{
ClutterKeyEvent event;
init_event (&event);
event.keyval = keyval;
event.unicode_value = 0; /* should be ignored for cursor keys etc. */
clutter_actor_event (CLUTTER_ACTOR (group), (ClutterEvent *) &event, FALSE);
}
static void
on_activate (KeyGroup *key_group,
ClutterActor *child,
gpointer data)
{
gint _index = GPOINTER_TO_INT (data);
g_assert_cmpint (key_group->selected_index, ==, _index);
}
static void
binding_pool (void)
{
KeyGroup *key_group = g_object_new (TYPE_KEY_GROUP, NULL);
g_object_ref_sink (key_group);
clutter_actor_add_child (CLUTTER_ACTOR (key_group),
g_object_new (CLUTTER_TYPE_ACTOR,
"width", 50.0,
"height", 50.0,
"x", 0.0, "y", 0.0,
NULL));
clutter_actor_add_child (CLUTTER_ACTOR (key_group),
g_object_new (CLUTTER_TYPE_ACTOR,
"width", 50.0,
"height", 50.0,
"x", 75.0, "y", 0.0,
NULL));
clutter_actor_add_child (CLUTTER_ACTOR (key_group),
g_object_new (CLUTTER_TYPE_ACTOR,
"width", 50.0,
"height", 50.0,
"x", 150.0, "y", 0.0,
NULL));
g_assert_cmpint (key_group->selected_index, ==, -1);
send_keyval (key_group, CLUTTER_KEY_Left);
g_assert_cmpint (key_group->selected_index, ==, 2);
send_keyval (key_group, CLUTTER_KEY_Left);
g_assert_cmpint (key_group->selected_index, ==, 1);
send_keyval (key_group, CLUTTER_KEY_Right);
g_assert_cmpint (key_group->selected_index, ==, 2);
send_keyval (key_group, CLUTTER_KEY_Right);
g_assert_cmpint (key_group->selected_index, ==, 0);
g_signal_connect (key_group,
"activate", G_CALLBACK (on_activate),
GINT_TO_POINTER (0));
send_keyval (key_group, CLUTTER_KEY_Return);
clutter_actor_destroy (CLUTTER_ACTOR (key_group));
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/binding-pool", binding_pool)
)

View File

@ -0,0 +1,198 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
#define BLOCK_SIZE 16
/* Number of pixels at the border of a block to skip when verifying */
#define TEST_INSET 1
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
typedef enum
{
/* The first frame is drawn using clutter_cairo_texture_create. The
second frame is an update of the first frame using
clutter_cairo_texture_create_region. The states are stored like
this because the cairo drawing is done on idle and the validation
is done during paint and we need to synchronize the two */
TEST_BEFORE_DRAW_FIRST_FRAME,
TEST_BEFORE_VALIDATE_FIRST_FRAME,
TEST_BEFORE_DRAW_SECOND_FRAME,
TEST_BEFORE_VALIDATE_SECOND_FRAME,
TEST_DONE
} TestProgress;
typedef struct _TestState
{
ClutterActor *stage;
ClutterActor *ct;
guint frame;
TestProgress progress;
} TestState;
static void
validate_part (int block_x, int block_y, const ClutterColor *color)
{
guint8 data[BLOCK_SIZE * BLOCK_SIZE * 4];
int x, y;
cogl_read_pixels (block_x * BLOCK_SIZE,
block_y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE,
COGL_READ_PIXELS_COLOR_BUFFER,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
data);
for (x = 0; x < BLOCK_SIZE - TEST_INSET * 2; x++)
for (y = 0; y < BLOCK_SIZE - TEST_INSET * 2; y++)
{
const guint8 *p = data + ((x + TEST_INSET) * 4 +
(y + TEST_INSET) * BLOCK_SIZE * 4);
g_assert_cmpint (p[0], ==, color->red);
g_assert_cmpint (p[1], ==, color->green);
g_assert_cmpint (p[2], ==, color->blue);
}
}
static void
paint_cb (ClutterActor *actor, TestState *state)
{
static const ClutterColor red = { 0xff, 0x00, 0x00, 0xff };
static const ClutterColor green = { 0x00, 0xff, 0x00, 0xff };
static const ClutterColor blue = { 0x00, 0x00, 0xff, 0xff };
if (state->frame++ < 2)
return;
switch (state->progress)
{
case TEST_BEFORE_DRAW_FIRST_FRAME:
case TEST_BEFORE_DRAW_SECOND_FRAME:
case TEST_DONE:
/* Handled by the idle callback */
break;
case TEST_BEFORE_VALIDATE_FIRST_FRAME:
/* In the first frame there is a red rectangle next to a green
rectangle */
validate_part (0, 0, &red);
validate_part (1, 0, &green);
state->progress = TEST_BEFORE_DRAW_SECOND_FRAME;
break;
case TEST_BEFORE_VALIDATE_SECOND_FRAME:
/* The second frame is the same except the green rectangle is
replaced with a blue one */
validate_part (0, 0, &red);
validate_part (1, 0, &blue);
state->progress = TEST_DONE;
break;
}
}
static gboolean
idle_cb (gpointer data)
{
TestState *state = data;
cairo_t *cr;
if (state->frame < 2)
clutter_actor_queue_redraw (CLUTTER_ACTOR (state->stage));
else
switch (state->progress)
{
case TEST_BEFORE_DRAW_FIRST_FRAME:
/* Draw two different colour rectangles */
cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (state->ct));
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_save (cr);
cairo_rectangle (cr, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
cairo_clip (cr);
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
cairo_paint (cr);
cairo_restore (cr);
cairo_rectangle (cr, BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE);
cairo_clip (cr);
cairo_set_source_rgb (cr, 0.0, 1.0, 0.0);
cairo_paint (cr);
cairo_restore (cr);
cairo_destroy (cr);
state->progress = TEST_BEFORE_VALIDATE_FIRST_FRAME;
break;
case TEST_BEFORE_DRAW_SECOND_FRAME:
/* Replace the second rectangle with a blue one */
cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (state->ct));
cairo_rectangle (cr, BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE);
cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
cairo_fill (cr);
cairo_destroy (cr);
state->progress = TEST_BEFORE_VALIDATE_SECOND_FRAME;
break;
case TEST_BEFORE_VALIDATE_FIRST_FRAME:
case TEST_BEFORE_VALIDATE_SECOND_FRAME:
/* Handled by the paint callback */
break;
case TEST_DONE:
clutter_main_quit ();
break;
}
return G_SOURCE_CONTINUE;
}
void
texture_cairo (TestConformSimpleFixture *fixture,
gconstpointer data)
{
TestState state;
unsigned int idle_source;
unsigned int paint_handler;
state.frame = 0;
state.stage = clutter_stage_new ();
state.progress = TEST_BEFORE_DRAW_FIRST_FRAME;
state.ct = clutter_cairo_texture_new (BLOCK_SIZE * 2, BLOCK_SIZE);
clutter_container_add_actor (CLUTTER_CONTAINER (state.stage), state.ct);
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
/* We force continuous redrawing of the stage, since we need to skip
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
idle_source = clutter_threads_add_idle (idle_cb, &state);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (paint_cb), &state);
clutter_actor_show (state.stage);
clutter_main ();
g_signal_handler_disconnect (state.stage, paint_handler);
g_source_remove (idle_source);
if (g_test_verbose ())
g_print ("OK\n");
clutter_actor_destroy (state.stage);
}

View File

@ -0,0 +1,338 @@
#include <clutter/clutter.h>
#include <string.h>
#include <stdlib.h>
#include "test-conform-common.h"
#define TEST_FONT "Sans 10"
typedef struct _CallbackData CallbackData;
struct _CallbackData
{
ClutterActor *stage;
ClutterActor *label;
gint offset;
gboolean test_failed;
gint extents_x;
gint extents_y;
gint extents_width;
gint extents_height;
GSList *run_attributes;
GSList *default_attributes;
CallbackData *next;
};
static gint
attribute_lookup_func (gconstpointer data,
gconstpointer user_data)
{
AtkAttribute *lookup_attr = (AtkAttribute*) user_data;
AtkAttribute *at = (AtkAttribute *) data;
if (!data)
return -1;
if (!g_strcmp0 (at->name, lookup_attr->name))
return g_strcmp0 (at->value, lookup_attr->value);
return -1;
}
/* check l1 is a sub-set of l2 */
static gboolean
compare_lists (GSList* l1, GSList* l2)
{
gboolean fail = FALSE;
if (l2 && !l1)
return TRUE;
while (l1)
{
AtkAttribute *at = (AtkAttribute *) l1->data;
GSList* result = g_slist_find_custom ((GSList*) l2,
(gconstpointer) at,
attribute_lookup_func);
if (!result)
{
fail = TRUE;
break;
}
l1 = g_slist_next (l1);
}
return fail;
}
static void
dump_attribute_set (AtkAttributeSet *at_set)
{
GSList *attrs = (GSList*) at_set;
while (attrs) {
AtkAttribute *at = (AtkAttribute *) attrs->data;
g_print ("text attribute %s = %s\n", at->name, at->value);
attrs = g_slist_next (attrs);
}
}
static gboolean
check_result (CallbackData *data)
{
gboolean fail = FALSE;
gchar *text = NULL;
const gchar *expected_text = NULL;
AtkObject *object = NULL;
AtkText *cally_text = NULL;
gunichar unichar;
gunichar expected_char;
gint x, y, width, height;
gint pos;
AtkAttributeSet *at_set = NULL;
GSList *attrs;
gint start = -1;
gint end = -1;
object = atk_gobject_accessible_for_object (G_OBJECT (data->label));
cally_text = ATK_TEXT (object);
if (!cally_text) {
g_print("no text\n");
return TRUE;
}
text = atk_text_get_text (cally_text, 0, -1);
expected_text = clutter_text_get_text (CLUTTER_TEXT (data->label));
if (g_strcmp0 (expected_text, text) != 0)
{
if (g_test_verbose ())
g_print ("text value differs %s vs %s\n", expected_text, text);
fail = TRUE;
}
unichar = atk_text_get_character_at_offset (cally_text, data->offset);
expected_char = g_utf8_get_char (g_utf8_offset_to_pointer (text, data->offset));
if (expected_char != unichar)
{
if (g_test_verbose ())
g_print ("text af offset differs\n");
fail = TRUE;
}
atk_text_get_character_extents (cally_text, data->offset, &x, &y, &width, &height,
ATK_XY_WINDOW);
if (x != data->extents_x)
{
if (g_test_verbose ())
g_print ("extents x position at index 0 differs (current value=%d)\n", x);
fail = TRUE;
}
if (y != data->extents_y)
{
if (g_test_verbose ())
g_print ("extents y position at index 0 differs (current value=%d)\n", y);
fail = TRUE;
}
if (width != data->extents_width)
{
if (g_test_verbose ())
g_print ("extents width at index 0 differs (current value=%d)\n", width);
fail = TRUE;
}
if (height != data->extents_height)
{
if (g_test_verbose ())
g_print ("extents height at index 0 differs (current value=%d)\n", height);
fail = TRUE;
}
pos = atk_text_get_offset_at_point (cally_text, x, y, ATK_XY_WINDOW);
if (pos != data->offset)
{
if (g_test_verbose ())
g_print ("offset at position (%d, %d) differs (current value=%d)\n", x,
y, pos);
fail = TRUE;
}
at_set = atk_text_get_run_attributes (cally_text, 0,
&start, &end);
if (start != 0)
{
if (g_test_verbose ())
g_print ("run attributes start offset is not 0: %d\n", start);
fail = TRUE;
}
if (end != g_utf8_strlen (text, -1))
{
if (g_test_verbose ())
g_print ("run attributes end offset is not text length: %d\n", end);
fail = TRUE;
}
attrs = (GSList*) at_set;
fail = compare_lists (attrs, data->run_attributes);
if (fail && g_test_verbose ())
{
g_print ("run attributes mismatch\n");
dump_attribute_set (attrs);
}
at_set = atk_text_get_default_attributes (cally_text);
attrs = (GSList*) at_set;
fail = compare_lists (attrs, data->default_attributes);
if (fail && g_test_verbose ())
{
g_print ("default attributes mismatch\n");
dump_attribute_set (attrs);
}
g_free (text);
text = NULL;
if (fail)
{
if (g_test_verbose ())
g_print ("FAIL\n");
data->test_failed = TRUE;
}
else if (g_test_verbose ())
g_print ("pass\n");
return fail;
}
static gboolean
do_tests (CallbackData *data)
{
while (data)
{
gboolean result = check_result (data);
g_assert (result == FALSE);
data = data->next;
}
clutter_main_quit ();
return FALSE;
}
static GSList*
build_attribute_set (const gchar* first_attribute, ...)
{
AtkAttributeSet *return_set = g_slist_alloc ();
va_list args;
const gchar *name;
const gchar *value;
gint i = 0;
value = first_attribute;
va_start (args, first_attribute);
while (value)
{
if ((i> 0) && (i % 2 != 0))
{
AtkAttribute *at = g_malloc (sizeof (AtkAttribute));
at->name = g_strdup (name);
at->value = g_strdup (value);
return_set = g_slist_prepend (return_set, at);
}
i++;
name = g_strdup (value);
value = va_arg (args, gchar*);
}
va_end (args);
return return_set;
}
void
cally_text (void)
{
CallbackData data;
CallbackData data1;
GSList* default_attributes = build_attribute_set ("left-margin", "0",
"right-margin", "0",
"indent", "0",
"invisible", "false",
"editable", "false",
"pixels-above-lines", "0",
"pixels-below-lines", "0",
"pixels-inside-wrap", "0",
"bg-full-height", "0",
"bg-stipple", "false",
"fg-stipple", "false",
"fg-color", "0,0,0",
"wrap-mode", "word",
"justification", "left",
"size", "10",
"weight", "400",
"family-name", "Sans",
"stretch", "normal",
"variant", "normal",
"style", "normal",
"language", "en-us",
"direction", "ltr",
NULL);
memset (&data, 0, sizeof (data));
data.stage = clutter_stage_new ();
data.default_attributes = default_attributes;
data.run_attributes = build_attribute_set ("fg-color", "0,0,0", NULL);
data.label = clutter_text_new_with_text (TEST_FONT, "Lorem ipsum dolor sit amet");
clutter_container_add (CLUTTER_CONTAINER (data.stage), data.label, NULL);
data.offset = 6;
data.extents_x = 64;
data.extents_y = 99;
data.extents_width = 3;
data.extents_height = 17;
clutter_actor_set_position (data.label, 20, 100);
memset (&data1, 0, sizeof (data1));
data1.stage = data.stage;
data1.default_attributes = default_attributes;
data1.run_attributes = build_attribute_set ("bg-color", "0,65535,0",
"fg-color", "65535,65535,0",
"strikethrough", "true", NULL);
data1.label = clutter_text_new_with_text (TEST_FONT, "");
clutter_text_set_markup (CLUTTER_TEXT(data1.label), "<span fgcolor=\"#FFFF00\" bgcolor=\"#00FF00\"><s>Lorem ipsum dolor sit amet</s></span>");
clutter_container_add (CLUTTER_CONTAINER (data1.stage), data1.label, NULL);
data1.offset = 10;
data1.extents_x = 90;
data1.extents_y = 199;
data1.extents_width = 13;
data1.extents_height = 17;
clutter_actor_set_position (data1.label, 20, 200);
data.next = &data1;
clutter_actor_show (data.stage);
clutter_threads_add_idle ((GSourceFunc) do_tests, &data);
clutter_main ();
clutter_actor_destroy (data.stage);
if (g_test_verbose ())
g_print ("\nOverall result: ");
if (g_test_verbose ())
{
if (data.test_failed)
g_print ("FAIL\n");
else
g_print ("pass\n");
}
else
{
g_assert (data.test_failed != TRUE);
g_assert (data1.test_failed != TRUE);
}
}

View File

@ -0,0 +1,319 @@
#include <clutter/clutter.h>
static void
color_hls_roundtrip (void)
{
ClutterColor color;
gfloat hue, luminance, saturation;
/* test luminance only */
clutter_color_from_string (&color, "#7f7f7f");
g_assert_cmpuint (color.red, ==, 0x7f);
g_assert_cmpuint (color.green, ==, 0x7f);
g_assert_cmpuint (color.blue, ==, 0x7f);
clutter_color_to_hls (&color, &hue, &luminance, &saturation);
g_assert_cmpfloat (hue, ==, 0.0);
g_assert (luminance >= 0.0 && luminance <= 1.0);
g_assert_cmpfloat (saturation, ==, 0.0);
if (g_test_verbose ())
{
g_print ("RGB = { %x, %x, %x }, HLS = { %.2f, %.2f, %.2f }\n",
color.red,
color.green,
color.blue,
hue,
luminance,
saturation);
}
color.red = color.green = color.blue = 0;
clutter_color_from_hls (&color, hue, luminance, saturation);
g_assert_cmpuint (color.red, ==, 0x7f);
g_assert_cmpuint (color.green, ==, 0x7f);
g_assert_cmpuint (color.blue, ==, 0x7f);
/* full conversion */
clutter_color_from_string (&color, "#7f8f7f");
color.alpha = 255;
g_assert_cmpuint (color.red, ==, 0x7f);
g_assert_cmpuint (color.green, ==, 0x8f);
g_assert_cmpuint (color.blue, ==, 0x7f);
clutter_color_to_hls (&color, &hue, &luminance, &saturation);
g_assert (hue >= 0.0 && hue < 360.0);
g_assert (luminance >= 0.0 && luminance <= 1.0);
g_assert (saturation >= 0.0 && saturation <= 1.0);
if (g_test_verbose ())
{
g_print ("RGB = { %x, %x, %x }, HLS = { %.2f, %.2f, %.2f }\n",
color.red,
color.green,
color.blue,
hue,
luminance,
saturation);
}
color.red = color.green = color.blue = 0;
clutter_color_from_hls (&color, hue, luminance, saturation);
g_assert_cmpuint (color.red, ==, 0x7f);
g_assert_cmpuint (color.green, ==, 0x8f);
g_assert_cmpuint (color.blue, ==, 0x7f);
/* the alpha channel should be untouched */
g_assert_cmpuint (color.alpha, ==, 255);
}
static void
color_from_string_invalid (void)
{
ClutterColor color;
g_assert (!clutter_color_from_string (&color, "ff0000ff"));
g_assert (!clutter_color_from_string (&color, "#decaffbad"));
g_assert (!clutter_color_from_string (&color, "ponies"));
g_assert (!clutter_color_from_string (&color, "rgb(255, 0, 0, 0)"));
g_assert (!clutter_color_from_string (&color, "rgba(1.0, 0, 0)"));
g_assert (!clutter_color_from_string (&color, "hsl(100, 0, 0)"));
g_assert (!clutter_color_from_string (&color, "hsla(10%, 0%, 50%)"));
g_assert (!clutter_color_from_string (&color, "hsla(100%, 0%, 50%, 20%)"));
g_assert (!clutter_color_from_string (&color, "hsla(0.5, 0.9, 0.2, 0.4)"));
}
static void
color_from_string_valid (void)
{
ClutterColor color;
g_assert (clutter_color_from_string (&color, "#ff0000ff"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0xff, 0, 0, 0xff }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert_cmpuint (color.red, ==, 0xff);
g_assert_cmpuint (color.green, ==, 0);
g_assert_cmpuint (color.blue, ==, 0);
g_assert_cmpuint (color.alpha, ==, 0xff);
g_assert (clutter_color_from_string (&color, "#0f0f"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0xff, 0, 0xff }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert_cmpuint (color.red, ==, 0);
g_assert_cmpuint (color.green, ==, 0xff);
g_assert_cmpuint (color.blue, ==, 0);
g_assert_cmpuint (color.alpha, ==, 0xff);
g_assert (clutter_color_from_string (&color, "#0000ff"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0, 0xff, 0xff }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert_cmpuint (color.red, ==, 0);
g_assert_cmpuint (color.green, ==, 0);
g_assert_cmpuint (color.blue, ==, 0xff);
g_assert_cmpuint (color.alpha, ==, 0xff);
g_assert (clutter_color_from_string (&color, "#abc"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0xaa, 0xbb, 0xcc, 0xff }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert_cmpuint (color.red, ==, 0xaa);
g_assert_cmpuint (color.green, ==, 0xbb);
g_assert_cmpuint (color.blue, ==, 0xcc);
g_assert_cmpuint (color.alpha, ==, 0xff);
g_assert (clutter_color_from_string (&color, "#123abc"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0x12, 0x3a, 0xbc, 0xff }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert (color.red == 0x12);
g_assert (color.green == 0x3a);
g_assert (color.blue == 0xbc);
g_assert (color.alpha == 0xff);
g_assert (clutter_color_from_string (&color, "rgb(255, 128, 64)"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 255, 128, 64, 255 }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert_cmpuint (color.red, ==, 255);
g_assert_cmpuint (color.green, ==, 128);
g_assert_cmpuint (color.blue, ==, 64);
g_assert_cmpuint (color.alpha, ==, 255);
g_assert (clutter_color_from_string (&color, "rgba ( 30%, 0, 25%, 0.5 ) "));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { %.1f, 0, %.1f, 128 }\n",
color.red,
color.green,
color.blue,
color.alpha,
CLAMP (255.0 / 100.0 * 30.0, 0, 255),
CLAMP (255.0 / 100.0 * 25.0, 0, 255));
}
g_assert_cmpuint (color.red, ==, (255.0 / 100.0 * 30.0));
g_assert_cmpuint (color.green, ==, 0);
g_assert_cmpuint (color.blue, ==, (255.0 / 100.0 * 25.0));
g_assert_cmpuint (color.alpha, ==, 127);
g_assert (clutter_color_from_string (&color, "rgb( 50%, -50%, 150% )"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 127, 0, 255, 255 }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert_cmpuint (color.red, ==, 127);
g_assert_cmpuint (color.green, ==, 0);
g_assert_cmpuint (color.blue, ==, 255);
g_assert_cmpuint (color.alpha, ==, 255);
g_assert (clutter_color_from_string (&color, "hsl( 0, 100%, 50% )"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 255, 0, 0, 255 }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert_cmpuint (color.red, ==, 255);
g_assert_cmpuint (color.green, ==, 0);
g_assert_cmpuint (color.blue, ==, 0);
g_assert_cmpuint (color.alpha, ==, 255);
g_assert (clutter_color_from_string (&color, "hsl( 0, 100%, 50% )"));
g_assert (clutter_color_from_string (&color, "hsla( 0, 100%, 50%, 0.5 )"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 255, 0, 0, 127 }\n",
color.red,
color.green,
color.blue,
color.alpha);
}
g_assert_cmpuint (color.red, ==, 255);
g_assert_cmpuint (color.green, ==, 0);
g_assert_cmpuint (color.blue, ==, 0);
g_assert_cmpuint (color.alpha, ==, 127);
g_test_bug ("662818");
g_assert (clutter_color_from_string (&color, "hsla(0,100%,50% , 0.5)"));
}
static void
color_to_string (void)
{
ClutterColor color;
gchar *str;
color.red = 0xcc;
color.green = 0xcc;
color.blue = 0xcc;
color.alpha = 0x22;
str = clutter_color_to_string (&color);
g_assert_cmpstr (str, ==, "#cccccc22");
g_free (str);
}
static void
color_operators (void)
{
ClutterColor op1, op2;
ClutterColor res;
clutter_color_from_pixel (&op1, 0xff0000ff);
g_assert_cmpuint (op1.red, ==, 0xff);
g_assert_cmpuint (op1.green, ==, 0);
g_assert_cmpuint (op1.blue, ==, 0);
g_assert_cmpuint (op1.alpha, ==, 0xff);
clutter_color_from_pixel (&op2, 0x00ff00ff);
g_assert_cmpuint (op2.red, ==, 0);
g_assert_cmpuint (op2.green, ==, 0xff);
g_assert_cmpuint (op2.blue, ==, 0);
g_assert_cmpuint (op2.alpha, ==, 0xff);
if (g_test_verbose ())
g_print ("Adding %x, %x; expected result: %x\n",
clutter_color_to_pixel (&op1),
clutter_color_to_pixel (&op2),
0xffff00ff);
clutter_color_add (&op1, &op2, &res);
g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0xffff00ff);
if (g_test_verbose ())
g_print ("Checking alpha channel on color add\n");
op1.alpha = 0xdd;
op2.alpha = 0xcc;
clutter_color_add (&op1, &op2, &res);
g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0xffff00dd);
clutter_color_from_pixel (&op1, 0xffffffff);
clutter_color_from_pixel (&op2, 0xff00ffff);
if (g_test_verbose ())
g_print ("Subtracting %x, %x; expected result: %x\n",
clutter_color_to_pixel (&op1),
clutter_color_to_pixel (&op2),
0x00ff00ff);
clutter_color_subtract (&op1, &op2, &res);
g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0x00ff00ff);
if (g_test_verbose ())
g_print ("Checking alpha channel on color subtract\n");
op1.alpha = 0xdd;
op2.alpha = 0xcc;
clutter_color_subtract (&op1, &op2, &res);
g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0x00ff00cc);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/color/hls-roundtrip", color_hls_roundtrip)
CLUTTER_TEST_UNIT ("/color/from-string/invalid", color_from_string_invalid)
CLUTTER_TEST_UNIT ("/color/from-string/valid", color_from_string_valid)
CLUTTER_TEST_UNIT ("/color/to-string", color_to_string)
CLUTTER_TEST_UNIT ("/color/operators", color_operators)
)

View File

@ -0,0 +1,60 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
static void
group_depth_sorting (void)
{
ClutterActor *group;
ClutterActor *child, *test;
ClutterGroup *g;
GList *children;
group = clutter_group_new ();
g = CLUTTER_GROUP (group);
child = clutter_rectangle_new ();
clutter_actor_set_size (child, 20, 20);
clutter_actor_set_depth (child, 0);
clutter_actor_set_name (child, "zero");
clutter_container_add_actor (CLUTTER_CONTAINER (group), child);
children = clutter_container_get_children (CLUTTER_CONTAINER (group));
g_assert (children->data == child);
g_assert (children->next == NULL);
g_list_free (children);
child = clutter_rectangle_new ();
clutter_actor_set_size (child, 20, 20);
clutter_actor_set_depth (child, 10);
clutter_actor_set_name (child, "plus-ten");
clutter_container_add_actor (CLUTTER_CONTAINER (group), child);
test = clutter_group_get_nth_child (g, 0);
g_assert_cmpstr (clutter_actor_get_name (test), ==, "zero");
test = clutter_group_get_nth_child (g, 1);
g_assert_cmpstr (clutter_actor_get_name (test), ==, "plus-ten");
child = clutter_rectangle_new ();
clutter_actor_set_size (child, 20, 20);
clutter_actor_set_depth (child, -10);
clutter_actor_set_name (child, "minus-ten");
clutter_container_add_actor (CLUTTER_CONTAINER (group), child);
g_assert_cmpint (clutter_group_get_n_children (g), ==, 3);
test = clutter_group_get_nth_child (g, 0);
g_assert_cmpstr (clutter_actor_get_name (test), ==, "minus-ten");
test = clutter_group_get_nth_child (g, 1);
g_assert_cmpstr (clutter_actor_get_name (test), ==, "zero");
test = clutter_group_get_nth_child (g, 2);
g_assert_cmpstr (clutter_actor_get_name (test), ==, "plus-ten");
clutter_actor_destroy (group);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/group/depth-sorting", group_depth_sorting)
)

View File

@ -0,0 +1,117 @@
#include <clutter/clutter.h>
static void
interval_initial_state (void)
{
ClutterInterval *interval;
int initial, final;
const GValue *value;
interval = clutter_interval_new (G_TYPE_INT, 0, 100);
g_assert (CLUTTER_IS_INTERVAL (interval));
g_assert (clutter_interval_get_value_type (interval) == G_TYPE_INT);
clutter_interval_get_interval (interval, &initial, &final);
g_assert_cmpint (initial, ==, 0);
g_assert_cmpint (final, ==, 100);
value = clutter_interval_compute (interval, 0);
g_assert (G_VALUE_HOLDS_INT (value));
g_assert_cmpint (g_value_get_int (value), ==, 0);
value = clutter_interval_compute (interval, 1);
g_assert (G_VALUE_HOLDS_INT (value));
g_assert_cmpint (g_value_get_int (value), ==, 100);
value = clutter_interval_compute (interval, 0.5);
g_assert (G_VALUE_HOLDS_INT (value));
g_assert_cmpint (g_value_get_int (value), ==, 50);
clutter_interval_set_final (interval, 200);
value = clutter_interval_peek_final_value (interval);
g_assert (G_VALUE_HOLDS_INT (value));
g_assert_cmpint (g_value_get_int (value), ==, 200);
g_object_unref (interval);
}
static void
interval_transform (void)
{
ClutterInterval *interval;
GValue value = G_VALUE_INIT;
const GValue *value_p = NULL;
interval = clutter_interval_new_with_values (G_TYPE_FLOAT, NULL, NULL);
g_value_init (&value, G_TYPE_DOUBLE);
g_value_set_double (&value, 0.0);
clutter_interval_set_initial_value (interval, &value);
g_value_set_double (&value, 100.0);
clutter_interval_set_final_value (interval, &value);
g_value_unset (&value);
value_p = clutter_interval_peek_initial_value (interval);
g_assert (G_VALUE_HOLDS_FLOAT (value_p));
g_assert_cmpfloat (g_value_get_float (value_p), ==, 0.f);
value_p = clutter_interval_peek_final_value (interval);
g_assert (G_VALUE_HOLDS_FLOAT (value_p));
g_assert_cmpfloat (g_value_get_float (value_p), ==, 100.f);
g_object_unref (interval);
}
static void
interval_from_script (void)
{
ClutterScript *script = clutter_script_new ();
ClutterInterval *interval;
gchar *test_file;
GError *error = NULL;
GValue *initial, *final;
test_file = g_test_build_filename (G_TEST_DIST,
"scripts",
"test-script-interval.json",
NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_printerr ("\tError: %s", error->message);
g_assert_no_error (error);
interval = CLUTTER_INTERVAL (clutter_script_get_object (script, "int-1"));
initial = clutter_interval_peek_initial_value (interval);
if (g_test_verbose ())
g_test_message ("\tinitial ['%s'] = '%.2f'",
g_type_name (G_VALUE_TYPE (initial)),
g_value_get_float (initial));
g_assert (G_VALUE_HOLDS (initial, G_TYPE_FLOAT));
g_assert_cmpfloat (g_value_get_float (initial), ==, 23.3f);
final = clutter_interval_peek_final_value (interval);
if (g_test_verbose ())
g_test_message ("\tfinal ['%s'] = '%.2f'",
g_type_name (G_VALUE_TYPE (final)),
g_value_get_float (final));
g_assert (G_VALUE_HOLDS (final, G_TYPE_FLOAT));
g_assert_cmpfloat (g_value_get_float (final), ==, 42.2f);
interval = CLUTTER_INTERVAL (clutter_script_get_object (script, "int-2"));
initial = clutter_interval_peek_initial_value (interval);
g_assert (G_VALUE_HOLDS (initial, CLUTTER_TYPE_COLOR));
final = clutter_interval_peek_final_value (interval);
g_assert (G_VALUE_HOLDS (final, CLUTTER_TYPE_COLOR));
g_object_unref (script);
g_free (test_file);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/interval/initial-state", interval_initial_state)
CLUTTER_TEST_UNIT ("/interval/transform", interval_transform)
CLUTTER_TEST_UNIT ("/interval/from-script", interval_from_script)
)

View File

@ -0,0 +1,78 @@
clutter_tests_conform_c_args = [
'-DG_LOG_DOMAIN="Clutter-Conform"',
'-DCOGL_DISABLE_DEPRECATION_WARNINGS',
]
clutter_tests_conform_c_args += clutter_debug_c_args
clutter_tests_conform_link_args = [
'-Wl,--export-dynamic',
]
clutter_conform_tests_actor_tests = [
'actor-anchors',
'actor-destroy',
'actor-graph',
'actor-invariants',
'actor-iter',
'actor-layout',
'actor-meta',
'actor-offscreen-redirect',
'actor-paint-opacity',
'actor-pick',
'actor-shader-effect',
'actor-size',
]
clutter_conform_tests_classes_tests = [
'text',
]
clutter_conform_tests_general_tests = [
'binding-pool',
'color',
'interval',
'script-parser',
'units',
]
clutter_conform_tests_deprecated_tests = [
'behaviours',
'group',
'rectangle',
'texture',
]
clutter_conform_tests = []
clutter_conform_tests += clutter_conform_tests_actor_tests
clutter_conform_tests += clutter_conform_tests_classes_tests
clutter_conform_tests += clutter_conform_tests_general_tests
clutter_conform_tests += clutter_conform_tests_deprecated_tests
test_env = environment()
test_env.set('G_TEST_SRCDIR', meson.current_source_dir())
test_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
test_env.set('G_ENABLE_DIAGNOSTIC', '0')
test_env.set('CLUTTER_ENABLE_DIAGNOSTIC', '0')
test_env.set('CLUTTER_SCALE', '1')
foreach test : clutter_conform_tests
test_executable = executable('@0@'.format(test),
sources: [
'@0@.c'.format(test),
],
include_directories: clutter_includes,
c_args: clutter_tests_conform_c_args,
link_args: clutter_tests_conform_link_args,
dependencies: [
clutter_deps,
libmutter_clutter_dep,
libmutter_cogl_path_dep
],
install: false,
)
test(test, test_executable,
suite: ['clutter', 'clutter/conform'],
env: test_env
)
endforeach

View File

@ -0,0 +1,740 @@
#include <clutter/clutter.h>
#include <cairo.h>
#include <string.h>
#include <math.h>
#include "test-conform-common.h"
#define MAX_NODES 128
#define FLOAT_FUZZ_AMOUNT 5.0f
typedef struct _CallbackData CallbackData;
typedef gboolean (* PathTestFunc) (CallbackData *data);
static void compare_node (const ClutterPathNode *node, gpointer data_p);
struct _CallbackData
{
ClutterPath *path;
guint n_nodes;
ClutterPathNode nodes[MAX_NODES];
gboolean nodes_different;
guint nodes_found;
};
static const char path_desc[] =
"M 21 22 "
"L 25 26 "
"C 29 30 31 32 33 34 "
"m 23 24 "
"l 27 28 "
"c 35 36 37 38 39 40 "
"z";
static const ClutterPathNode path_nodes[] =
{ { CLUTTER_PATH_MOVE_TO, { { 21, 22 }, { 0, 0 }, { 0, 0 } } },
{ CLUTTER_PATH_LINE_TO, { { 25, 26 }, { 0, 0 }, { 0, 0 } } },
{ CLUTTER_PATH_CURVE_TO, { { 29, 30 }, { 31, 32 }, { 33, 34 } } },
{ CLUTTER_PATH_REL_MOVE_TO, { { 23, 24 }, { 0, 0 }, { 0, 0 } } },
{ CLUTTER_PATH_REL_LINE_TO, { { 27, 28 }, { 0, 0 }, { 0, 0 } } },
{ CLUTTER_PATH_REL_CURVE_TO, { { 35, 36 }, { 37, 38 }, { 39, 40 } } },
{ CLUTTER_PATH_CLOSE, { { 0, 0 }, { 0, 0 }, { 0, 0 } } } };
static gboolean
path_test_add_move_to (CallbackData *data)
{
ClutterPathNode node = { 0, };
node.type = CLUTTER_PATH_MOVE_TO;
node.points[0].x = 1;
node.points[0].y = 2;
clutter_path_add_move_to (data->path, node.points[0].x, node.points[0].y);
data->nodes[data->n_nodes++] = node;
return TRUE;
}
static gboolean
path_test_add_line_to (CallbackData *data)
{
ClutterPathNode node = { 0, };
node.type = CLUTTER_PATH_LINE_TO;
node.points[0].x = 3;
node.points[0].y = 4;
clutter_path_add_line_to (data->path, node.points[0].x, node.points[0].y);
data->nodes[data->n_nodes++] = node;
return TRUE;
}
static gboolean
path_test_add_curve_to (CallbackData *data)
{
ClutterPathNode node = { 0, };
node.type = CLUTTER_PATH_CURVE_TO;
node.points[0].x = 5;
node.points[0].y = 6;
node.points[1].x = 7;
node.points[1].y = 8;
node.points[2].x = 9;
node.points[2].y = 10;
clutter_path_add_curve_to (data->path,
node.points[0].x, node.points[0].y,
node.points[1].x, node.points[1].y,
node.points[2].x, node.points[2].y);
data->nodes[data->n_nodes++] = node;
return TRUE;
}
static gboolean
path_test_add_close (CallbackData *data)
{
ClutterPathNode node = { 0, };
node.type = CLUTTER_PATH_CLOSE;
clutter_path_add_close (data->path);
data->nodes[data->n_nodes++] = node;
return TRUE;
}
static gboolean
path_test_add_rel_move_to (CallbackData *data)
{
ClutterPathNode node = { 0, };
node.type = CLUTTER_PATH_REL_MOVE_TO;
node.points[0].x = 11;
node.points[0].y = 12;
clutter_path_add_rel_move_to (data->path, node.points[0].x, node.points[0].y);
data->nodes[data->n_nodes++] = node;
return TRUE;
}
static gboolean
path_test_add_rel_line_to (CallbackData *data)
{
ClutterPathNode node = { 0, };
node.type = CLUTTER_PATH_REL_LINE_TO;
node.points[0].x = 13;
node.points[0].y = 14;
clutter_path_add_rel_line_to (data->path, node.points[0].x, node.points[0].y);
data->nodes[data->n_nodes++] = node;
return TRUE;
}
static gboolean
path_test_add_rel_curve_to (CallbackData *data)
{
ClutterPathNode node = { 0, };
node.type = CLUTTER_PATH_REL_CURVE_TO;
node.points[0].x = 15;
node.points[0].y = 16;
node.points[1].x = 17;
node.points[1].y = 18;
node.points[2].x = 19;
node.points[2].y = 20;
clutter_path_add_rel_curve_to (data->path,
node.points[0].x, node.points[0].y,
node.points[1].x, node.points[1].y,
node.points[2].x, node.points[2].y);
data->nodes[data->n_nodes++] = node;
return TRUE;
}
static gboolean
path_test_add_string (CallbackData *data)
{
int i;
for (i = 0; i < G_N_ELEMENTS (path_nodes); i++)
data->nodes[data->n_nodes++] = path_nodes[i];
clutter_path_add_string (data->path, path_desc);
return TRUE;
}
static gboolean
path_test_add_node_by_struct (CallbackData *data)
{
int i;
for (i = 0; i < G_N_ELEMENTS (path_nodes); i++)
{
data->nodes[data->n_nodes++] = path_nodes[i];
clutter_path_add_node (data->path, path_nodes + i);
}
return TRUE;
}
static gboolean
path_test_get_n_nodes (CallbackData *data)
{
return clutter_path_get_n_nodes (data->path) == data->n_nodes;
}
static gboolean
path_test_get_node (CallbackData *data)
{
int i;
data->nodes_found = 0;
data->nodes_different = FALSE;
for (i = 0; i < data->n_nodes; i++)
{
ClutterPathNode node;
clutter_path_get_node (data->path, i, &node);
compare_node (&node, data);
}
return !data->nodes_different;
}
static gboolean
path_test_get_nodes (CallbackData *data)
{
GSList *list, *node;
data->nodes_found = 0;
data->nodes_different = FALSE;
list = clutter_path_get_nodes (data->path);
for (node = list; node; node = node->next)
compare_node (node->data, data);
g_slist_free (list);
return !data->nodes_different && data->nodes_found == data->n_nodes;
}
static gboolean
path_test_insert_beginning (CallbackData *data)
{
ClutterPathNode node;
node.type = CLUTTER_PATH_LINE_TO;
node.points[0].x = 41;
node.points[0].y = 42;
memmove (data->nodes + 1, data->nodes,
data->n_nodes++ * sizeof (ClutterPathNode));
data->nodes[0] = node;
clutter_path_insert_node (data->path, 0, &node);
return TRUE;
}
static gboolean
path_test_insert_end (CallbackData *data)
{
ClutterPathNode node;
node.type = CLUTTER_PATH_LINE_TO;
node.points[0].x = 43;
node.points[0].y = 44;
data->nodes[data->n_nodes++] = node;
clutter_path_insert_node (data->path, -1, &node);
return TRUE;
}
static gboolean
path_test_insert_middle (CallbackData *data)
{
ClutterPathNode node;
int pos = data->n_nodes / 2;
node.type = CLUTTER_PATH_LINE_TO;
node.points[0].x = 45;
node.points[0].y = 46;
memmove (data->nodes + pos + 1, data->nodes + pos,
(data->n_nodes - pos) * sizeof (ClutterPathNode));
data->nodes[pos] = node;
data->n_nodes++;
clutter_path_insert_node (data->path, pos, &node);
return TRUE;
}
static gboolean
path_test_clear (CallbackData *data)
{
clutter_path_clear (data->path);
data->n_nodes = 0;
return TRUE;
}
static gboolean
path_test_clear_insert (CallbackData *data)
{
return path_test_clear (data) && path_test_insert_middle (data);
}
static gboolean
path_test_remove_beginning (CallbackData *data)
{
memmove (data->nodes, data->nodes + 1,
--data->n_nodes * sizeof (ClutterPathNode));
clutter_path_remove_node (data->path, 0);
return TRUE;
}
static gboolean
path_test_remove_end (CallbackData *data)
{
clutter_path_remove_node (data->path, --data->n_nodes);
return TRUE;
}
static gboolean
path_test_remove_middle (CallbackData *data)
{
int pos = data->n_nodes / 2;
memmove (data->nodes + pos, data->nodes + pos + 1,
(--data->n_nodes - pos) * sizeof (ClutterPathNode));
clutter_path_remove_node (data->path, pos);
return TRUE;
}
static gboolean
path_test_remove_only (CallbackData *data)
{
return path_test_clear (data)
&& path_test_add_line_to (data)
&& path_test_remove_beginning (data);
}
static gboolean
path_test_replace (CallbackData *data)
{
ClutterPathNode node;
int pos = data->n_nodes / 2;
node.type = CLUTTER_PATH_LINE_TO;
node.points[0].x = 47;
node.points[0].y = 48;
data->nodes[pos] = node;
clutter_path_replace_node (data->path, pos, &node);
return TRUE;
}
static gboolean
path_test_set_description (CallbackData *data)
{
data->n_nodes = G_N_ELEMENTS (path_nodes);
memcpy (data->nodes, path_nodes, sizeof (path_nodes));
return clutter_path_set_description (data->path, path_desc);
}
static gboolean
path_test_get_description (CallbackData *data)
{
char *desc1, *desc2;
gboolean ret = TRUE;
desc1 = clutter_path_get_description (data->path);
clutter_path_clear (data->path);
if (!clutter_path_set_description (data->path, desc1))
ret = FALSE;
desc2 = clutter_path_get_description (data->path);
if (strcmp (desc1, desc2))
ret = FALSE;
g_free (desc1);
g_free (desc2);
return ret;
}
static gboolean
path_test_convert_to_cairo_path (CallbackData *data)
{
cairo_surface_t *surface;
cairo_t *cr;
cairo_path_t *cpath;
guint i, j;
ClutterKnot path_start = { 0, 0 }, last_point = { 0, 0 };
/* Create a temporary image surface and context to hold the cairo
path */
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10);
cr = cairo_create (surface);
/* Convert to a cairo path */
clutter_path_to_cairo_path (data->path, cr);
/* Get a copy of the cairo path data */
cpath = cairo_copy_path (cr);
/* Convert back to a clutter path */
clutter_path_clear (data->path);
clutter_path_add_cairo_path (data->path, cpath);
/* The relative nodes will have been converted to absolute so we
need to reflect this in the node array for comparison */
for (i = 0; i < data->n_nodes; i++)
{
switch (data->nodes[i].type)
{
case CLUTTER_PATH_MOVE_TO:
path_start = last_point = data->nodes[i].points[0];
break;
case CLUTTER_PATH_LINE_TO:
last_point = data->nodes[i].points[0];
break;
case CLUTTER_PATH_CURVE_TO:
last_point = data->nodes[i].points[2];
break;
case CLUTTER_PATH_REL_MOVE_TO:
last_point.x += data->nodes[i].points[0].x;
last_point.y += data->nodes[i].points[0].y;
data->nodes[i].points[0] = last_point;
data->nodes[i].type = CLUTTER_PATH_MOVE_TO;
path_start = last_point;
break;
case CLUTTER_PATH_REL_LINE_TO:
last_point.x += data->nodes[i].points[0].x;
last_point.y += data->nodes[i].points[0].y;
data->nodes[i].points[0] = last_point;
data->nodes[i].type = CLUTTER_PATH_LINE_TO;
break;
case CLUTTER_PATH_REL_CURVE_TO:
for (j = 0; j < 3; j++)
{
data->nodes[i].points[j].x += last_point.x;
data->nodes[i].points[j].y += last_point.y;
}
last_point = data->nodes[i].points[2];
data->nodes[i].type = CLUTTER_PATH_CURVE_TO;
break;
case CLUTTER_PATH_CLOSE:
last_point = path_start;
/* Cairo always adds a move to after every close so we need
to insert one here. Since Cairo commit 166453c1abf2 it
doesn't seem to do this anymore so will assume that if
Cairo's minor version is >= 11 then it includes that
commit */
if (cairo_version () < CAIRO_VERSION_ENCODE (1, 11, 0))
{
memmove (data->nodes + i + 2, data->nodes + i + 1,
(data->n_nodes - i - 1) * sizeof (ClutterPathNode));
data->nodes[i + 1].type = CLUTTER_PATH_MOVE_TO;
data->nodes[i + 1].points[0] = last_point;
data->n_nodes++;
}
break;
}
}
/* Free the cairo resources */
cairo_path_destroy (cpath);
cairo_destroy (cr);
cairo_surface_destroy (surface);
return TRUE;
}
static gboolean
float_fuzzy_equals (float fa, float fb)
{
return fabs (fa - fb) <= FLOAT_FUZZ_AMOUNT;
}
static void
set_triangle_path (CallbackData *data)
{
/* Triangular shaped path hitting (0,0), (64,64) and (128,0) in four
parts. The two curves are actually straight lines */
static const ClutterPathNode nodes[] =
{ { CLUTTER_PATH_MOVE_TO, { { 0, 0 } } },
{ CLUTTER_PATH_LINE_TO, { { 32, 32 } } },
{ CLUTTER_PATH_CURVE_TO, { { 40, 40 }, { 56, 56 }, { 64, 64 } } },
{ CLUTTER_PATH_REL_CURVE_TO, { { 8, -8 }, { 24, -24 }, { 32, -32 } } },
{ CLUTTER_PATH_REL_LINE_TO, { { 32, -32 } } } };
gint i;
clutter_path_clear (data->path);
for (i = 0; i < G_N_ELEMENTS (nodes); i++)
clutter_path_add_node (data->path, nodes + i);
memcpy (data->nodes, nodes, sizeof (nodes));
data->n_nodes = G_N_ELEMENTS (nodes);
}
static gboolean
path_test_get_position (CallbackData *data)
{
static const float values[] = { 0.125f, 16.0f, 16.0f,
0.375f, 48.0f, 48.0f,
0.625f, 80.0f, 48.0f,
0.875f, 112.0f, 16.0f };
gint i;
set_triangle_path (data);
for (i = 0; i < G_N_ELEMENTS (values); i += 3)
{
ClutterKnot pos;
clutter_path_get_position (data->path,
values[i],
&pos);
if (!float_fuzzy_equals (values[i + 1], pos.x)
|| !float_fuzzy_equals (values[i + 2], pos.y))
return FALSE;
}
return TRUE;
}
static gboolean
path_test_get_length (CallbackData *data)
{
const float actual_length /* sqrt(64**2 + 64**2) * 2 */ = 181.019336f;
guint approx_length;
clutter_path_set_description (data->path, "M 0 0 L 46340 0");
g_object_get (data->path, "length", &approx_length, NULL);
if (!(fabs (approx_length - 46340.f) / 46340.f <= 0.15f))
{
if (g_test_verbose ())
g_print ("M 0 0 L 46340 0 - Expected 46340, got %d instead.", approx_length);
return FALSE;
}
clutter_path_set_description (data->path, "M 0 0 L 46341 0");
g_object_get (data->path, "length", &approx_length, NULL);
if (!(fabs (approx_length - 46341.f) / 46341.f <= 0.15f))
{
if (g_test_verbose ())
g_print ("M 0 0 L 46341 0 - Expected 46341, got %d instead.", approx_length);
return FALSE;
}
set_triangle_path (data);
g_object_get (data->path, "length", &approx_length, NULL);
/* Allow 15% margin of error */
if (!(fabs (approx_length - actual_length) / (float) actual_length <= 0.15f))
{
if (g_test_verbose ())
g_print ("Expected %g, got %d instead.\n", actual_length, approx_length);
return FALSE;
}
return TRUE;
}
static gboolean
path_test_boxed_type (CallbackData *data)
{
gboolean ret = TRUE;
GSList *nodes, *l;
GValue value;
nodes = clutter_path_get_nodes (data->path);
memset (&value, 0, sizeof (value));
for (l = nodes; l; l = l->next)
{
g_value_init (&value, CLUTTER_TYPE_PATH_NODE);
g_value_set_boxed (&value, l->data);
if (!clutter_path_node_equal (l->data,
g_value_get_boxed (&value)))
ret = FALSE;
g_value_unset (&value);
}
g_slist_free (nodes);
return ret;
}
static const struct
{
const char *desc;
PathTestFunc func;
}
path_tests[] =
{
{ "Add line to", path_test_add_line_to },
{ "Add move to", path_test_add_move_to },
{ "Add curve to", path_test_add_curve_to },
{ "Add close", path_test_add_close },
{ "Add relative line to", path_test_add_rel_line_to },
{ "Add relative move to", path_test_add_rel_move_to },
{ "Add relative curve to", path_test_add_rel_curve_to },
{ "Add string", path_test_add_string },
{ "Add node by struct", path_test_add_node_by_struct },
{ "Get number of nodes", path_test_get_n_nodes },
{ "Get a node", path_test_get_node },
{ "Get all nodes", path_test_get_nodes },
{ "Insert at beginning", path_test_insert_beginning },
{ "Insert at end", path_test_insert_end },
{ "Insert at middle", path_test_insert_middle },
{ "Add after insert", path_test_add_line_to },
{ "Clear then insert", path_test_clear_insert },
{ "Add string again", path_test_add_string },
{ "Remove from beginning", path_test_remove_beginning },
{ "Remove from end", path_test_remove_end },
{ "Remove from middle", path_test_remove_middle },
{ "Add after remove", path_test_add_line_to },
{ "Remove only node", path_test_remove_only },
{ "Add after remove again", path_test_add_line_to },
{ "Replace a node", path_test_replace },
{ "Set description", path_test_set_description },
{ "Get description", path_test_get_description },
{ "Convert to cairo path and back", path_test_convert_to_cairo_path },
{ "Clear", path_test_clear },
{ "Get position", path_test_get_position },
{ "Check node boxed type", path_test_boxed_type },
{ "Get length", path_test_get_length }
};
static void
compare_node (const ClutterPathNode *node, gpointer data_p)
{
CallbackData *data = data_p;
if (data->nodes_found >= data->n_nodes)
data->nodes_different = TRUE;
else
{
guint n_points = 0, i;
const ClutterPathNode *onode = data->nodes + data->nodes_found;
if (node->type != onode->type)
data->nodes_different = TRUE;
switch (node->type & ~CLUTTER_PATH_RELATIVE)
{
case CLUTTER_PATH_MOVE_TO: n_points = 1; break;
case CLUTTER_PATH_LINE_TO: n_points = 1; break;
case CLUTTER_PATH_CURVE_TO: n_points = 3; break;
case CLUTTER_PATH_CLOSE: n_points = 0; break;
default:
data->nodes_different = TRUE;
break;
}
for (i = 0; i < n_points; i++)
if (node->points[i].x != onode->points[i].x
|| node->points[i].y != onode->points[i].y)
{
data->nodes_different = TRUE;
break;
}
}
data->nodes_found++;
}
static gboolean
compare_nodes (CallbackData *data)
{
data->nodes_different = FALSE;
data->nodes_found = 0;
clutter_path_foreach (data->path, compare_node, data);
return !data->nodes_different && data->nodes_found == data->n_nodes;
}
void
path_base (TestConformSimpleFixture *fixture,
gconstpointer _data)
{
CallbackData data;
gint i;
memset (&data, 0, sizeof (data));
data.path = clutter_path_new ();
for (i = 0; i < G_N_ELEMENTS (path_tests); i++)
{
gboolean succeeded;
if (g_test_verbose ())
g_print ("%s... ", path_tests[i].desc);
succeeded = path_tests[i].func (&data) && compare_nodes (&data);
if (g_test_verbose ())
g_print ("%s\n", succeeded ? "ok" : "FAIL");
g_assert (succeeded);
}
g_object_unref (data.path);
}

View File

@ -0,0 +1,51 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
static void
rectangle_set_size (void)
{
ClutterActor *rect = clutter_rectangle_new ();
/* initial positioning */
g_assert_cmpint (clutter_actor_get_x (rect), ==, 0);
g_assert_cmpint (clutter_actor_get_y (rect), ==, 0);
clutter_actor_set_size (rect, 100, 100);
/* make sure that changing the size does not affect the
* rest of the bounding box
*/
g_assert_cmpint (clutter_actor_get_x (rect), ==, 0);
g_assert_cmpint (clutter_actor_get_y (rect), ==, 0);
g_assert_cmpint (clutter_actor_get_width (rect), ==, 100);
g_assert_cmpint (clutter_actor_get_height (rect), ==, 100);
clutter_actor_destroy (rect);
}
static void
rectangle_set_color (void)
{
ClutterActor *rect = clutter_rectangle_new ();
ClutterColor white = { 255, 255, 255, 255 };
ClutterColor black = { 0, 0, 0, 255 };
ClutterColor check = { 0, };
clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &black);
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &check);
g_assert_cmpint (check.blue, ==, black.blue);
clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &white);
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &check);
g_assert_cmpint (check.green, ==, white.green);
g_assert_cmpint (clutter_actor_get_opacity (rect), ==, white.alpha);
clutter_actor_destroy (rect);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/rectangle/set-size", rectangle_set_size)
CLUTTER_TEST_UNIT ("/rectangle/set-color", rectangle_set_color)
)

View File

@ -0,0 +1,427 @@
#include <stdlib.h>
#include <string.h>
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#define TEST_TYPE_GROUP (test_group_get_type ())
#define TEST_TYPE_GROUP_META (test_group_meta_get_type ())
#define TEST_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_GROUP, TestGroup))
#define TEST_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_GROUP))
#define TEST_GROUP_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_GROUP_META, TestGroupMeta))
#define TEST_IS_GROUP_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_GROUP_META))
typedef struct _ClutterActor TestGroup;
typedef struct _ClutterActorClass TestGroupClass;
typedef struct _TestGroupMeta {
ClutterChildMeta parent_instance;
guint is_focus : 1;
} TestGroupMeta;
typedef struct _ClutterChildMetaClass TestGroupMetaClass;
GType test_group_meta_get_type (void);
G_DEFINE_TYPE (TestGroupMeta, test_group_meta, CLUTTER_TYPE_CHILD_META)
enum
{
PROP_META_0,
PROP_META_FOCUS
};
static void
test_group_meta_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
TestGroupMeta *self = TEST_GROUP_META (gobject);
switch (prop_id)
{
case PROP_META_FOCUS:
self->is_focus = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
test_group_meta_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
TestGroupMeta *self = TEST_GROUP_META (gobject);
switch (prop_id)
{
case PROP_META_FOCUS:
g_value_set_boolean (value, self->is_focus);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
test_group_meta_class_init (TestGroupMetaClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
gobject_class->set_property = test_group_meta_set_property;
gobject_class->get_property = test_group_meta_get_property;
pspec = g_param_spec_boolean ("focus", "Focus", "Focus",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_META_FOCUS, pspec);
}
static void
test_group_meta_init (TestGroupMeta *meta)
{
meta->is_focus = FALSE;
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
iface->child_meta_type = TEST_TYPE_GROUP_META;
}
GType test_group_get_type (void);
G_DEFINE_TYPE_WITH_CODE (TestGroup, test_group, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init))
static void
test_group_class_init (TestGroupClass *klass)
{
}
static void
test_group_init (TestGroup *self)
{
}
static void
script_child (void)
{
ClutterScript *script = clutter_script_new ();
GObject *container, *actor;
GError *error = NULL;
gboolean focus_ret;
gchar *test_file;
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-child.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
container = actor = NULL;
clutter_script_get_objects (script,
"test-group", &container,
"test-rect-1", &actor,
NULL);
g_assert (TEST_IS_GROUP (container));
g_assert (CLUTTER_IS_RECTANGLE (actor));
focus_ret = FALSE;
clutter_container_child_get (CLUTTER_CONTAINER (container),
CLUTTER_ACTOR (actor),
"focus", &focus_ret,
NULL);
g_assert (focus_ret);
actor = clutter_script_get_object (script, "test-rect-2");
g_assert (CLUTTER_IS_RECTANGLE (actor));
focus_ret = FALSE;
clutter_container_child_get (CLUTTER_CONTAINER (container),
CLUTTER_ACTOR (actor),
"focus", &focus_ret,
NULL);
g_assert (!focus_ret);
g_object_unref (script);
g_free (test_file);
}
static void
script_single (void)
{
ClutterScript *script = clutter_script_new ();
ClutterColor color = { 0, };
GObject *actor = NULL;
GError *error = NULL;
ClutterActor *rect;
gchar *test_file;
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-single.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
actor = clutter_script_get_object (script, "test");
g_assert (CLUTTER_IS_RECTANGLE (actor));
rect = CLUTTER_ACTOR (actor);
g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 50.0);
g_assert_cmpfloat (clutter_actor_get_y (rect), ==, 100.0);
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color);
g_assert_cmpint (color.red, ==, 255);
g_assert_cmpint (color.green, ==, 0xcc);
g_assert_cmpint (color.alpha, ==, 0xff);
g_object_unref (script);
g_free (test_file);
}
static void
script_implicit_alpha (void)
{
ClutterScript *script = clutter_script_new ();
ClutterTimeline *timeline;
GObject *behaviour = NULL;
GError *error = NULL;
ClutterAlpha *alpha;
gchar *test_file;
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-implicit-alpha.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s", error->message);
#if GLIB_CHECK_VERSION (2, 20, 0)
g_assert_no_error (error);
#else
g_assert (error == NULL);
#endif
behaviour = clutter_script_get_object (script, "test");
g_assert (CLUTTER_IS_BEHAVIOUR (behaviour));
alpha = clutter_behaviour_get_alpha (CLUTTER_BEHAVIOUR (behaviour));
g_assert (CLUTTER_IS_ALPHA (alpha));
g_assert_cmpint (clutter_alpha_get_mode (alpha), ==, CLUTTER_EASE_OUT_CIRC);
timeline = clutter_alpha_get_timeline (alpha);
g_assert (CLUTTER_IS_TIMELINE (timeline));
g_assert_cmpint (clutter_timeline_get_duration (timeline), ==, 500);
g_object_unref (script);
g_free (test_file);
}
static void
script_object_property (void)
{
ClutterScript *script = clutter_script_new ();
ClutterLayoutManager *manager;
GObject *actor = NULL;
GError *error = NULL;
gchar *test_file;
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-object-property.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
actor = clutter_script_get_object (script, "test");
g_assert (CLUTTER_IS_BOX (actor));
manager = clutter_box_get_layout_manager (CLUTTER_BOX (actor));
g_assert (CLUTTER_IS_BIN_LAYOUT (manager));
g_object_unref (script);
g_free (test_file);
}
static void
script_named_object (void)
{
ClutterScript *script = clutter_script_new ();
ClutterLayoutManager *manager;
GObject *actor = NULL;
GError *error = NULL;
gchar *test_file;
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-named-object.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
actor = clutter_script_get_object (script, "test");
g_assert (CLUTTER_IS_BOX (actor));
manager = clutter_box_get_layout_manager (CLUTTER_BOX (actor));
g_assert (CLUTTER_IS_BOX_LAYOUT (manager));
g_assert (clutter_box_layout_get_vertical (CLUTTER_BOX_LAYOUT (manager)));
g_object_unref (script);
g_free (test_file);
}
static void
script_animation (void)
{
ClutterScript *script = clutter_script_new ();
GObject *animation = NULL;
GError *error = NULL;
gchar *test_file;
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-animation.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
animation = clutter_script_get_object (script, "test");
g_assert (CLUTTER_IS_ANIMATION (animation));
g_object_unref (script);
g_free (test_file);
}
static void
script_layout_property (void)
{
ClutterScript *script = clutter_script_new ();
GObject *manager, *container, *actor1, *actor2;
GError *error = NULL;
gchar *test_file;
gboolean x_fill, expand;
ClutterBoxAlignment y_align;
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-layout-property.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
manager = container = actor1 = actor2 = NULL;
clutter_script_get_objects (script,
"manager", &manager,
"container", &container,
"actor-1", &actor1,
"actor-2", &actor2,
NULL);
g_assert (CLUTTER_IS_LAYOUT_MANAGER (manager));
g_assert (CLUTTER_IS_CONTAINER (container));
g_assert (CLUTTER_IS_ACTOR (actor1));
g_assert (CLUTTER_IS_ACTOR (actor2));
x_fill = FALSE;
y_align = CLUTTER_BOX_ALIGNMENT_START;
expand = FALSE;
clutter_layout_manager_child_get (CLUTTER_LAYOUT_MANAGER (manager),
CLUTTER_CONTAINER (container),
CLUTTER_ACTOR (actor1),
"x-fill", &x_fill,
"y-align", &y_align,
"expand", &expand,
NULL);
g_assert (x_fill);
g_assert (y_align == CLUTTER_BOX_ALIGNMENT_CENTER);
g_assert (expand);
x_fill = TRUE;
y_align = CLUTTER_BOX_ALIGNMENT_START;
expand = TRUE;
clutter_layout_manager_child_get (CLUTTER_LAYOUT_MANAGER (manager),
CLUTTER_CONTAINER (container),
CLUTTER_ACTOR (actor2),
"x-fill", &x_fill,
"y-align", &y_align,
"expand", &expand,
NULL);
g_assert (x_fill == FALSE);
g_assert (y_align == CLUTTER_BOX_ALIGNMENT_END);
g_assert (expand == FALSE);
g_object_unref (script);
}
static void
script_margin (void)
{
ClutterScript *script = clutter_script_new ();
ClutterActor *actor;
gchar *test_file;
GError *error = NULL;
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-margin.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
actor = CLUTTER_ACTOR (clutter_script_get_object (script, "actor-1"));
g_assert_cmpfloat (clutter_actor_get_margin_top (actor), ==, 10.0f);
g_assert_cmpfloat (clutter_actor_get_margin_right (actor), ==, 10.0f);
g_assert_cmpfloat (clutter_actor_get_margin_bottom (actor), ==, 10.0f);
g_assert_cmpfloat (clutter_actor_get_margin_left (actor), ==, 10.0f);
actor = CLUTTER_ACTOR (clutter_script_get_object (script, "actor-2"));
g_assert_cmpfloat (clutter_actor_get_margin_top (actor), ==, 10.0f);
g_assert_cmpfloat (clutter_actor_get_margin_right (actor), ==, 20.0f);
g_assert_cmpfloat (clutter_actor_get_margin_bottom (actor), ==, 10.0f);
g_assert_cmpfloat (clutter_actor_get_margin_left (actor), ==, 20.0f);
actor = CLUTTER_ACTOR (clutter_script_get_object (script, "actor-3"));
g_assert_cmpfloat (clutter_actor_get_margin_top (actor), ==, 10.0f);
g_assert_cmpfloat (clutter_actor_get_margin_right (actor), ==, 20.0f);
g_assert_cmpfloat (clutter_actor_get_margin_bottom (actor), ==, 30.0f);
g_assert_cmpfloat (clutter_actor_get_margin_left (actor), ==, 20.0f);
actor = CLUTTER_ACTOR (clutter_script_get_object (script, "actor-4"));
g_assert_cmpfloat (clutter_actor_get_margin_top (actor), ==, 10.0f);
g_assert_cmpfloat (clutter_actor_get_margin_right (actor), ==, 20.0f);
g_assert_cmpfloat (clutter_actor_get_margin_bottom (actor), ==, 30.0f);
g_assert_cmpfloat (clutter_actor_get_margin_left (actor), ==, 40.0f);
g_object_unref (script);
g_free (test_file);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/script/single-object", script_single)
CLUTTER_TEST_UNIT ("/script/container-child", script_child)
CLUTTER_TEST_UNIT ("/script/named-object", script_named_object)
CLUTTER_TEST_UNIT ("/script/animation", script_animation)
CLUTTER_TEST_UNIT ("/script/implicit-alpha", script_implicit_alpha)
CLUTTER_TEST_UNIT ("/script/object-property", script_object_property)
CLUTTER_TEST_UNIT ("/script/layout-property", script_layout_property)
CLUTTER_TEST_UNIT ("/script/actor-margin", script_margin)
)

View File

@ -0,0 +1,5 @@
{
"type" : "ClutterAnimator",
"id" : "animator",
"duration" : 1000
}

View File

@ -0,0 +1,29 @@
[
{
"type" : "ClutterRectangle",
"id" : "foo",
"x" : 0,
"y" : 0,
"width" : 100,
"height" : 100
},
{
"type" : "ClutterAnimator",
"id" : "animator",
"duration" : 1000,
"properties" : [
{
"object" : "foo",
"name" : "x",
"ease-in" : true,
"interpolation" : "linear",
"keys" : [
[ 0.0, "easeInCubic", 100.0 ],
[ 0.2, "easeOutCubic", 150.0 ],
[ 0.8, "linear", 200.0 ]
]
}
]
}
]

View File

@ -0,0 +1,40 @@
[
{
"type" : "ClutterRectangle",
"id" : "foo",
"x" : 0,
"y" : 0,
"width" : 100,
"height" : 100
},
{
"type" : "ClutterAnimator",
"id" : "animator",
"duration" : 1000,
"properties" : [
{
"object" : "foo",
"name" : "x",
"ease-in" : true,
"interpolation" : "linear",
"keys" : [
[ 0.0, "easeInCubic", 100.0 ],
[ 0.2, "easeOutCubic", 150.0 ],
[ 0.8, "linear", 200.0 ]
]
},
{
"object" : "foo",
"name" : "y",
"ease-in" : true,
"interpolation" : "linear",
"keys" : [
[ 0.0, "easeInCubic", 100.0 ],
[ 0.2, "easeOutCubic", 150.0 ],
[ 0.8, "linear", 200.0 ]
]
}
]
}
]

View File

@ -0,0 +1,14 @@
{
"type" : "ClutterAnimation",
"id" : "test",
"mode" : "easeInCubic",
"duration" : 500,
"object" : {
"type" : "ClutterRectangle",
"id" : "rect",
"opacity" : 128,
"width" : 100,
"height" : 16,
"color" : "white"
}
}

View File

@ -0,0 +1,21 @@
{
"type" : "TestGroup",
"id" : "test-group",
"children" : [
{
"type" : "ClutterRectangle",
"id" : "test-rect-1",
"width" : 100.0,
"height" : 100.0,
"color" : [ 255, 0, 0, 255 ],
"child::focus" : true
},
{
"type" : "ClutterRectangle",
"id" : "test-rect-2",
"width" : 100.0,
"height" : 100.0,
"color" : [ 0, 255, 0, 255 ]
}
]
}

View File

@ -0,0 +1,8 @@
{
"id" : "test",
"type" : "ClutterBehaviourOpacity",
"alpha" : {
"mode" : "easeOutCirc",
"timeline" : { "duration" : 500 }
}
}

View File

@ -0,0 +1,16 @@
[
{
"id" : "int-1",
"type" : "ClutterInterval",
"value-type" : "gfloat",
"initial" : 23.3,
"final" : 42.2
},
{
"id" : "int-2",
"type" : "ClutterInterval",
"value-type" : "ClutterColor",
"initial" : "red",
"final" : "blue"
}
]

View File

@ -0,0 +1,21 @@
[
{ "id" : "manager", "type" : "ClutterBoxLayout" },
{
"id" : "container", "type" : "ClutterBox",
"layout-manager" : "manager",
"children" : [
{
"id" : "actor-1", "type" : "ClutterRectangle",
"layout::x-fill" : true,
"layout::y-align" : "center",
"layout::expand" : true
}, {
"id" : "actor-2", "type" : "ClutterRectangle",
"layout::x-fill" : false,
"layout::y-align" : "end",
"layout::expand" : false
}
]
}
]

View File

@ -0,0 +1,22 @@
[
{
"id" : "actor-1",
"type" : "ClutterActor",
"margin" : [ 10 ]
},
{
"id" : "actor-2",
"type" : "ClutterActor",
"margin" : [ 10, 20 ]
},
{
"id" : "actor-3",
"type" : "ClutterActor",
"margin" : [ 10, 20, 30 ]
},
{
"id" : "actor-4",
"type" : "ClutterActor",
"margin" : [ 10, 20, 30, 40]
}
]

View File

@ -0,0 +1,17 @@
{
"id" : "test-model",
"type" : "ClutterListModel",
"columns" : [
[ "text-column", "gchararray" ],
[ "int-column", "gint" ],
[ "actor-column", "ClutterRectangle" ]
],
"rows" : [
[ "text-row-1", 1, null ],
[ "text-row-2", 2, { "type" : "ClutterRectangle", "color" : "blue" } ],
{
"int-column" : 3,
"actor-column" : { "type" : "ClutterRectangle", "name" : "actor-row-3" }
}
]
}

View File

@ -0,0 +1,44 @@
[
{
"id" : "layout",
"type" : "ClutterBoxLayout",
"orientation" : "vertical",
"spacing" : 12,
"pack-start" : false
},
{
"type" : "ClutterStage",
"id" : "main-stage",
"children" : [
{
"id" : "test",
"type" : "ClutterBox",
"layout-manager" : "layout",
"children" : [
{
"id" : "child-1",
"type" : "ClutterRectangle",
"width" : "3 em",
"height" : "3 em"
}
],
"constraints" : [
{
"type" : "ClutterAlignConstraint",
"name" : "x-align",
"factor" : 0.5,
"align-axis" : "x-axis",
"source" : "main-stage"
},
{
"type" : "ClutterAlignConstraint",
"name" : "y-align",
"factor" : 0.5,
"align-axis" : "y-axis",
"source" : "main-stage"
}
]
}
]
}
]

View File

@ -0,0 +1,13 @@
{
"id" : "test",
"type" : "ClutterBox",
"layout-manager" : { "id" : "layout", "type" : "ClutterBinLayout" },
"children" : [
{
"id" : "child-1",
"type" : "ClutterRectangle",
"width" : "3 em",
"height" : "3 em"
}
]
}

View File

@ -0,0 +1,10 @@
{
"type" : "ClutterRectangle",
"id" : "test",
"width" : 50.0,
"height" : 100.0,
"x" : 100.0,
"y" : 100.0,
"color" : "#ffccdd",
"name" : "Test Rectangle"
}

View File

@ -0,0 +1,12 @@
{
"id" : "timeline0",
"type" : "ClutterTimeline",
"duration" : 1000,
"markers" : [
{ "name" : "marker0", "time" : 250 },
{ "name" : "marker1", "time" : 500 },
{ "name" : "marker2", "time" : 750 },
{ "name" : "marker3", "progress" : 0.5 }
]
}

View File

@ -0,0 +1,33 @@
[
{
"type" : "ClutterRectangle",
"id" : "rect",
"width" : 100,
"height" : 100
},
{
"type" : "ClutterState",
"id" : "state",
"transitions" : [
{
"source" : "base",
"target" : "clicked",
"duration" : 250,
"keys" : [
[ "rect", "opacity", "linear", 128 ]
]
},
{
"source" : "clicked",
"target" : "base",
"duration" : 150,
"keys" : [
[ "rect", "opacity", "linear", 255 ]
]
}
]
}
]

View File

@ -0,0 +1,87 @@
#include <clutter/clutter.h>
#include "test-conform-common.h"
void
state_base (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
gconstpointer dummy G_GNUC_UNUSED)
{
ClutterScript *script = clutter_script_new ();
GObject *state = NULL;
GError *error = NULL;
gchar *test_file;
GList *states, *keys;
ClutterStateKey *state_key;
guint duration;
test_file = clutter_test_get_data_file ("test-state-1.json");
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
g_print ("Error: %s\n", error->message);
g_free (test_file);
#if GLIB_CHECK_VERSION (2, 20, 0)
g_assert_no_error (error);
#else
g_assert (error == NULL);
#endif
state = clutter_script_get_object (script, "state");
g_assert (CLUTTER_IS_STATE (state));
states = clutter_state_get_states (CLUTTER_STATE (state));
g_assert (states != NULL);
g_assert (g_list_find (states, g_intern_static_string ("clicked")));
g_list_free (states);
duration = clutter_state_get_duration (CLUTTER_STATE (state), "base", "clicked");
g_assert_cmpint (duration, ==, 250);
duration = clutter_state_get_duration (CLUTTER_STATE (state), "clicked", "base");
g_assert_cmpint (duration, ==, 150);
keys = clutter_state_get_keys (CLUTTER_STATE (state), "base", "clicked",
clutter_script_get_object (script, "rect"),
"opacity");
g_assert (keys != NULL);
g_assert_cmpint (g_list_length (keys), ==, 1);
state_key = keys->data;
g_assert (clutter_state_key_get_object (state_key) == clutter_script_get_object (script, "rect"));
g_assert (clutter_state_key_get_mode (state_key) == CLUTTER_LINEAR);
g_assert_cmpstr (clutter_state_key_get_property_name (state_key), ==, "opacity");
g_list_free (keys);
keys = clutter_state_get_keys (CLUTTER_STATE (state), NULL, NULL, NULL, NULL);
g_assert_cmpint (g_list_length (keys), ==, 2);
g_list_free (keys);
clutter_state_set (CLUTTER_STATE (state), "base", "clicked", state, "state", CLUTTER_LINEAR, "foo", NULL);
keys = clutter_state_get_keys (CLUTTER_STATE (state), "base", "clicked",
NULL, NULL);
g_assert (keys != NULL);
g_assert_cmpint (g_list_length (keys), ==, 2);
g_list_free (keys);
states = clutter_state_get_states (CLUTTER_STATE (state));
g_assert_cmpint (g_list_length (states), ==, 2);
g_list_free (states);
clutter_state_remove_key (CLUTTER_STATE (state), NULL, "clicked", NULL, NULL);
states = clutter_state_get_states (CLUTTER_STATE (state));
/* removing the "clicked" state, will also cause the "base" state to be removed
* since in the .json there is no default source state
*/
g_assert_cmpint (g_list_length (states), ==, 0);
g_list_free (states);
g_object_unref (script);
}

View File

@ -0,0 +1,297 @@
#include <clutter/clutter.h>
#include <string.h>
#include <stdlib.h>
#include "test-conform-common.h"
#define TEST_FONT "Sans 10"
static const char long_text[] =
"<b>This</b> <i>is</i> some <span size=\"x-large\">REALLY</span> "
"long text that contains markup for testing the <tt>use_markup</tt> "
"property and to test word-wrapping, justification and alignment.";
typedef struct _CallbackData CallbackData;
struct _CallbackData
{
ClutterActor *stage;
ClutterActor *label;
PangoLayout *old_layout;
gboolean layout_changed;
PangoRectangle label_extents;
PangoLayout *test_layout;
gboolean test_failed;
};
static void
on_paint (ClutterActor *stage, CallbackData *data)
{
PangoLayout *new_layout;
/* Check whether the layout used for this paint is different from
the layout used for the last paint */
new_layout = clutter_text_get_layout (CLUTTER_TEXT (data->label));
data->layout_changed = data->old_layout != new_layout;
if (data->old_layout)
g_object_unref (data->old_layout);
/* Keep a reference to the old layout so we can be sure it won't
just reallocate a new layout with the same address */
data->old_layout = g_object_ref (new_layout);
pango_layout_get_extents (new_layout, NULL, &data->label_extents);
}
static void
force_redraw (CallbackData *data)
{
/* XXX - this is fugly; we force a paint on the stage, which
* will then paint the Text actor. inside the Text actor we
* check for a Layout with the allocation size. if the allocation
* has changed it will cause a relayout in the middle of the
* paint, which is expensive and broken. this will ensure that
* the test passes, though
*/
clutter_actor_paint (clutter_actor_get_stage (data->label));
}
static gboolean
check_result (CallbackData *data, const char *note,
gboolean layout_should_change)
{
PangoRectangle test_extents;
gboolean fail = FALSE;
if (g_test_verbose ())
g_print ("%s: ", note);
/* Force a redraw to get the on_paint handler to run */
force_redraw (data);
/* Compare the extents from the label with the extents from our test
layout */
pango_layout_get_extents (data->test_layout, NULL, &test_extents);
if (memcmp (&test_extents, &data->label_extents, sizeof (PangoRectangle)))
{
if (g_test_verbose ())
g_print ("extents are different: expected: %d, %d, %d, %d "
"-> text: %d, %d, %d, %d\n",
test_extents.x / 1024,
test_extents.y / 1024,
test_extents.width / 1024,
test_extents.height / 1024,
data->label_extents.x / 1024,
data->label_extents.y / 1024,
data->label_extents.width / 1024,
data->label_extents.height / 1024);
fail = TRUE;
}
else
{
if (g_test_verbose ())
g_print ("extents are the same, ");
}
if (data->layout_changed)
{
if (g_test_verbose ())
g_print ("layout changed, ");
}
else
{
if (g_test_verbose ())
g_print ("layout did not change, ");
}
if (data->layout_changed != layout_should_change)
fail = TRUE;
if (fail)
{
if (g_test_verbose ())
g_print ("FAIL\n");
data->test_failed = TRUE;
}
else
{
if (g_test_verbose ())
g_print ("pass\n");
}
return fail;
}
static gboolean
do_tests (CallbackData *data)
{
PangoFontDescription *fd;
static const ClutterColor red = { 0xff, 0x00, 0x00, 0xff };
PangoAttrList *attr_list, *attr_list_copy;
PangoAttribute *attr;
/* TEST 1: change the text */
clutter_text_set_text (CLUTTER_TEXT (data->label), "Counter 0");
pango_layout_set_text (data->test_layout, "Counter 0", -1);
g_assert (check_result (data, "Change text", TRUE) == FALSE);
/* TEST 2: change a single character */
clutter_text_set_text (CLUTTER_TEXT (data->label), "Counter 1");
pango_layout_set_text (data->test_layout, "Counter 1", -1);
g_assert (check_result (data, "Change a single character", TRUE) == FALSE);
/* TEST 3: move the label */
clutter_actor_set_position (data->label, 10, 0);
g_assert (check_result (data, "Move the label", FALSE) == FALSE);
/* TEST 4: change the font */
clutter_text_set_font_name (CLUTTER_TEXT (data->label), "Serif 15");
fd = pango_font_description_from_string ("Serif 15");
pango_layout_set_font_description (data->test_layout, fd);
pango_font_description_free (fd);
g_assert (check_result (data, "Change the font", TRUE) == FALSE);
/* TEST 5: change the color */
clutter_text_set_color (CLUTTER_TEXT (data->label), &red);
g_assert (check_result (data, "Change the color", FALSE) == FALSE);
/* TEST 6: change the attributes */
attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
attr->start_index = 0;
attr->end_index = 2;
attr_list = pango_attr_list_new ();
pango_attr_list_insert (attr_list, attr);
attr_list_copy = pango_attr_list_copy (attr_list);
clutter_text_set_attributes (CLUTTER_TEXT (data->label), attr_list);
pango_layout_set_attributes (data->test_layout, attr_list_copy);
pango_attr_list_unref (attr_list_copy);
pango_attr_list_unref (attr_list);
g_assert (check_result (data, "Change the attributes", TRUE) == FALSE);
/* TEST 7: change the text again */
clutter_text_set_attributes (CLUTTER_TEXT (data->label), NULL);
clutter_text_set_text (CLUTTER_TEXT (data->label), long_text);
pango_layout_set_attributes (data->test_layout, NULL);
pango_layout_set_text (data->test_layout, long_text, -1);
g_assert (check_result (data, "Change the text again", TRUE) == FALSE);
/* TEST 8: enable markup */
clutter_text_set_use_markup (CLUTTER_TEXT (data->label), TRUE);
pango_layout_set_markup (data->test_layout, long_text, -1);
g_assert (check_result (data, "Enable markup", TRUE) == FALSE);
/* This part can't be a test because Clutter won't restrict the
width if wrapping and ellipsizing is disabled so the extents will
be different, but we still want to do it for the later tests */
clutter_actor_set_width (data->label, 200);
pango_layout_set_width (data->test_layout, 200 * PANGO_SCALE);
/* Force a redraw so that changing the width won't affect the
results */
force_redraw (data);
/* TEST 9: enable ellipsize */
clutter_text_set_ellipsize (CLUTTER_TEXT (data->label),
PANGO_ELLIPSIZE_END);
pango_layout_set_ellipsize (data->test_layout, PANGO_ELLIPSIZE_END);
g_assert (check_result (data, "Enable ellipsize", TRUE) == FALSE);
clutter_text_set_ellipsize (CLUTTER_TEXT (data->label),
PANGO_ELLIPSIZE_NONE);
pango_layout_set_ellipsize (data->test_layout, PANGO_ELLIPSIZE_NONE);
force_redraw (data);
/* TEST 10: enable line wrap */
clutter_text_set_line_wrap (CLUTTER_TEXT (data->label), TRUE);
pango_layout_set_wrap (data->test_layout, PANGO_WRAP_WORD);
g_assert (check_result (data, "Enable line wrap", TRUE) == FALSE);
/* TEST 11: change wrap mode
* FIXME - broken
*/
clutter_text_set_line_wrap_mode (CLUTTER_TEXT (data->label),
PANGO_WRAP_CHAR);
pango_layout_set_wrap (data->test_layout, PANGO_WRAP_CHAR);
g_assert (check_result (data, "Change wrap mode", TRUE) == FALSE);
/* TEST 12: enable justify */
clutter_text_set_justify (CLUTTER_TEXT (data->label), TRUE);
pango_layout_set_justify (data->test_layout, TRUE);
/* Pango appears to have a bug which means that you can't change the
justification after setting the text but this fixes it.
See http://bugzilla.gnome.org/show_bug.cgi?id=551865 */
pango_layout_context_changed (data->test_layout);
g_assert (check_result (data, "Enable justify", TRUE) == FALSE);
/* TEST 13: change alignment */
clutter_text_set_line_alignment (CLUTTER_TEXT (data->label),
PANGO_ALIGN_RIGHT);
pango_layout_set_alignment (data->test_layout, PANGO_ALIGN_RIGHT);
g_assert (check_result (data, "Change alignment", TRUE) == FALSE);
clutter_main_quit ();
return FALSE;
}
static PangoLayout *
make_layout_like_label (ClutterText *label)
{
PangoLayout *label_layout, *new_layout;
PangoContext *context;
PangoFontDescription *fd;
/* Make another layout using the same context as the layout from the
label */
label_layout = clutter_text_get_layout (label);
context = pango_layout_get_context (label_layout);
new_layout = pango_layout_new (context);
fd = pango_font_description_from_string (TEST_FONT);
pango_layout_set_font_description (new_layout, fd);
pango_font_description_free (fd);
return new_layout;
}
void
text_cache (void)
{
CallbackData data;
memset (&data, 0, sizeof (data));
data.stage = clutter_stage_new ();
data.label = clutter_text_new_with_text (TEST_FONT, "");
data.test_layout = make_layout_like_label (CLUTTER_TEXT (data.label));
g_signal_connect (data.stage, "paint", G_CALLBACK (on_paint), &data);
clutter_container_add (CLUTTER_CONTAINER (data.stage), data.label, NULL);
clutter_actor_show (data.stage);
clutter_threads_add_idle ((GSourceFunc) do_tests, &data);
clutter_main ();
clutter_actor_destroy (data.stage);
if (g_test_verbose ())
g_print ("\nOverall result: ");
if (g_test_verbose ())
{
if (data.test_failed)
g_print ("FAIL\n");
else
g_print ("pass\n");
}
else
g_assert (data.test_failed != TRUE);
}

View File

@ -0,0 +1,563 @@
#include <glib.h>
#include <clutter/clutter.h>
#include <string.h>
typedef struct {
gunichar unichar;
const char bytes[6];
gint nbytes;
} TestData;
static const TestData
test_text_data[] = {
{ 0xe4, "\xc3\xa4", 2 }, /* LATIN SMALL LETTER A WITH DIAERESIS */
{ 0x2665, "\xe2\x99\xa5", 3 } /* BLACK HEART SUIT */
};
static void
text_utf8_validation (void)
{
int i;
for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
{
const TestData *t = &test_text_data[i];
gunichar unichar;
char bytes[6];
int nbytes;
g_assert (g_unichar_validate (t->unichar));
nbytes = g_unichar_to_utf8 (t->unichar, bytes);
bytes[nbytes] = '\0';
g_assert_cmpint (nbytes, ==, t->nbytes);
g_assert (memcmp (t->bytes, bytes, nbytes) == 0);
unichar = g_utf8_get_char_validated (bytes, nbytes);
g_assert_cmpint (unichar, ==, t->unichar);
}
}
static int
get_nbytes (ClutterText *text)
{
const char *s = clutter_text_get_text (text);
return strlen (s);
}
static int
get_nchars (ClutterText *text)
{
const char *s = clutter_text_get_text (text);
g_assert (g_utf8_validate (s, -1, NULL));
return g_utf8_strlen (s, -1);
}
#define DONT_MOVE_CURSOR (-2)
static void
insert_unichar (ClutterText *text, gunichar unichar, int position)
{
if (position > DONT_MOVE_CURSOR)
{
clutter_text_set_cursor_position (text, position);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, position);
}
clutter_text_insert_unichar (text, unichar);
}
static void
text_set_empty (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
g_object_ref_sink (text);
g_assert_cmpstr (clutter_text_get_text (text), ==, "");
g_assert_cmpint (*clutter_text_get_text (text), ==, '\0');
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
clutter_text_set_text (text, "");
g_assert_cmpint (get_nchars (text), ==, 0);
g_assert_cmpint (get_nbytes (text), ==, 0);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_set_text (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
g_object_ref_sink (text);
clutter_text_set_text (text, "abcdef");
g_assert_cmpint (get_nchars (text), ==, 6);
g_assert_cmpint (get_nbytes (text), ==, 6);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
clutter_text_set_cursor_position (text, 5);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 5);
/* FIXME: cursor position should be -1?
clutter_text_set_text (text, "");
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
*/
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_append_some (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
int i;
g_object_ref_sink (text);
for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
{
const TestData *t = &test_text_data[i];
int j;
for (j = 1; j <= 4; j++)
{
insert_unichar (text, t->unichar, DONT_MOVE_CURSOR);
g_assert_cmpint (get_nchars (text), ==, j);
g_assert_cmpint (get_nbytes (text), ==, j * t->nbytes);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
}
clutter_text_set_text (text, "");
}
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_prepend_some (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
int i;
g_object_ref_sink (text);
for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
{
const TestData *t = &test_text_data[i];
int j;
clutter_text_insert_unichar (text, t->unichar);
g_assert_cmpint (get_nchars (text), ==, 1);
g_assert_cmpint (get_nbytes (text), ==, 1 * t->nbytes);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
for (j = 2; j <= 4; j++)
{
insert_unichar (text, t->unichar, 0);
g_assert_cmpint (get_nchars (text), ==, j);
g_assert_cmpint (get_nbytes (text), ==, j * t->nbytes);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1);
}
clutter_text_set_text (text, "");
}
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_insert (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
int i;
g_object_ref_sink (text);
for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
{
const TestData *t = &test_text_data[i];
clutter_text_insert_unichar (text, t->unichar);
clutter_text_insert_unichar (text, t->unichar);
insert_unichar (text, t->unichar, 1);
g_assert_cmpint (get_nchars (text), ==, 3);
g_assert_cmpint (get_nbytes (text), ==, 3 * t->nbytes);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 2);
clutter_text_set_text (text, "");
}
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_delete_chars (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
int i;
g_object_ref_sink (text);
for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
{
const TestData *t = &test_text_data[i];
int j;
for (j = 0; j < 4; j++)
clutter_text_insert_unichar (text, t->unichar);
if (g_test_verbose ())
g_print ("text: %s\n", clutter_text_get_text (text));
clutter_text_set_cursor_position (text, 2);
clutter_text_delete_chars (text, 1);
if (g_test_verbose ())
g_print ("text: %s (cursor at: %d)\n",
clutter_text_get_text (text),
clutter_text_get_cursor_position (text));
g_assert_cmpint (get_nchars (text), ==, 3);
g_assert_cmpint (get_nbytes (text), ==, 3 * t->nbytes);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1);
clutter_text_set_cursor_position (text, 2);
clutter_text_delete_chars (text, 1);
if (g_test_verbose ())
g_print ("text: %s (cursor at: %d)\n",
clutter_text_get_text (text),
clutter_text_get_cursor_position (text));
g_assert_cmpint (get_nchars (text), ==, 2);
g_assert_cmpint (get_nbytes (text), ==, 2 * t->nbytes);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1);
clutter_text_set_text (text, "");
}
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_get_chars (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
gchar *chars;
g_object_ref_sink (text);
clutter_text_set_text (text, "00abcdef11");
g_assert_cmpint (get_nchars (text), ==, 10);
g_assert_cmpint (get_nbytes (text), ==, 10);
g_assert_cmpstr (clutter_text_get_text (text), ==, "00abcdef11");
chars = clutter_text_get_chars (text, 2, -1);
g_assert_cmpstr (chars, ==, "abcdef11");
g_free (chars);
chars = clutter_text_get_chars (text, 0, 8);
g_assert_cmpstr (chars, ==, "00abcdef");
g_free (chars);
chars = clutter_text_get_chars (text, 2, 8);
g_assert_cmpstr (chars, ==, "abcdef");
g_free (chars);
chars = clutter_text_get_chars (text, 8, 12);
g_assert_cmpstr (chars, ==, "11");
g_free (chars);
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_delete_text (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
int i;
g_object_ref_sink (text);
for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
{
const TestData *t = &test_text_data[i];
int j;
for (j = 0; j < 4; j++)
clutter_text_insert_unichar (text, t->unichar);
clutter_text_set_cursor_position (text, 3);
clutter_text_delete_text (text, 2, 4);
g_assert_cmpint (get_nchars (text), ==, 2);
g_assert_cmpint (get_nbytes (text), ==, 2 * t->nbytes);
/* FIXME: cursor position should be -1?
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
*/
clutter_text_set_text (text, "");
}
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_password_char (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
g_object_ref_sink (text);
g_assert_cmpint (clutter_text_get_password_char (text), ==, 0);
clutter_text_set_text (text, "hello");
g_assert_cmpstr (clutter_text_get_text (text), ==, "hello");
clutter_text_set_password_char (text, '*');
g_assert_cmpint (clutter_text_get_password_char (text), ==, '*');
g_assert_cmpstr (clutter_text_get_text (text), ==, "hello");
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static ClutterEvent *
init_event (void)
{
ClutterEvent *retval = clutter_event_new (CLUTTER_KEY_PRESS);
clutter_event_set_time (retval, CLUTTER_CURRENT_TIME);
clutter_event_set_flags (retval, CLUTTER_EVENT_FLAG_SYNTHETIC);
return retval;
}
static void
send_keyval (ClutterText *text, int keyval)
{
ClutterEvent *event = init_event ();
/* Unicode should be ignored for cursor keys etc. */
clutter_event_set_key_unicode (event, 0);
clutter_event_set_key_symbol (event, keyval);
clutter_actor_event (CLUTTER_ACTOR (text), event, FALSE);
clutter_event_free (event);
}
static void
send_unichar (ClutterText *text, gunichar unichar)
{
ClutterEvent *event = init_event ();
/* Key symbol should be ignored for printable characters */
clutter_event_set_key_symbol (event, 0);
clutter_event_set_key_unicode (event, unichar);
clutter_actor_event (CLUTTER_ACTOR (text), event, FALSE);
clutter_event_free (event);
}
static void
text_cursor (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
int i;
g_object_ref_sink (text);
/* only editable entries listen to events */
clutter_text_set_editable (text, TRUE);
for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
{
const TestData *t = &test_text_data[i];
int j;
for (j = 0; j < 4; ++j)
clutter_text_insert_unichar (text, t->unichar);
clutter_text_set_cursor_position (text, 2);
/* test cursor moves and is clamped */
send_keyval (text, CLUTTER_KEY_Left);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1);
send_keyval (text, CLUTTER_KEY_Left);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 0);
send_keyval (text, CLUTTER_KEY_Left);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 0);
/* delete text containing the cursor */
clutter_text_set_cursor_position (text, 3);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 3);
clutter_text_delete_text (text, 2, 4);
send_keyval (text, CLUTTER_KEY_Left);
/* FIXME: cursor position should be -1?
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
*/
clutter_text_set_text (text, "");
}
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static void
text_event (void)
{
ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
int i;
g_object_ref_sink (text);
/* only editable entries listen to events */
clutter_text_set_editable (text, TRUE);
for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
{
const TestData *t = &test_text_data[i];
send_unichar (text, t->unichar);
g_assert_cmpint (get_nchars (text), ==, 1);
g_assert_cmpint (get_nbytes (text), ==, 1 * t->nbytes);
g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
clutter_text_set_text (text, "");
}
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
static inline void
validate_markup_attributes (ClutterText *text,
PangoAttrType attr_type,
int start_index,
int end_index)
{
PangoLayout *layout;
PangoAttrList *attrs;
PangoAttrIterator *iter;
layout = clutter_text_get_layout (text);
g_assert (layout != NULL);
attrs = pango_layout_get_attributes (layout);
g_assert (attrs != NULL);
iter = pango_attr_list_get_iterator (attrs);
while (pango_attr_iterator_next (iter))
{
GSList *attributes = pango_attr_iterator_get_attrs (iter);
PangoAttribute *a;
if (attributes == NULL)
break;
g_assert (attributes->data != NULL);
a = attributes->data;
if (a->klass->type == PANGO_ATTR_SCALE)
{
PangoAttrFloat *scale = (PangoAttrFloat*) a;
float resource_scale;
if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (text), &resource_scale))
resource_scale = 1.0;
g_assert_cmpfloat (scale->value, ==, resource_scale);
g_slist_free_full (attributes, (GDestroyNotify) pango_attribute_destroy);
continue;
}
g_assert (a->klass->type == attr_type);
g_assert_cmpint (a->start_index, ==, start_index);
g_assert_cmpint (a->end_index, ==, end_index);
g_slist_free_full (attributes, (GDestroyNotify) pango_attribute_destroy);
}
pango_attr_iterator_destroy (iter);
}
static void
text_idempotent_use_markup (void)
{
ClutterText *text;
const char *contents = "foo <b>bar</b>";
const char *display = "foo bar";
int bar_start_index = strstr (display, "bar") - display;
int bar_end_index = bar_start_index + strlen ("bar");
/* case 1: text -> use_markup */
if (g_test_verbose ())
g_print ("text: '%s' -> use-markup: TRUE\n", contents);
text = g_object_new (CLUTTER_TYPE_TEXT,
"text", contents, "use-markup", TRUE,
NULL);
g_object_ref_sink (text);
if (g_test_verbose ())
g_print ("Contents: '%s' (expected: '%s')\n",
clutter_text_get_text (text),
display);
g_assert_cmpstr (clutter_text_get_text (text), ==, display);
validate_markup_attributes (text,
PANGO_ATTR_WEIGHT,
bar_start_index,
bar_end_index);
clutter_actor_destroy (CLUTTER_ACTOR (text));
/* case 2: use_markup -> text */
if (g_test_verbose ())
g_print ("use-markup: TRUE -> text: '%s'\n", contents);
text = g_object_new (CLUTTER_TYPE_TEXT,
"use-markup", TRUE, "text", contents,
NULL);
if (g_test_verbose ())
g_print ("Contents: '%s' (expected: '%s')\n",
clutter_text_get_text (text),
display);
g_assert_cmpstr (clutter_text_get_text (text), ==, display);
validate_markup_attributes (text,
PANGO_ATTR_WEIGHT,
bar_start_index,
bar_end_index);
clutter_actor_destroy (CLUTTER_ACTOR (text));
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/text/utf8-validation", text_utf8_validation)
CLUTTER_TEST_UNIT ("/text/set-empty", text_set_empty)
CLUTTER_TEST_UNIT ("/text/set-text", text_set_text)
CLUTTER_TEST_UNIT ("/text/append-some", text_append_some)
CLUTTER_TEST_UNIT ("/text/prepend-some", text_prepend_some)
CLUTTER_TEST_UNIT ("/text/insert", text_insert)
CLUTTER_TEST_UNIT ("/text/delete-chars", text_delete_chars)
CLUTTER_TEST_UNIT ("/text/get-chars", text_get_chars)
CLUTTER_TEST_UNIT ("/text/delete-text", text_delete_text)
CLUTTER_TEST_UNIT ("/text/password-char", text_password_char)
CLUTTER_TEST_UNIT ("/text/cursor", text_cursor)
CLUTTER_TEST_UNIT ("/text/event", text_event)
CLUTTER_TEST_UNIT ("/text/idempotent-use-markup", text_idempotent_use_markup)
)

View File

@ -0,0 +1,235 @@
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include "test-conform-common.h"
#define SOURCE_SIZE 32
#define SOURCE_DIVISIONS_X 2
#define SOURCE_DIVISIONS_Y 2
#define DIVISION_WIDTH (SOURCE_SIZE / SOURCE_DIVISIONS_X)
#define DIVISION_HEIGHT (SOURCE_SIZE / SOURCE_DIVISIONS_Y)
static const ClutterColor
corner_colors[SOURCE_DIVISIONS_X * SOURCE_DIVISIONS_Y] =
{
{ 0xff, 0x00, 0x00, 0xff }, /* red top left */
{ 0x00, 0xff, 0x00, 0xff }, /* green top right */
{ 0x00, 0x00, 0xff, 0xff }, /* blue bottom left */
{ 0xff, 0x00, 0xff, 0xff } /* purple bottom right */
};
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
typedef struct _TestState
{
ClutterActor *stage;
guint frame;
gboolean was_painted;
} TestState;
static ClutterActor *
create_source (void)
{
int x, y;
ClutterActor *group = clutter_group_new ();
/* Create a group with a different coloured rectangle at each
corner */
for (y = 0; y < SOURCE_DIVISIONS_Y; y++)
for (x = 0; x < SOURCE_DIVISIONS_X; x++)
{
ClutterActor *rect = clutter_rectangle_new ();
clutter_actor_set_size (rect, DIVISION_WIDTH, DIVISION_HEIGHT);
clutter_actor_set_position (rect,
DIVISION_WIDTH * x,
DIVISION_HEIGHT * y);
clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect),
corner_colors +
(y * SOURCE_DIVISIONS_X + x));
clutter_container_add (CLUTTER_CONTAINER (group), rect, NULL);
}
return group;
}
static void
pre_paint_clip_cb (void)
{
/* Generate a clip path that clips out the top left division */
cogl_path_move_to (DIVISION_WIDTH, 0);
cogl_path_line_to (SOURCE_SIZE, 0);
cogl_path_line_to (SOURCE_SIZE, SOURCE_SIZE);
cogl_path_line_to (0, SOURCE_SIZE);
cogl_path_line_to (0, DIVISION_HEIGHT);
cogl_path_line_to (DIVISION_WIDTH, DIVISION_HEIGHT);
cogl_path_close ();
cogl_clip_push_from_path ();
}
static void
post_paint_clip_cb (void)
{
cogl_clip_pop ();
}
static void
validate_part (TestState *state,
int xpos, int ypos,
int clip_flags)
{
int x, y;
/* Check whether the center of each division is the right color */
for (y = 0; y < SOURCE_DIVISIONS_Y; y++)
for (x = 0; x < SOURCE_DIVISIONS_X; x++)
{
guchar *pixels;
const ClutterColor *correct_color;
/* Read the center pixels of this division */
pixels = clutter_stage_read_pixels (CLUTTER_STAGE (state->stage),
x * DIVISION_WIDTH +
DIVISION_WIDTH / 2 + xpos,
y * DIVISION_HEIGHT +
DIVISION_HEIGHT / 2 + ypos,
1, 1);
/* If this division is clipped then it should be the stage
color */
if ((clip_flags & (1 << ((y * SOURCE_DIVISIONS_X) + x))))
correct_color = &stage_color;
else
/* Otherwise it should be the color for this division */
correct_color = corner_colors + (y * SOURCE_DIVISIONS_X) + x;
g_assert (pixels != NULL);
g_assert_cmpint (pixels[0], ==, correct_color->red);
g_assert_cmpint (pixels[1], ==, correct_color->green);
g_assert_cmpint (pixels[2], ==, correct_color->blue);
g_free (pixels);
}
}
static void
validate_result (TestState *state)
{
int ypos = 0;
if (g_test_verbose ())
g_print ("Testing onscreen clone...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 0);
ypos++;
#if 0 /* this doesn't work */
if (g_test_verbose ())
g_print ("Testing offscreen clone...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 0);
#endif
ypos++;
if (g_test_verbose ())
g_print ("Testing onscreen clone with rectangular clip...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, ~1);
ypos++;
if (g_test_verbose ())
g_print ("Testing onscreen clone with path clip...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 1);
ypos++;
}
static gboolean
on_paint (gpointer data)
{
TestState *state = data;
int frame_num;
/* XXX: validate_result calls clutter_stage_read_pixels which will result in
* another paint run so to avoid infinite recursion we only aim to validate
* the first frame. */
frame_num = state->frame++;
if (frame_num == 1)
validate_result (state);
state->was_painted = TRUE;
return G_SOURCE_REMOVE;
}
void
texture_fbo (TestConformSimpleFixture *fixture,
gconstpointer data)
{
TestState state;
ClutterActor *actor;
int ypos = 0;
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
{
if (g_test_verbose ())
g_print ("Offscreen buffers are not available, skipping.\n");
return;
}
state.frame = 0;
state.stage = clutter_stage_new ();
clutter_stage_set_color (CLUTTER_STAGE (state.stage), &stage_color);
/* Onscreen source with clone next to it */
actor = create_source ();
clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL);
clutter_actor_set_position (actor, 0, ypos * SOURCE_SIZE);
actor = clutter_texture_new_from_actor (actor);
clutter_actor_set_position (actor, SOURCE_SIZE, ypos * SOURCE_SIZE);
clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL);
ypos++;
/* Offscreen source with clone */
#if 0 /* this doesn't work */
actor = create_source ();
actor = clutter_texture_new_from_actor (actor);
clutter_actor_set_position (actor, SOURCE_SIZE, ypos * SOURCE_SIZE);
clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL);
#endif
ypos++;
/* Source clipped to the top left division */
actor = create_source ();
clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL);
clutter_actor_set_position (actor, 0, ypos * SOURCE_SIZE);
clutter_actor_set_clip (actor, 0, 0, DIVISION_WIDTH, DIVISION_HEIGHT);
actor = clutter_texture_new_from_actor (actor);
clutter_actor_set_position (actor, SOURCE_SIZE, ypos * SOURCE_SIZE);
clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL);
ypos++;
/* Source clipped to everything but top left division using a
path */
actor = create_source ();
clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL);
clutter_actor_set_position (actor, 0, ypos * SOURCE_SIZE);
g_signal_connect (actor, "paint",
G_CALLBACK (pre_paint_clip_cb), NULL);
g_signal_connect_after (actor, "paint",
G_CALLBACK (post_paint_clip_cb), NULL);
actor = clutter_texture_new_from_actor (actor);
clutter_actor_set_position (actor, SOURCE_SIZE, ypos * SOURCE_SIZE);
clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL);
ypos++;
clutter_actor_show (state.stage);
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
on_paint,
&state,
NULL);
while (!state.was_painted)
g_main_context_iteration (NULL, FALSE);
clutter_actor_destroy (state.stage);
}

View File

@ -0,0 +1,84 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <clutter/clutter.h>
#include <string.h>
static CoglHandle
make_texture (void)
{
guint32 *data = g_malloc (100 * 100 * 4);
int x;
int y;
for (y = 0; y < 100; y ++)
for (x = 0; x < 100; x++)
{
if (x < 50 && y < 50)
data[y * 100 + x] = 0xff00ff00;
else
data[y * 100 + x] = 0xff00ffff;
}
return cogl_texture_new_from_data (100,
100,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_ARGB_8888,
COGL_PIXEL_FORMAT_ARGB_8888,
400,
(guchar *)data);
}
static void
texture_pick_with_alpha (void)
{
ClutterTexture *tex = CLUTTER_TEXTURE (clutter_texture_new ());
ClutterStage *stage = CLUTTER_STAGE (clutter_test_get_stage ());
ClutterActor *actor;
clutter_texture_set_cogl_texture (tex, make_texture ());
clutter_actor_add_child (CLUTTER_ACTOR (stage), CLUTTER_ACTOR (tex));
clutter_actor_show (CLUTTER_ACTOR (stage));
if (g_test_verbose ())
{
g_print ("\nstage = %p\n", stage);
g_print ("texture = %p\n\n", tex);
}
clutter_texture_set_pick_with_alpha (tex, TRUE);
if (g_test_verbose ())
g_print ("Testing with pick-with-alpha enabled:\n");
/* This should fall through and hit the stage: */
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 10);
if (g_test_verbose ())
g_print ("actor @ (10, 10) = %p\n", actor);
g_assert (actor == CLUTTER_ACTOR (stage));
/* The rest should hit the texture */
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 90, 10);
if (g_test_verbose ())
g_print ("actor @ (90, 10) = %p\n", actor);
g_assert (actor == CLUTTER_ACTOR (tex));
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 90, 90);
if (g_test_verbose ())
g_print ("actor @ (90, 90) = %p\n", actor);
g_assert (actor == CLUTTER_ACTOR (tex));
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 90);
if (g_test_verbose ())
g_print ("actor @ (10, 90) = %p\n", actor);
g_assert (actor == CLUTTER_ACTOR (tex));
clutter_texture_set_pick_with_alpha (tex, FALSE);
if (g_test_verbose ())
g_print ("Testing with pick-with-alpha disabled:\n");
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL, 10, 10);
if (g_test_verbose ())
g_print ("actor @ (10, 10) = %p\n", actor);
g_assert (actor == CLUTTER_ACTOR (tex));
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/texture/pick-with-alpha", texture_pick_with_alpha)
)

View File

@ -0,0 +1,161 @@
#include <stdlib.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
/* We ask for 1 frame per millisecond.
* Whenever this rate can't be achieved then the timeline
* will interpolate the number frames that should have
* passed between timeouts. */
#define TEST_TIMELINE_FPS 1000
#define TEST_TIMELINE_DURATION 5000
/* We are at the mercy of the system scheduler so this
* may not be a very reliable tolerance. */
#define TEST_ERROR_TOLERANCE 20
typedef struct _TestState
{
ClutterTimeline *timeline;
int64_t start_time;
guint new_frame_counter;
gint expected_frame;
gint completion_count;
gboolean passed;
} TestState;
static void
new_frame_cb (ClutterTimeline *timeline,
gint frame_num,
TestState *state)
{
int64_t current_time;
gint current_frame;
glong msec_diff;
gint loop_overflow = 0;
static gint step = 1;
current_time = g_get_real_time ();
current_frame = clutter_timeline_get_elapsed_time (state->timeline);
msec_diff = (current_time - state->start_time) / G_TIME_SPAN_MILLISECOND;
/* If we expect to have interpolated past the end of the timeline
* we keep track of the overflow so we can determine when
* the next timeout will happen. We then clip expected_frames
* to TEST_TIMELINE_DURATION since clutter-timeline
* semantics guaranty this frame is always signaled before
* looping */
if (state->expected_frame > TEST_TIMELINE_DURATION)
{
loop_overflow = state->expected_frame - TEST_TIMELINE_DURATION;
state->expected_frame = TEST_TIMELINE_DURATION;
}
if (current_frame >= (state->expected_frame-TEST_ERROR_TOLERANCE)
&& current_frame <= (state->expected_frame+TEST_ERROR_TOLERANCE))
{
g_test_message ("elapsed milliseconds=%-5li "
"expected frame=%-4i actual frame=%-4i (OK)",
msec_diff,
state->expected_frame,
current_frame);
}
else
{
g_test_message ("elapsed milliseconds=%-5li "
"expected frame=%-4i actual frame=%-4i (FAILED)",
msec_diff,
state->expected_frame,
current_frame);
state->passed = FALSE;
}
if (step>0)
{
state->expected_frame = current_frame + (TEST_TIMELINE_FPS / 4);
g_test_message ("Sleeping for 250ms "
"so next frame should be (%i + %i) = %i",
current_frame,
(TEST_TIMELINE_FPS / 4),
state->expected_frame);
g_usleep (250000);
}
else
{
state->expected_frame = current_frame + TEST_TIMELINE_FPS;
g_test_message ("Sleeping for 1sec "
"so next frame should be (%i + %i) = %i",
current_frame,
TEST_TIMELINE_FPS,
state->expected_frame);
g_usleep (1000000);
}
if (current_frame >= TEST_TIMELINE_DURATION)
{
state->expected_frame += loop_overflow;
state->expected_frame -= TEST_TIMELINE_DURATION;
g_test_message ("End of timeline reached: "
"Wrapping expected frame too %i",
state->expected_frame);
}
state->new_frame_counter++;
step = -step;
}
static void
completed_cb (ClutterTimeline *timeline,
TestState *state)
{
state->completion_count++;
if (state->completion_count == 2)
{
if (state->passed)
{
g_test_message ("Passed\n");
clutter_main_quit ();
}
else
{
g_test_message ("Failed\n");
exit (EXIT_FAILURE);
}
}
}
void
timeline_interpolation (void)
{
TestState state;
state.timeline =
clutter_timeline_new (TEST_TIMELINE_DURATION);
clutter_timeline_set_loop (state.timeline, TRUE);
g_signal_connect (G_OBJECT(state.timeline),
"new-frame",
G_CALLBACK(new_frame_cb),
&state);
g_signal_connect (G_OBJECT(state.timeline),
"completed",
G_CALLBACK(completed_cb),
&state);
state.completion_count = 0;
state.new_frame_counter = 0;
state.passed = TRUE;
state.expected_frame = 0;
state.start_time = g_get_real_time ();
clutter_timeline_start (state.timeline);
clutter_main();
g_object_unref (state.timeline);
}

View File

@ -0,0 +1,110 @@
#include <glib.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
void
timeline_progress_step (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
gconstpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline;
timeline = clutter_timeline_new (1000);
if (g_test_verbose ())
g_print ("mode: step(3, end)\n");
clutter_timeline_rewind (timeline);
clutter_timeline_set_step_progress (timeline, 3, CLUTTER_STEP_MODE_END);
g_assert_cmpint (clutter_timeline_get_progress (timeline), ==, 0);
clutter_timeline_advance (timeline, 1000 / 3 - 1);
g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 0);
clutter_timeline_advance (timeline, 1000 / 3 + 1);
g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 333);
clutter_timeline_advance (timeline, 1000 / 3 * 2 - 1);
g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 333);
clutter_timeline_advance (timeline, 1000 / 3 * 2 + 1);
g_assert_cmpint (clutter_timeline_get_progress (timeline) * 1000, ==, 666);
clutter_timeline_rewind (timeline);
clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_START);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
clutter_timeline_advance (timeline, 1);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
clutter_timeline_advance (timeline, 500);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
clutter_timeline_advance (timeline, 999);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
clutter_timeline_advance (timeline, 1000);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
if (g_test_verbose ())
g_print ("mode: step-start\n");
clutter_timeline_rewind (timeline);
clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_START);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
clutter_timeline_advance (timeline, 1);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
clutter_timeline_advance (timeline, 500);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
clutter_timeline_advance (timeline, 999);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
clutter_timeline_advance (timeline, 1000);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
if (g_test_verbose ())
g_print ("mode: step-end\n");
clutter_timeline_rewind (timeline);
clutter_timeline_set_progress_mode (timeline, CLUTTER_STEP_END);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
clutter_timeline_advance (timeline, 1);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
clutter_timeline_advance (timeline, 500);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
clutter_timeline_advance (timeline, 999);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
clutter_timeline_advance (timeline, 1000);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
g_object_unref (timeline);
}
void
timeline_progress_mode (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
gconstpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline;
timeline = clutter_timeline_new (1000);
g_assert (clutter_timeline_get_progress_mode (timeline) == CLUTTER_LINEAR);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
clutter_timeline_advance (timeline, 500);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.5);
clutter_timeline_advance (timeline, 1000);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
clutter_timeline_rewind (timeline);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 0.0);
g_object_unref (timeline);
}

View File

@ -0,0 +1,92 @@
#include <stdlib.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
#define TEST_TIMELINE_DURATION 500
#define TEST_WATCHDOG_KICK_IN_SECONDS 10
typedef struct _TestState
{
ClutterTimeline *timeline;
gint rewind_count;
} TestState;
static gboolean
watchdog_timeout (gpointer data)
{
TestState *state = data;
g_test_message ("Watchdog timer kicking in");
g_test_message ("rewind_count=%i", state->rewind_count);
if (state->rewind_count <= 3)
{
/* The test has hung */
g_test_message ("Failed (This test shouldn't have hung!)");
exit (EXIT_FAILURE);
}
else
{
g_test_message ("Passed");
clutter_main_quit ();
}
return G_SOURCE_REMOVE;
}
static void
new_frame_cb (ClutterTimeline *timeline,
gint elapsed_time,
TestState *state)
{
if (elapsed_time == TEST_TIMELINE_DURATION)
{
g_test_message ("new-frame signal received (end of timeline)");
g_test_message ("Rewinding timeline");
clutter_timeline_rewind (timeline);
state->rewind_count++;
}
else
{
if (elapsed_time == 0)
{
g_test_message ("new-frame signal received (start of timeline)");
}
else
{
g_test_message ("new-frame signal received (mid frame)");
}
if (state->rewind_count >= 2)
{
g_test_message ("Sleeping for 1 second");
g_usleep (1000000);
}
}
}
void
timeline_rewind (void)
{
TestState state;
state.timeline =
clutter_timeline_new (TEST_TIMELINE_DURATION);
g_signal_connect (G_OBJECT(state.timeline),
"new-frame",
G_CALLBACK(new_frame_cb),
&state);
g_test_message ("Installing a watchdog timeout "
"to determine if this test hangs");
clutter_threads_add_timeout (TEST_WATCHDOG_KICK_IN_SECONDS * 1000,
watchdog_timeout,
&state);
state.rewind_count = 0;
clutter_timeline_start (state.timeline);
clutter_main();
g_object_unref (state.timeline);
}

View File

@ -0,0 +1,361 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
/* This test runs three timelines at 30 fps with 10 frames. Some of
the timelines have markers. Once the timelines are run it then
checks that all of the frames were hit, all of the markers were hit
and that the completed signal was fired. The timelines are then run
again but this time with a timeout source that introduces a
delay. This should cause some frames to be skipped. The test is run
again but only the markers and the completed signal is checked
for. */
#define FRAME_COUNT 10
#define FPS 30
typedef struct _TimelineData TimelineData;
struct _TimelineData
{
int timeline_num;
guint frame_hit_count[FRAME_COUNT + 1];
GSList *markers_hit;
guint completed_count;
};
static void
timeline_data_init (TimelineData *data, int timeline_num)
{
memset (data, 0, sizeof (TimelineData));
data->timeline_num = timeline_num;
}
static void
timeline_data_destroy (TimelineData *data)
{
g_slist_free_full (data->markers_hit, g_free);
}
static void
timeline_complete_cb (ClutterTimeline *timeline,
TimelineData *data)
{
if (g_test_verbose ())
g_print ("%i: Completed\n", data->timeline_num);
data->completed_count++;
}
static void
timeline_new_frame_cb (ClutterTimeline *timeline,
gint msec,
TimelineData *data)
{
/* Calculate an approximate frame number from the duration with
rounding */
int frame_no = ((msec * FRAME_COUNT + (FRAME_COUNT * 1000 / FPS) / 2)
/ (FRAME_COUNT * 1000 / FPS));
if (g_test_verbose ())
g_print ("%i: Doing frame %d, delta = %i\n",
data->timeline_num, frame_no,
clutter_timeline_get_delta (timeline));
g_assert (frame_no >= 0 && frame_no <= FRAME_COUNT);
data->frame_hit_count[frame_no]++;
}
static void
timeline_marker_reached_cb (ClutterTimeline *timeline,
const gchar *marker_name,
guint frame_num,
TimelineData *data)
{
if (g_test_verbose ())
g_print ("%i: Marker '%s' (%d) reached, delta = %i\n",
data->timeline_num, marker_name, frame_num,
clutter_timeline_get_delta (timeline));
data->markers_hit = g_slist_prepend (data->markers_hit,
g_strdup (marker_name));
}
static gboolean
check_timeline (ClutterTimeline *timeline,
TimelineData *data,
gboolean check_missed_frames)
{
gchar **markers;
gsize n_markers;
guint *marker_reached_count;
gboolean succeeded = TRUE;
GSList *node;
int i;
int missed_frame_count = 0;
int frame_offset;
if (clutter_timeline_get_direction (timeline) == CLUTTER_TIMELINE_BACKWARD)
frame_offset = 0;
else
frame_offset = 1;
markers = clutter_timeline_list_markers (timeline, -1, &n_markers);
marker_reached_count = g_new0 (guint, n_markers);
for (node = data->markers_hit; node; node = node->next)
{
for (i = 0; i < n_markers; i++)
if (!strcmp (node->data, markers[i]))
break;
if (i < n_markers)
marker_reached_count[i]++;
else
{
if (g_test_verbose ())
g_print ("FAIL: unknown marker '%s' hit for timeline %i\n",
(char *) node->data, data->timeline_num);
succeeded = FALSE;
}
}
for (i = 0; i < n_markers; i++)
if (marker_reached_count[i] != 1)
{
if (g_test_verbose ())
g_print ("FAIL: marker '%s' hit %i times for timeline %i\n",
markers[i], marker_reached_count[i], data->timeline_num);
succeeded = FALSE;
}
if (check_missed_frames)
{
for (i = 0; i < FRAME_COUNT; i++)
if (data->frame_hit_count[i + frame_offset] < 1)
missed_frame_count++;
if (missed_frame_count)
{
if (g_test_verbose ())
g_print ("FAIL: missed %i frame%s for timeline %i\n",
missed_frame_count, missed_frame_count == 1 ? "" : "s",
data->timeline_num);
succeeded = FALSE;
}
}
if (data->completed_count != 1)
{
if (g_test_verbose ())
g_print ("FAIL: timeline %i completed %i times\n",
data->timeline_num, data->completed_count);
succeeded = FALSE;
}
g_strfreev (markers);
g_free (marker_reached_count);
return succeeded;
}
static gboolean
timeout_cb (gpointer data G_GNUC_UNUSED)
{
clutter_main_quit ();
return FALSE;
}
static gboolean
delay_cb (gpointer data)
{
/* Waste a bit of time so that it will skip frames */
g_usleep (G_USEC_PER_SEC * 66 / 1000);
return TRUE;
}
void
timeline_base (TestConformSimpleFixture *fixture,
gconstpointer data)
{
ClutterTimeline *timeline_1;
TimelineData data_1;
ClutterTimeline *timeline_2;
TimelineData data_2;
ClutterTimeline *timeline_3;
TimelineData data_3;
gchar **markers;
gsize n_markers;
guint delay_tag;
/* NB: We have to ensure a stage is instantiated else the master
* clock wont run... */
ClutterActor *stage = clutter_stage_new ();
timeline_data_init (&data_1, 1);
timeline_1 = clutter_timeline_new (FRAME_COUNT * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_1, "start-marker",
0 * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_1, "foo", 5 * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_1, "bar", 5 * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_1, "baz", 5 * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_1, "near-end-marker",
9 * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_1, "end-marker",
10 * 1000 / FPS);
markers = clutter_timeline_list_markers (timeline_1, 5 * 1000 / FPS,
&n_markers);
g_assert (markers != NULL);
g_assert (n_markers == 3);
g_strfreev (markers);
timeline_data_init (&data_2, 2);
timeline_2 = clutter_timeline_clone (timeline_1);
clutter_timeline_add_marker_at_time (timeline_2, "bar", 2 * 1000 / FPS);
markers = clutter_timeline_list_markers (timeline_2, -1, &n_markers);
g_assert (markers != NULL);
g_assert (n_markers == 1);
g_assert (strcmp (markers[0], "bar") == 0);
g_strfreev (markers);
timeline_data_init (&data_3, 3);
timeline_3 = clutter_timeline_clone (timeline_1);
clutter_timeline_set_direction (timeline_3, CLUTTER_TIMELINE_BACKWARD);
clutter_timeline_add_marker_at_time (timeline_3, "start-marker",
FRAME_COUNT * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_3, "foo", 5 * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_3, "baz", 8 * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_3, "near-end-marker",
1 * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_3, "end-marker",
0 * 1000 / FPS);
g_signal_connect (timeline_1,
"marker-reached", G_CALLBACK (timeline_marker_reached_cb),
&data_1);
g_signal_connect (timeline_1,
"new-frame", G_CALLBACK (timeline_new_frame_cb),
&data_1);
g_signal_connect (timeline_1,
"completed", G_CALLBACK (timeline_complete_cb),
&data_1);
g_signal_connect (timeline_2,
"marker-reached::bar",
G_CALLBACK (timeline_marker_reached_cb),
&data_2);
g_signal_connect (timeline_2,
"new-frame", G_CALLBACK (timeline_new_frame_cb),
&data_2);
g_signal_connect (timeline_2,
"completed", G_CALLBACK (timeline_complete_cb),
&data_2);
g_signal_connect (timeline_3,
"marker-reached", G_CALLBACK (timeline_marker_reached_cb),
&data_3);
g_signal_connect (timeline_3,
"new-frame", G_CALLBACK (timeline_new_frame_cb),
&data_3);
g_signal_connect (timeline_3,
"completed", G_CALLBACK (timeline_complete_cb),
&data_3);
if (g_test_verbose ())
g_print ("Without delay...\n");
clutter_timeline_start (timeline_1);
clutter_timeline_start (timeline_2);
clutter_timeline_start (timeline_3);
clutter_threads_add_timeout (2000, timeout_cb, NULL);
clutter_main ();
g_assert (check_timeline (timeline_1, &data_1, TRUE));
g_assert (check_timeline (timeline_2, &data_2, TRUE));
g_assert (check_timeline (timeline_3, &data_3, TRUE));
if (g_test_verbose ())
g_print ("With delay...\n");
timeline_data_destroy (&data_1);
timeline_data_init (&data_1, 1);
timeline_data_destroy (&data_2);
timeline_data_init (&data_2, 2);
timeline_data_destroy (&data_3);
timeline_data_init (&data_3, 3);
clutter_timeline_start (timeline_1);
clutter_timeline_start (timeline_2);
clutter_timeline_start (timeline_3);
clutter_threads_add_timeout (2000, timeout_cb, NULL);
delay_tag = clutter_threads_add_timeout (99, delay_cb, NULL);
clutter_main ();
g_assert (check_timeline (timeline_1, &data_1, FALSE));
g_assert (check_timeline (timeline_2, &data_2, FALSE));
g_assert (check_timeline (timeline_3, &data_3, FALSE));
g_object_unref (timeline_1);
g_object_unref (timeline_2);
g_object_unref (timeline_3);
timeline_data_destroy (&data_1);
timeline_data_destroy (&data_2);
timeline_data_destroy (&data_3);
g_source_remove (delay_tag);
clutter_actor_destroy (stage);
}
void
timeline_markers_from_script (TestConformSimpleFixture *fixture,
gconstpointer data)
{
ClutterScript *script = clutter_script_new ();
ClutterTimeline *timeline;
GError *error = NULL;
gchar *test_file;
gchar **markers;
gsize n_markers;
test_file = clutter_test_get_data_file ("test-script-timeline-markers.json");
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error != NULL)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
timeline = CLUTTER_TIMELINE (clutter_script_get_object (script, "timeline0"));
g_assert (clutter_timeline_has_marker (timeline, "marker0"));
g_assert (clutter_timeline_has_marker (timeline, "marker1"));
g_assert (!clutter_timeline_has_marker (timeline, "foo"));
g_assert (clutter_timeline_has_marker (timeline, "marker2"));
g_assert (clutter_timeline_has_marker (timeline, "marker3"));
markers = clutter_timeline_list_markers (timeline, -1, &n_markers);
g_assert_cmpint (n_markers, ==, 4);
g_strfreev (markers);
markers = clutter_timeline_list_markers (timeline, 500, &n_markers);
g_assert_cmpint (n_markers, ==, 2);
g_assert (markers != NULL);
g_assert_cmpstr (markers[0], ==, "marker3");
g_assert_cmpstr (markers[1], ==, "marker1");
g_strfreev (markers);
g_object_unref (script);
g_free (test_file);
}

View File

@ -0,0 +1,131 @@
#include <clutter/clutter.h>
static void
units_cache (void)
{
ClutterUnits units;
ClutterSettings *settings;
gfloat pixels;
gint old_dpi;
settings = clutter_settings_get_default ();
g_object_get (settings, "font-dpi", &old_dpi, NULL);
g_object_set (settings, "font-dpi", 96 * 1024, NULL);
clutter_units_from_em (&units, 1.0);
pixels = clutter_units_to_pixels (&units);
g_object_set (settings, "font-dpi", ((96 * 2) * 1024), NULL);
g_assert_cmpfloat (clutter_units_to_pixels (&units), !=, pixels);
g_object_set (settings, "font-dpi", (96 * 1024), NULL);
g_assert_cmpfloat (clutter_units_to_pixels (&units), ==, pixels);
g_object_set (settings, "font-dpi", old_dpi, NULL);
}
static void
units_constructors (void)
{
ClutterUnits units, units_cm;
clutter_units_from_pixels (&units, 100);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 100.0);
g_assert_cmpfloat (clutter_units_to_pixels (&units), ==, 100.0);
clutter_units_from_em (&units, 5.0);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5.0);
g_assert_cmpfloat (clutter_units_to_pixels (&units), !=, 5.0);
clutter_units_from_cm (&units_cm, 5.0);
g_assert (clutter_units_get_unit_type (&units_cm) == CLUTTER_UNIT_CM);
g_assert_cmpfloat (clutter_units_get_unit_value (&units_cm), ==, 5.0);
g_assert_cmpfloat (clutter_units_to_pixels (&units_cm), !=, 5.0);
clutter_units_from_mm (&units, 50.0);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_MM);
g_assert_cmpfloat (clutter_units_to_pixels (&units),
==,
clutter_units_to_pixels (&units_cm));
}
static void
units_string (void)
{
ClutterUnits units;
gchar *string;
g_assert (clutter_units_from_string (&units, "") == FALSE);
g_assert (clutter_units_from_string (&units, "10") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 10);
g_assert (clutter_units_from_string (&units, "10 px") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL);
g_assert (clutter_units_from_string (&units, "10 mm") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_MM);
g_assert (clutter_units_from_string (&units, "10 cm") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_CM);
g_assert (clutter_units_from_string (&units, "10 ") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 10);
g_assert (clutter_units_from_string (&units, "5 em") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5);
g_assert (clutter_units_from_string (&units, "5 emeralds") == FALSE);
g_assert (clutter_units_from_string (&units, " 16 mm") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_MM);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 16);
g_assert (clutter_units_from_string (&units, " 24 pt ") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_POINT);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 24);
g_assert (clutter_units_from_string (&units, " 32 em garbage") == FALSE);
g_assert (clutter_units_from_string (&units, "5.1cm") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_CM);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5.1f);
g_assert (clutter_units_from_string (&units, "5,mm") == FALSE);
g_assert (clutter_units_from_string (&units, ".5pt") == TRUE);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_POINT);
g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 0.5f);
g_assert (clutter_units_from_string (&units, "1 omg!!pony") == FALSE);
clutter_units_from_pt (&units, 24.0);
string = clutter_units_to_string (&units);
g_assert_cmpstr (string, ==, "24.0 pt");
g_free (string);
clutter_units_from_em (&units, 3.0);
string = clutter_units_to_string (&units);
g_assert_cmpstr (string, ==, "3.00 em");
units.unit_type = CLUTTER_UNIT_PIXEL;
units.value = 0;
g_assert (clutter_units_from_string (&units, string) == TRUE);
g_assert (clutter_units_get_unit_type (&units) != CLUTTER_UNIT_PIXEL);
g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM);
g_assert_cmpint ((int) clutter_units_get_unit_value (&units), ==, 3);
g_free (string);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/units/string", units_string)
CLUTTER_TEST_UNIT ("/units/cache", units_cache)
CLUTTER_TEST_UNIT ("/units/constructors", units_constructors)
)

View File

@ -0,0 +1,55 @@
/stamp-test-interactive
/stamp-test-unit-names
/test-actors
/test-animation
/test-animator
/test-bind-constraint
/test-binding-pool
/test-cairo-clock
/test-cairo-flowers
/test-clip
/test-cogl-multitexture
/test-cogl-offscreen
/test-cogl-point-sprites
/test-cogl-primitives
/test-cogl-shader-glsl
/test-cogl-tex-convert
/test-cogl-tex-foreign
/test-cogl-tex-getset
/test-cogl-tex-polygon
/test-cogl-tex-tile
/test-cogl-vertex-buffer
/test-content
/test-devices
/test-easing
/test-events
/test-fbo
/test-grab
/test-image
/test-interactive
/test-keyframe-transition
/test-layout
/test-multistage
/test-paint-wrapper
/test-path-constraint
/test-pixmap
/test-rotate-zoom
/test-scale
/test-script
/test-scrolling
/test-shader-effects
/test-stage-read-pixels
/test-stage-sizing
/test-state
/test-state-animator
/test-state-script
/test-swipe-action
/test-table-layout
/test-text
/test-text-field
/test-texture-async
/test-texture-material
/test-texture-quality
/test-texture-slicing
/test-touch-events
/test-unit-names.h

View File

@ -0,0 +1,91 @@
clutter_tests_interactive_srcdir = meson.current_source_dir()
clutter_tests_interactive_includepath = include_directories('.')
clutter_tests_interactive_c_args = [
'-DTESTS_DATADIR="@0@"'.format(clutter_tests_interactive_srcdir),
'-DG_DISABLE_SINGLE_INCLUDES',
'-DGLIB_DISABLE_DEPRECATION_WARNINGS',
'-DCOGL_DISABLE_DEPRECATION_WARNINGS',
'-DCLUTTER_DISABLE_DEPRECATION_WARNINGS',
]
clutter_tests_interactive_c_args += clutter_debug_c_args
clutter_tests_interactive_link_args = [
'-Wl,--export-dynamic',
]
clutter_tests_interactive_test_sources = [
'test-texture-slicing.c',
'test-texture-async.c',
'test-texture-material.c',
'test-events.c',
'test-scale.c',
'test-actors.c',
'test-shader-effects.c',
'test-script.c',
'test-grab.c',
'test-cogl-shader-glsl.c',
'test-state.c',
'test-fbo.c',
'test-cogl-tex-tile.c',
'test-cogl-tex-convert.c',
'test-cogl-offscreen.c',
'test-cogl-tex-polygon.c',
'test-cogl-multitexture.c',
'test-stage-read-pixels.c',
'test-paint-wrapper.c',
'test-texture-quality.c',
'test-layout.c',
'test-animation.c',
'test-easing.c',
'test-binding-pool.c',
'test-text.c',
'test-text-field.c',
'test-cairo-clock.c',
'test-cairo-flowers.c',
'test-cogl-vertex-buffer.c',
'test-stage-sizing.c',
'test-scrolling.c',
'test-swipe-action.c',
'test-cogl-point-sprites.c',
'test-table-layout.c',
'test-path-constraint.c',
'test-state-script.c',
'test-devices.c',
'test-content.c',
'test-keyframe-transition.c',
'test-bind-constraint.c',
'test-touch-events.c',
'test-rotate-zoom.c',
'test-image.c',
]
gen_test_unit_names = find_program('meson/gen-test-unit-names.sh')
clutter_interactive_test_unit_names_h = custom_target('gen-test-unit-names',
output: 'test-unit-names.h',
input: clutter_tests_interactive_test_sources,
command: [gen_test_unit_names, '@OUTPUT@', '@INPUT@'],
install: false,
)
clutter_tests_interactive_sources = [
'test-main.c',
clutter_interactive_test_unit_names_h,
clutter_tests_interactive_test_sources
]
executable('test-interactive',
sources: clutter_tests_interactive_sources,
include_directories: [
clutter_includes,
clutter_tests_interactive_includepath,
],
c_args: clutter_tests_interactive_c_args,
link_args: clutter_tests_interactive_link_args,
dependencies: [
clutter_deps,
libmutter_clutter_dep,
gdk_pixbuf_dep,
],
install: false,
)

View File

@ -0,0 +1,14 @@
#!/bin/sh
outputfile=$1
shift
echo '/* ** This file is autogenerated. Do not edit. ** */' > "$outputfile"
echo '' >> "$outputfile"
echo 'const char *test_unit_names[] = {' >> "$outputfile"
for test_source_file in "$@"; do
echo " \"$(echo "$test_source_file" | sed 's/.*\(test-[a-z0-9\-]\+\)\.c/\1/')\"," >> "$outputfile"
done
echo '};' >> "$outputfile"

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -0,0 +1,318 @@
#include <clutter/clutter.h>
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#include <glib.h>
#include <gmodule.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;
ClutterBehaviour *scaler_1;
ClutterBehaviour *scaler_2;
ClutterTimeline *timeline;
} SuperOH;
static gint n_hands = NHANDS;
int
test_actors_main (int argc, char *argv[]);
static GOptionEntry super_oh_entries[] = {
{
"num-hands", 'n',
0,
G_OPTION_ARG_INT, &n_hands,
"Number of hands", "HANDS"
},
{ NULL }
};
static void
on_group_destroy (ClutterActor *actor,
SuperOH *oh)
{
oh->group = NULL;
}
static void
on_hand_destroy (ClutterActor *actor,
SuperOH *oh)
{
int i;
for (i = 0; i < n_hands; i++)
{
if (oh->hand[i] == actor)
oh->hand[i] = NULL;
}
}
static gboolean
on_button_press_event (ClutterActor *actor,
ClutterEvent *event,
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 (event->type == 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_main_quit ();
return TRUE;
}
else if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_r)
{
gint i;
for (i = 0; i < n_hands; 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 = clutter_timeline_get_progress (timeline) * 360.0f;
/* Rotate everything clockwise about stage center*/
if (oh->group != NULL)
clutter_actor_set_rotation (oh->group,
CLUTTER_Z_AXIS,
rotation,
oh->stage_width / 2,
oh->stage_height / 2,
0);
for (i = 0; i < n_hands; i++)
{
/* Rotate each hand around there centers - to get this we need
* to take into account any scaling.
*/
if (oh->hand[i] != NULL)
clutter_actor_set_rotation (oh->hand[i],
CLUTTER_Z_AXIS,
-6.0 * rotation,
0, 0, 0);
}
}
static void
stop_and_quit (ClutterActor *stage,
SuperOH *data)
{
clutter_timeline_stop (data->timeline);
clutter_main_quit ();
}
static gdouble
my_sine_wave (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
gdouble progress = clutter_timeline_get_progress (timeline);
return sin (progress * G_PI);
}
G_MODULE_EXPORT int
test_actors_main (int argc, char *argv[])
{
ClutterAlpha *alpha;
SuperOH *oh;
gint i;
GError *error;
ClutterActor *real_hand;
gchar *file;
error = NULL;
if (clutter_init_with_args (&argc, &argv,
NULL,
super_oh_entries,
NULL,
&error) != CLUTTER_INIT_SUCCESS)
{
g_warning ("Unable to initialise Clutter:\n%s",
error->message);
g_error_free (error);
return EXIT_FAILURE;
}
oh = g_new (SuperOH, 1);
oh->stage = clutter_stage_new ();
clutter_actor_set_size (oh->stage, 800, 600);
clutter_actor_set_name (oh->stage, "Default Stage");
clutter_actor_set_background_color (oh->stage, CLUTTER_COLOR_LightSkyBlue);
g_signal_connect (oh->stage, "destroy", G_CALLBACK (stop_and_quit), oh);
clutter_stage_set_title (CLUTTER_STAGE (oh->stage), "Actors");
/* Create a timeline to manage animation */
oh->timeline = clutter_timeline_new (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);
/* Set up some behaviours to handle scaling */
alpha = clutter_alpha_new_with_func (oh->timeline, my_sine_wave, NULL, NULL);
oh->scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, 1.0, 1.0);
oh->scaler_2 = clutter_behaviour_scale_new (alpha, 1.0, 1.0, 0.5, 0.5);
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
real_hand = clutter_texture_new_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_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*, n_hands);
oh->stage_width = clutter_actor_get_width (oh->stage);
oh->stage_height = clutter_actor_get_height (oh->stage);
oh->radius = (oh->stage_width + oh->stage_height)
/ n_hands;
for (i = 0; i < n_hands; 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 = clutter_actor_get_width (oh->hand[i]);
h = clutter_actor_get_height (oh->hand[i]);
x = oh->stage_width / 2
+ oh->radius
* cos (i * G_PI / (n_hands / 2))
- w / 2;
y = oh->stage_height / 2
+ oh->radius
* sin (i * G_PI / (n_hands / 2))
- h / 2;
clutter_actor_set_position (oh->hand[i], x, y);
clutter_actor_move_anchor_point_from_gravity (oh->hand[i],
CLUTTER_GRAVITY_CENTER);
/* Add to our group group */
clutter_container_add_actor (CLUTTER_CONTAINER (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);
if (i % 2)
clutter_behaviour_apply (oh->scaler_1, oh->hand[i]);
else
clutter_behaviour_apply (oh->scaler_2, oh->hand[i]);
}
/* Add the group to the stage */
clutter_container_add_actor (CLUTTER_CONTAINER (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_main ();
clutter_timeline_stop (oh->timeline);
/* clean up */
g_object_unref (oh->scaler_1);
g_object_unref (oh->scaler_2);
g_object_unref (oh->timeline);
g_free (oh->hand);
g_free (oh);
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,130 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
static gboolean is_expanded = FALSE;
int
test_animation_main (int argc, char *argv[]);
const char *
test_animation_describe (void);
static void
on_rect_transitions_completed (ClutterActor *actor)
{
is_expanded = !is_expanded;
g_print ("Animation complete\n");
clutter_actor_set_reactive (actor, TRUE);
}
static void
on_clicked (ClutterClickAction *action,
ClutterActor *actor,
gpointer dummy G_GNUC_UNUSED)
{
gfloat old_x, old_y, new_x, new_y;
gfloat old_width, old_height, new_width, new_height;
gdouble new_angle;
const ClutterColor *new_color;
guint8 new_opacity;
clutter_actor_get_position (actor, &old_x, &old_y);
clutter_actor_get_size (actor, &old_width, &old_height);
/* determine the final state of the animation depending on
* the state of the actor
*/
if (!is_expanded)
{
new_x = old_x - 100;
new_y = old_y - 100;
new_width = old_width + 200;
new_height = old_height + 200;
new_angle = 360.0;
new_color = CLUTTER_COLOR_DarkScarletRed;
new_opacity = 255;
}
else
{
new_x = old_x + 100;
new_y = old_y + 100;
new_width = old_width - 200;
new_height = old_height - 200;
new_angle = 0.0;
new_color = CLUTTER_COLOR_LightOrange;
new_opacity = 128;
}
clutter_actor_save_easing_state (actor);
clutter_actor_set_easing_mode (actor, CLUTTER_EASE_IN_EXPO);
clutter_actor_set_easing_duration (actor, 2000);
clutter_actor_set_position (actor, new_x, new_y);
clutter_actor_set_size (actor, new_width, new_height);
clutter_actor_set_background_color (actor, new_color);
clutter_actor_set_rotation_angle (actor, CLUTTER_Z_AXIS, new_angle);
clutter_actor_set_reactive (actor, FALSE);
/* animate the opacity halfway through, with a different pacing */
clutter_actor_save_easing_state (actor);
clutter_actor_set_easing_mode (actor, CLUTTER_LINEAR);
clutter_actor_set_easing_delay (actor, 1000);
clutter_actor_set_easing_duration (actor, 1000);
clutter_actor_set_opacity (actor, new_opacity);
clutter_actor_restore_easing_state (actor);
clutter_actor_restore_easing_state (actor);
}
G_MODULE_EXPORT int
test_animation_main (int argc, char *argv[])
{
ClutterActor *stage, *rect;
ClutterAction *action;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Animation");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
rect = clutter_actor_new ();
clutter_actor_set_background_color (rect, CLUTTER_COLOR_LightOrange);
clutter_actor_add_child (stage, rect);
clutter_actor_set_size (rect, 50, 50);
clutter_actor_set_pivot_point (rect, .5f, .5f);
clutter_actor_set_translation (rect, -25, -25, 0);
clutter_actor_set_position (rect,
clutter_actor_get_width (stage) / 2,
clutter_actor_get_height (stage) / 2);
clutter_actor_set_opacity (rect, 128);
clutter_actor_set_reactive (rect, TRUE);
g_signal_connect (rect, "transitions-completed",
G_CALLBACK (on_rect_transitions_completed),
NULL);
action = clutter_click_action_new ();
g_signal_connect (action, "clicked", G_CALLBACK (on_clicked), NULL);
clutter_actor_add_action_with_name (rect, "click", action);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_animation_describe (void)
{
return "Simple animation demo";
}

View File

@ -0,0 +1,257 @@
#include <stdlib.h>
#include <clutter/clutter.h>
#define RECT_SIZE 128
#define H_PADDING 32
#define V_PADDING 32
enum
{
NorthWest, North, NorthEast,
West, Center, East,
SouthWest, South, SouthEast,
N_RECTS
};
static ClutterActor *rects[N_RECTS] = { NULL, };
static const gchar *colors[N_RECTS] = {
"#8ae234", "#73d216", "#4e9a06",
"#729fcf", "#3465a4", "#204a87",
"#ef2929", "#cc0000", "#a40000"
};
static const gchar *names[N_RECTS] = {
"North West", "North", "North East",
"West", "Center", "East",
"South West", "South", "South East"
};
static const gchar *desaturare_glsl_shader =
"uniform sampler2D tex;\n"
"uniform float factor;\n"
"\n"
"vec3 desaturate (const vec3 color, const float desaturation)\n"
"{\n"
" const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n"
" vec3 gray = vec3 (dot (gray_conv, color));\n"
" return vec3 (mix (color.rgb, gray, desaturation));\n"
"}\n"
"\n"
"void main ()\n"
"{\n"
" vec4 color = cogl_color_in * texture2D (tex, vec2 (cogl_tex_coord_in[0].xy));\n"
" color.rgb = desaturate (color.rgb, factor);\n"
" cogl_color_out = color;\n"
"}\n";
static gboolean is_expanded = FALSE;
const char *
test_bind_constraint_describe (void);
int
test_bind_constraint_main (int argc, char *argv[]);
static gboolean
on_button_release (ClutterActor *actor,
ClutterEvent *event,
gpointer data G_GNUC_UNUSED)
{
if (!is_expanded)
{
gfloat north_offset, south_offset;
gfloat west_offset, east_offset;
/* expand the 8 rectangles by animating the offset of the
* bind constraints
*/
north_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING)
* -1.0f;
south_offset = (clutter_actor_get_height (rects[Center]) + V_PADDING);
west_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING)
* -1.0f;
east_offset = (clutter_actor_get_width (rects[Center]) + H_PADDING);
clutter_actor_animate (rects[NorthWest], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 255,
"@constraints.x-bind.offset", west_offset,
"@constraints.y-bind.offset", north_offset,
"reactive", TRUE,
NULL);
clutter_actor_animate (rects[North], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 255,
"@constraints.y-bind.offset", north_offset,
"reactive", TRUE,
NULL);
clutter_actor_animate (rects[NorthEast], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 255,
"@constraints.x-bind.offset", east_offset,
"@constraints.y-bind.offset", north_offset,
"reactive", TRUE,
NULL);
clutter_actor_animate (rects[West], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 255,
"@constraints.x-bind.offset", west_offset,
"reactive", TRUE,
NULL);
/* turn on the desaturation effect and set the center
* rectangle not reactive
*/
clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500,
"@effects.desaturate.enabled", TRUE,
"reactive", FALSE,
NULL);
clutter_actor_animate (rects[East], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 255,
"@constraints.x-bind.offset", east_offset,
"reactive", TRUE,
NULL);
clutter_actor_animate (rects[SouthWest], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 255,
"@constraints.x-bind.offset", west_offset,
"@constraints.y-bind.offset", south_offset,
"reactive", TRUE,
NULL);
clutter_actor_animate (rects[South], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 255,
"@constraints.y-bind.offset", south_offset,
"reactive", TRUE,
NULL);
clutter_actor_animate (rects[SouthEast], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 255,
"@constraints.x-bind.offset", east_offset,
"@constraints.y-bind.offset", south_offset,
"reactive", TRUE,
NULL);
}
else
{
gint i;
clutter_actor_animate (rects[Center], CLUTTER_LINEAR, 500,
"@effects.desaturate.enabled", FALSE,
"reactive", TRUE,
NULL);
for (i = NorthWest; i < N_RECTS; i++)
{
if (i == Center)
continue;
/* put the 8 rectangles back into their initial state */
clutter_actor_animate (rects[i], CLUTTER_EASE_OUT_EXPO, 500,
"opacity", 0,
"@constraints.x-bind.offset", 0.0f,
"@constraints.y-bind.offset", 0.0f,
"reactive", FALSE,
NULL);
}
}
is_expanded = !is_expanded;
g_print ("Selected: [%s]\n", clutter_actor_get_name (actor));
return TRUE;
}
G_MODULE_EXPORT const char *
test_bind_constraint_describe (void)
{
return "Demonstrate the usage of ClutterBindConstraint";
}
G_MODULE_EXPORT int
test_bind_constraint_main (int argc, char *argv[])
{
ClutterActor *stage, *rect;
ClutterConstraint *constraint;
ClutterEffect *effect;
ClutterColor rect_color;
gint i;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Constraints");
clutter_actor_set_size (stage, 800, 600);
/* main rectangle */
clutter_color_from_string (&rect_color, "#3465a4");
rect = clutter_actor_new ();
g_signal_connect (rect, "button-release-event",
G_CALLBACK (on_button_release),
NULL);
clutter_actor_set_background_color (rect, &rect_color);
clutter_actor_set_size (rect, RECT_SIZE, RECT_SIZE);
clutter_actor_set_reactive (rect, TRUE);
clutter_actor_set_name (rect, names[Center]);
clutter_actor_add_child (stage, rect);
/* align the center rectangle to the center of the stage */
constraint = clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5);
clutter_actor_add_constraint_with_name (rect, "align", constraint);
/* this is the equivalent of the DesaturateEffect; we cannot animate
* the factor because the animation API only understands GObject
* properties; so we use the ActorMeta:enabled property to toggle
* the shader
*/
effect = clutter_shader_effect_new (CLUTTER_FRAGMENT_SHADER);
clutter_shader_effect_set_shader_source (CLUTTER_SHADER_EFFECT (effect),
desaturare_glsl_shader);
clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect),
"tex", G_TYPE_INT, 1, 0);
clutter_shader_effect_set_uniform (CLUTTER_SHADER_EFFECT (effect),
"factor", G_TYPE_FLOAT, 1, 0.66);
clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), FALSE);
clutter_actor_add_effect_with_name (rect, "desaturate", effect);
rects[Center] = rect;
/* build the other rectangles, and bind their position and size
* to the center rectangle. we are going to animate the offset
* of the BindConstraints
*/
for (i = 0; i < N_RECTS; i++)
{
if (i == Center)
continue;
clutter_color_from_string (&rect_color, colors[i]);
rect = clutter_actor_new ();
clutter_actor_set_background_color (rect, &rect_color);
clutter_actor_set_opacity (rect, 0);
clutter_actor_set_name (rect, names[i]);
clutter_actor_add_child (stage, rect);
constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_X, 0.0);
clutter_actor_add_constraint_with_name (rect, "x-bind", constraint);
constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_Y, 0.0);
clutter_actor_add_constraint_with_name (rect, "y-bind", constraint);
constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_SIZE, 0.0);
clutter_actor_add_constraint_with_name (rect, "size-bind", constraint);
g_signal_connect (rect, "button-release-event",
G_CALLBACK (on_button_release),
NULL);
rects[i] = rect;
}
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,316 @@
#include <stdlib.h>
#include <stdio.h>
#include <glib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#include <clutter/clutter-keysyms.h>
#define TYPE_KEY_GROUP (key_group_get_type ())
#define KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_KEY_GROUP, KeyGroup))
#define IS_KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_KEY_GROUP))
#define KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_KEY_GROUP, KeyGroupClass))
#define IS_KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_KEY_GROUP))
typedef struct _KeyGroup KeyGroup;
typedef struct _KeyGroupClass KeyGroupClass;
struct _KeyGroup
{
ClutterActor parent_instance;
gint selected_index;
};
struct _KeyGroupClass
{
ClutterActorClass parent_class;
void (* activate) (KeyGroup *group,
ClutterActor *child);
};
GType key_group_get_type (void);
int
test_binding_pool_main (int argc, char *argv[]);
const char *
test_binding_pool_describe (void);
G_DEFINE_TYPE (KeyGroup, key_group, CLUTTER_TYPE_ACTOR)
enum
{
ACTIVATE,
LAST_SIGNAL
};
static guint group_signals[LAST_SIGNAL] = { 0, };
static gboolean
key_group_action_move_left (KeyGroup *self,
const gchar *action_name,
guint key_val,
ClutterModifierType modifiers)
{
gint n_children;
g_debug ("%s: activated '%s' (k:%d, m:%d)",
G_STRLOC,
action_name,
key_val,
modifiers);
n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self));
self->selected_index -= 1;
if (self->selected_index < 0)
self->selected_index = n_children - 1;
return TRUE;
}
static gboolean
key_group_action_move_right (KeyGroup *self,
const gchar *action_name,
guint key_val,
ClutterModifierType modifiers)
{
gint n_children;
g_debug ("%s: activated '%s' (k:%d, m:%d)",
G_STRLOC,
action_name,
key_val,
modifiers);
n_children = clutter_actor_get_n_children (CLUTTER_ACTOR (self));
self->selected_index += 1;
if (self->selected_index >= n_children)
self->selected_index = 0;
return TRUE;
}
static gboolean
key_group_action_activate (KeyGroup *self,
const gchar *action_name,
guint key_val,
ClutterModifierType modifiers)
{
ClutterActor *child = NULL;
g_debug ("%s: activated '%s' (k:%d, m:%d)",
G_STRLOC,
action_name,
key_val,
modifiers);
if (self->selected_index == -1)
return FALSE;
child = clutter_actor_get_child_at_index (CLUTTER_ACTOR (self),
self->selected_index);
if (child != NULL)
{
g_signal_emit (self, group_signals[ACTIVATE], 0, child);
return TRUE;
}
else
return FALSE;
}
static gboolean
key_group_key_press (ClutterActor *actor,
ClutterKeyEvent *event)
{
ClutterBindingPool *pool;
gboolean res;
pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));
g_assert (pool != NULL);
res = clutter_binding_pool_activate (pool,
event->keyval,
event->modifier_state,
G_OBJECT (actor));
/* if we activate a key binding, redraw the actor */
if (res)
clutter_actor_queue_redraw (actor);
return res ? CLUTTER_EVENT_STOP : CLUTTER_EVENT_PROPAGATE;
}
static void
key_group_paint (ClutterActor *actor)
{
KeyGroup *self = KEY_GROUP (actor);
ClutterActorIter iter;
ClutterActor *child;
gint i = 0;
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
{
/* paint the selection rectangle */
if (i == self->selected_index)
{
ClutterActorBox box = { 0, };
clutter_actor_get_allocation_box (child, &box);
box.x1 -= 2;
box.y1 -= 2;
box.x2 += 2;
box.y2 += 2;
cogl_set_source_color4ub (255, 255, 0, 224);
cogl_rectangle (box.x1, box.y1, box.x2, box.y2);
}
clutter_actor_paint (child);
i += 1;
}
}
static void
key_group_class_init (KeyGroupClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
ClutterBindingPool *binding_pool;
actor_class->paint = key_group_paint;
actor_class->key_press_event = key_group_key_press;
group_signals[ACTIVATE] =
g_signal_new (g_intern_static_string ("activate"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (KeyGroupClass, activate),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
CLUTTER_TYPE_ACTOR);
binding_pool = clutter_binding_pool_get_for_class (klass);
clutter_binding_pool_install_action (binding_pool, "move-right",
CLUTTER_KEY_Right, 0,
G_CALLBACK (key_group_action_move_right),
NULL, NULL);
clutter_binding_pool_install_action (binding_pool, "move-left",
CLUTTER_KEY_Left, 0,
G_CALLBACK (key_group_action_move_left),
NULL, NULL);
clutter_binding_pool_install_action (binding_pool, "activate",
CLUTTER_KEY_Return, 0,
G_CALLBACK (key_group_action_activate),
NULL, NULL);
clutter_binding_pool_install_action (binding_pool, "activate",
CLUTTER_KEY_KP_Enter, 0,
G_CALLBACK (key_group_action_activate),
NULL, NULL);
clutter_binding_pool_install_action (binding_pool, "activate",
CLUTTER_KEY_ISO_Enter, 0,
G_CALLBACK (key_group_action_activate),
NULL, NULL);
}
static void
key_group_init (KeyGroup *self)
{
self->selected_index = -1;
}
static void
on_key_group_activate (KeyGroup *group,
ClutterActor *child)
{
g_print ("Child '%s' activated!\n", clutter_actor_get_name (child));
}
G_MODULE_EXPORT int
test_binding_pool_main (int argc, char *argv[])
{
ClutterActor *stage, *key_group;
gint group_x, group_y;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Key Binding Pool");
g_signal_connect (stage,
"button-press-event", G_CALLBACK (clutter_main_quit),
NULL);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
key_group = g_object_new (TYPE_KEY_GROUP, NULL);
clutter_actor_add_child (stage, key_group);
/* add three rectangles to the key group */
clutter_container_add (CLUTTER_CONTAINER (key_group),
g_object_new (CLUTTER_TYPE_ACTOR,
"background-color", CLUTTER_COLOR_Red,
"name", "Red Rectangle",
"width", 100.0,
"height", 100.0,
"x", 0.0,
"y", 0.0,
NULL),
g_object_new (CLUTTER_TYPE_ACTOR,
"background-color", CLUTTER_COLOR_Green,
"name", "Green Rectangle",
"width", 100.0,
"height", 100.0,
"x", 125.0,
"y", 0.0,
NULL),
g_object_new (CLUTTER_TYPE_ACTOR,
"background-color", CLUTTER_COLOR_Blue,
"name", "Blue Rectangle",
"width", 100.0,
"height", 100.0,
"x", 250.0,
"y", 0.0,
NULL),
NULL);
g_signal_connect (key_group,
"activate", G_CALLBACK (on_key_group_activate),
NULL);
group_x =
(clutter_actor_get_width (stage) - clutter_actor_get_width (key_group))
/ 2;
group_y =
(clutter_actor_get_height (stage) - clutter_actor_get_height (key_group))
/ 2;
clutter_actor_set_position (key_group, group_x, group_y);
clutter_actor_set_reactive (key_group, TRUE);
clutter_stage_set_key_focus (CLUTTER_STAGE (stage), key_group);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_binding_pool_describe (void)
{
return "Binding pools example";
}

View File

@ -0,0 +1,124 @@
#include <stdlib.h>
#include <math.h>
#include <cairo.h>
#include <clutter/clutter.h>
int
test_cairo_clock_main (int argc, char *argv[]);
const char *
test_cairo_clock_describe (void);
static gboolean
draw_clock (ClutterCanvas *canvas,
cairo_t *cr,
int width,
int height)
{
GDateTime *now;
float hours, minutes, seconds;
/* get the current time and compute the angles */
now = g_date_time_new_now_local ();
seconds = g_date_time_get_second (now) * G_PI / 30;
minutes = g_date_time_get_minute (now) * G_PI / 30;
hours = g_date_time_get_hour (now) * G_PI / 6;
/* clear the contents of the canvas, to avoid painting
* over the previous frame
*/
cairo_save (cr);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_restore (cr);
/* scale the modelview to the size of the surface */
cairo_scale (cr, width, height);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_width (cr, 0.1);
/* the black rail that holds the seconds indicator */
clutter_cairo_set_source_color (cr, CLUTTER_COLOR_Black);
cairo_translate (cr, 0.5, 0.5);
cairo_arc (cr, 0, 0, 0.4, 0, G_PI * 2);
cairo_stroke (cr);
/* the seconds indicator */
clutter_cairo_set_source_color (cr, CLUTTER_COLOR_White);
cairo_move_to (cr, 0, 0);
cairo_arc (cr, sinf (seconds) * 0.4, - cosf (seconds) * 0.4, 0.05, 0, G_PI * 2);
cairo_fill (cr);
/* the minutes hand */
clutter_cairo_set_source_color (cr, CLUTTER_COLOR_DarkChameleon);
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, sinf (minutes) * 0.4, -cosf (minutes) * 0.4);
cairo_stroke (cr);
/* the hours hand */
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, sinf (hours) * 0.2, -cosf (hours) * 0.2);
cairo_stroke (cr);
g_date_time_unref (now);
/* we're done drawing */
return TRUE;
}
static gboolean
invalidate_clock (gpointer data_)
{
/* invalidate the contents of the canvas */
clutter_content_invalidate (data_);
/* keep the timeout source */
return TRUE;
}
G_MODULE_EXPORT int
test_cairo_clock_main (int argc, char *argv[])
{
ClutterActor *stage;
ClutterContent *canvas;
/* initialize Clutter */
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
/* create a resizable stage */
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "2D Clock");
clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue);
clutter_actor_set_size (stage, 300, 300);
clutter_actor_show (stage);
/* our 2D canvas, courtesy of Cairo */
canvas = clutter_canvas_new ();
clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 300, 300);
clutter_actor_set_content (stage, canvas);
/* quit on destroy */
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* connect our drawing code */
g_signal_connect (canvas, "draw", G_CALLBACK (draw_clock), NULL);
/* invalidate the canvas, so that we can draw before the main loop starts */
clutter_content_invalidate (canvas);
/* set up a timer that invalidates the canvas every second */
clutter_threads_add_timeout (1000, invalidate_clock, canvas);
clutter_main ();
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_cairo_clock_describe (void)
{
return "Simple 2D canvas using a Cairo texture actor";
}

View File

@ -0,0 +1,262 @@
/*
* Pretty cairo flower hack.
*/
#include <clutter/clutter.h>
#ifndef _MSC_VER
#include <unistd.h> /* for sleep(), used for screenshots */
#endif
#include <stdlib.h>
#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#define PETAL_MIN 20
#define PETAL_VAR 40
#define N_FLOWERS 40 /* reduce if you have a small card */
typedef struct Flower
{
ClutterActor *ctex;
gint x,y,rot,v,rv;
}
Flower;
static ClutterActor *stage = NULL;
int
test_cairo_flowers_main (int argc, char **argv);
const char *
test_cairo_flowers_describe (void);
static gboolean
draw_flower (ClutterCanvas *canvas,
cairo_t *cr,
gint width,
gint height,
gpointer user_data)
{
/* No science here, just a hack from toying */
gint i, j;
double colors[] = {
0.71, 0.81, 0.83,
1.0, 0.78, 0.57,
0.64, 0.30, 0.35,
0.73, 0.40, 0.39,
0.91, 0.56, 0.64,
0.70, 0.47, 0.45,
0.92, 0.75, 0.60,
0.82, 0.86, 0.85,
0.51, 0.56, 0.67,
1.0, 0.79, 0.58,
};
gint size;
gint petal_size;
gint n_groups; /* Num groups of petals 1-3 */
gint n_petals; /* num of petals 4 - 8 */
gint pm1, pm2;
gint idx, last_idx = -1;
petal_size = GPOINTER_TO_INT (user_data);
size = petal_size * 8;
n_groups = rand() % 3 + 1;
cairo_set_tolerance (cr, 0.1);
/* Clear */
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_translate(cr, size/2, size/2);
for (i=0; i<n_groups; i++)
{
n_petals = rand() % 5 + 4;
cairo_save (cr);
cairo_rotate (cr, rand() % 6);
do {
idx = (rand() % (sizeof (colors) / sizeof (double) / 3)) * 3;
} while (idx == last_idx);
cairo_set_source_rgba (cr, colors[idx], colors[idx+1],
colors[idx+2], 0.5);
last_idx = idx;
/* some bezier randomness */
pm1 = rand() % 20;
pm2 = rand() % 4;
for (j=1; j<n_petals+1; j++)
{
cairo_save (cr);
cairo_rotate (cr, ((2*M_PI)/n_petals)*j);
/* Petals are made up beziers */
cairo_new_path (cr);
cairo_move_to (cr, 0, 0);
cairo_rel_curve_to (cr,
petal_size, petal_size,
(pm2+2)*petal_size, petal_size,
(2*petal_size) + pm1, 0);
cairo_rel_curve_to (cr,
0 + (pm2*petal_size), -petal_size,
-petal_size, -petal_size,
-((2*petal_size) + pm1), 0);
cairo_close_path (cr);
cairo_fill (cr);
cairo_restore (cr);
}
petal_size -= rand() % (size/8);
cairo_restore (cr);
}
/* Finally draw flower center */
do {
idx = (rand() % (sizeof (colors) / sizeof (double) / 3)) * 3;
} while (idx == last_idx);
if (petal_size < 0)
petal_size = rand() % 10;
cairo_set_source_rgba (cr, colors[idx], colors[idx+1], colors[idx+2], 0.5);
cairo_arc(cr, 0, 0, petal_size, 0, M_PI * 2);
cairo_fill(cr);
return TRUE;
}
static ClutterActor *
make_flower_actor (void)
{
gint petal_size = PETAL_MIN + rand() % PETAL_VAR;
gint size = petal_size * 8;
ClutterActor *ctex;
ClutterContent *canvas;
canvas = clutter_canvas_new ();
g_signal_connect (canvas, "draw",
G_CALLBACK (draw_flower), GINT_TO_POINTER (petal_size));
clutter_canvas_set_size (CLUTTER_CANVAS (canvas), size, size);
ctex = g_object_new (CLUTTER_TYPE_ACTOR,
"content", canvas,
"width", (gfloat) size,
"height", (gfloat) size,
NULL);
g_object_unref (canvas);
return ctex;
}
static void
tick (ClutterTimeline *timeline,
gint msecs,
gpointer data)
{
Flower **flowers = data;
gint i = 0;
for (i = 0; i < N_FLOWERS; i++)
{
flowers[i]->y += flowers[i]->v;
flowers[i]->rot += flowers[i]->rv;
if (flowers[i]->y > (gint) clutter_actor_get_height (stage))
flowers[i]->y = -clutter_actor_get_height (flowers[i]->ctex);
clutter_actor_set_position (flowers[i]->ctex,
flowers[i]->x, flowers[i]->y);
clutter_actor_set_rotation (flowers[i]->ctex,
CLUTTER_Z_AXIS,
flowers[i]->rot,
clutter_actor_get_width (flowers[i]->ctex)/2,
clutter_actor_get_height (flowers[i]->ctex)/2,
0);
}
}
static void
stop_and_quit (ClutterActor *actor,
ClutterTimeline *timeline)
{
clutter_timeline_stop (timeline);
clutter_main_quit ();
}
G_MODULE_EXPORT int
test_cairo_flowers_main (int argc, char **argv)
{
Flower *flowers[N_FLOWERS];
ClutterTimeline *timeline;
int i;
srand (time (NULL));
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
/* Create a timeline to manage animation */
timeline = clutter_timeline_new (6000);
clutter_timeline_set_repeat_count (timeline, -1);
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cairo Flowers");
g_signal_connect (stage, "destroy", G_CALLBACK (stop_and_quit), timeline);
clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black);
for (i=0; i< N_FLOWERS; i++)
{
flowers[i] = g_new0(Flower, 1);
flowers[i]->ctex = make_flower_actor();
flowers[i]->x = rand() % (int) clutter_actor_get_width (stage)
- (PETAL_MIN + PETAL_VAR) * 2;
flowers[i]->y = rand() % (int) clutter_actor_get_height (stage);
flowers[i]->rv = rand() % 5 + 1;
flowers[i]->v = rand() % 10 + 2;
clutter_container_add_actor (CLUTTER_CONTAINER (stage),
flowers[i]->ctex);
clutter_actor_set_position (flowers[i]->ctex,
flowers[i]->x, flowers[i]->y);
}
/* fire a callback for frame change */
g_signal_connect (timeline, "new-frame", G_CALLBACK (tick), flowers);
clutter_actor_show (stage);
clutter_timeline_start (timeline);
g_signal_connect (stage, "key-press-event",
G_CALLBACK (clutter_main_quit),
NULL);
clutter_main();
g_object_unref (timeline);
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_cairo_flowers_describe (void)
{
return "Drawing pretty flowers with Cairo";
}

View File

@ -0,0 +1,243 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
typedef struct _TestMultiLayerMaterialState
{
ClutterActor *group;
CoglHandle alpha_tex;
CoglHandle redhand_tex;
gfloat *tex_coords;
ClutterTimeline *timeline;
CoglHandle material0;
CoglMatrix tex_matrix0;
CoglMatrix rot_matrix0;
CoglHandle light_tex0;
CoglHandle material1;
CoglMatrix tex_matrix1;
CoglMatrix rot_matrix1;
CoglHandle light_tex1;
} TestMultiLayerMaterialState;
int
test_cogl_multitexture_main (int argc, char *argv[]);
const char *
test_cogl_multitexture_describe (void);
static void
frame_cb (ClutterTimeline *timeline,
gint frame_no,
gpointer data)
{
TestMultiLayerMaterialState *state = data;
cogl_matrix_multiply (&state->tex_matrix0,
&state->tex_matrix0,
&state->rot_matrix0);
cogl_material_set_layer_matrix (state->material0, 2, &state->tex_matrix0);
cogl_matrix_multiply (&state->tex_matrix1,
&state->tex_matrix1,
&state->rot_matrix1);
cogl_material_set_layer_matrix (state->material1, 2, &state->tex_matrix1);
}
static void
material_rectangle_paint (ClutterActor *actor, gpointer data)
{
TestMultiLayerMaterialState *state = data;
cogl_push_matrix ();
cogl_translate (150, 15, 0);
cogl_set_source (state->material0);
cogl_rectangle_with_multitexture_coords (0, 0, 200, 213,
state->tex_coords,
12);
cogl_translate (-300, -30, 0);
cogl_set_source (state->material1);
cogl_rectangle_with_multitexture_coords (0, 0, 200, 213,
state->tex_coords,
12);
cogl_pop_matrix ();
}
static void
animation_completed_cb (ClutterAnimation *animation,
TestMultiLayerMaterialState *state)
{
static gboolean go_back = FALSE;
gdouble new_rotation_y;
if (go_back)
new_rotation_y = 30;
else
new_rotation_y = -30;
go_back = !go_back;
clutter_actor_animate_with_timeline (state->group,
CLUTTER_LINEAR,
state->timeline,
"rotation-angle-y", new_rotation_y,
"signal-after::completed",
animation_completed_cb, state,
NULL);
}
G_MODULE_EXPORT int
test_cogl_multitexture_main (int argc, char *argv[])
{
GError *error = NULL;
ClutterActor *stage;
ClutterColor stage_color = { 0x61, 0x56, 0x56, 0xff };
TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1);
gfloat stage_w, stage_h;
gchar **files;
gfloat tex_coords[] =
{
/* tx1 ty1 tx2 ty2 */
0, 0, 1, 1,
0, 0, 1, 1,
0, 0, 1, 1
};
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_actor_get_size (stage, &stage_w, &stage_h);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl: Multi-texturing");
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* We create a non-descript actor that we know doesn't have a
* default paint handler, so that we can easily control
* painting in a paint signal handler, without having to
* sub-class anything etc. */
state->group = clutter_group_new ();
clutter_actor_set_position (state->group, stage_w / 2, stage_h / 2);
g_signal_connect (state->group, "paint",
G_CALLBACK(material_rectangle_paint), state);
files = g_new (gchar*, 4);
files[0] = g_build_filename (TESTS_DATADIR, "redhand_alpha.png", NULL);
files[1] = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
files[2] = g_build_filename (TESTS_DATADIR, "light0.png", NULL);
files[3] = NULL;
state->alpha_tex =
cogl_texture_new_from_file (files[0],
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY,
&error);
if (!state->alpha_tex)
g_critical ("Failed to load redhand_alpha.png: %s", error->message);
state->redhand_tex =
cogl_texture_new_from_file (files[1],
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY,
&error);
if (!state->redhand_tex)
g_critical ("Failed to load redhand.png: %s", error->message);
state->light_tex0 =
cogl_texture_new_from_file (files[2],
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY,
&error);
if (!state->light_tex0)
g_critical ("Failed to load light0.png: %s", error->message);
state->light_tex1 =
cogl_texture_new_from_file (files[2],
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY,
&error);
if (!state->light_tex1)
g_critical ("Failed to load light0.png: %s", error->message);
g_strfreev (files);
state->material0 = cogl_material_new ();
cogl_material_set_layer (state->material0, 0, state->alpha_tex);
cogl_material_set_layer (state->material0, 1, state->redhand_tex);
cogl_material_set_layer (state->material0, 2, state->light_tex0);
state->material1 = cogl_material_new ();
cogl_material_set_layer (state->material1, 0, state->alpha_tex);
cogl_material_set_layer (state->material1, 1, state->redhand_tex);
cogl_material_set_layer (state->material1, 2, state->light_tex1);
state->tex_coords = tex_coords;
cogl_matrix_init_identity (&state->tex_matrix0);
cogl_matrix_init_identity (&state->tex_matrix1);
cogl_matrix_init_identity (&state->rot_matrix0);
cogl_matrix_init_identity (&state->rot_matrix1);
cogl_matrix_translate (&state->rot_matrix0, 0.5, 0.5, 0);
cogl_matrix_rotate (&state->rot_matrix0, 10.0, 0, 0, 1.0);
cogl_matrix_translate (&state->rot_matrix0, -0.5, -0.5, 0);
cogl_matrix_translate (&state->rot_matrix1, 0.5, 0.5, 0);
cogl_matrix_rotate (&state->rot_matrix1, -10.0, 0, 0, 1.0);
cogl_matrix_translate (&state->rot_matrix1, -0.5, -0.5, 0);
clutter_actor_set_anchor_point (state->group, 86, 125);
clutter_container_add_actor (CLUTTER_CONTAINER(stage),
state->group);
state->timeline = clutter_timeline_new (2812);
g_signal_connect (state->timeline, "new-frame", G_CALLBACK (frame_cb), state);
clutter_actor_animate_with_timeline (state->group,
CLUTTER_LINEAR,
state->timeline,
"rotation-angle-y", 30.0,
"signal-after::completed",
animation_completed_cb, state,
NULL);
/* start the timeline and thus the animations */
clutter_timeline_start (state->timeline);
clutter_actor_show_all (stage);
clutter_main();
cogl_handle_unref (state->material1);
cogl_handle_unref (state->material0);
cogl_handle_unref (state->alpha_tex);
cogl_handle_unref (state->redhand_tex);
cogl_handle_unref (state->light_tex0);
cogl_handle_unref (state->light_tex1);
g_free (state);
return 0;
}
G_MODULE_EXPORT const char *
test_cogl_multitexture_describe (void)
{
return "Multi-texturing support in Cogl.";
}

View File

@ -0,0 +1,337 @@
#include <glib.h>
#include <gmodule.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
/* Coglbox declaration
*--------------------------------------------------*/
G_BEGIN_DECLS
#define TEST_TYPE_COGLBOX test_coglbox_get_type()
#define TEST_COGLBOX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
TEST_TYPE_COGLBOX, TestCoglbox))
#define TEST_COGLBOX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
TEST_TYPE_COGLBOX, TestCoglboxClass))
#define TEST_IS_COGLBOX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
TEST_TYPE_COGLBOX))
#define TEST_IS_COGLBOX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
TEST_TYPE_COGLBOX))
#define TEST_COGLBOX_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
TEST_TYPE_COGLBOX, TestCoglboxClass))
typedef struct _TestCoglbox TestCoglbox;
typedef struct _TestCoglboxClass TestCoglboxClass;
typedef struct _TestCoglboxPrivate TestCoglboxPrivate;
struct _TestCoglbox
{
ClutterActor parent;
/*< private >*/
TestCoglboxPrivate *priv;
};
struct _TestCoglboxClass
{
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_test_coglbox1) (void);
void (*_test_coglbox2) (void);
void (*_test_coglbox3) (void);
void (*_test_coglbox4) (void);
};
static GType test_coglbox_get_type (void) G_GNUC_CONST;
int
test_cogl_offscreen_main (int argc, char *argv[]);
const char *
test_cogl_offscreen_describe (void);
G_END_DECLS
/* Coglbox private declaration
*--------------------------------------------------*/
struct _TestCoglboxPrivate
{
CoglHandle texhand_id;
CoglHandle texture_id;
CoglHandle offscreen_id;
};
G_DEFINE_TYPE_WITH_PRIVATE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR);
#define TEST_COGLBOX_GET_PRIVATE(obj) \
(test_coglbox_get_instance_private (TEST_COGLBOX ((obj))))
/* Coglbox implementation
*--------------------------------------------------*/
static void
test_coglbox_paint (ClutterActor *self)
{
TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self);
gfloat texcoords[4] = { 0, 0, 1, 1 };
CoglHandle material;
cogl_set_source_color4ub (0x66, 0x66, 0xdd, 0xff);
cogl_rectangle (0, 0, 400, 400);
cogl_set_source_texture (priv->texhand_id);
cogl_rectangle_with_texture_coords (0, 0,
400, 400,
0, 0,
6, 6);
cogl_push_framebuffer (priv->offscreen_id);
cogl_set_source_color4ub (0xff, 0, 0, 0xff);
cogl_rectangle (20, 20, 20 + 100, 20 + 100);
cogl_set_source_color4ub (0, 0xff, 0, 0xff);
cogl_rectangle (80, 80, 80 + 100, 80 + 100);
cogl_pop_framebuffer ();
material = cogl_material_new ();
cogl_material_set_color4ub (material, 0x88, 0x88, 0x88, 0x88);
cogl_material_set_layer (material, 0, priv->texture_id);
cogl_set_source (material);
cogl_rectangle_with_texture_coords (100, 100,
300, 300,
texcoords[0],
texcoords[1],
texcoords[2],
texcoords[3]);
}
static void
test_coglbox_finalize (GObject *object)
{
G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object);
}
static void
test_coglbox_dispose (GObject *object)
{
TestCoglboxPrivate *priv;
priv = TEST_COGLBOX_GET_PRIVATE (object);
cogl_handle_unref (priv->texture_id);
cogl_handle_unref (priv->offscreen_id);
G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object);
}
/* A newly created Cogl framebuffer will be initialized with a
* viewport covering the size of the viewport i.e. equavalent to:
*
* calling cogl_framebuffer_set_viewport (
* fb,
* 0, 0,
* cogl_framebuffer_get_viewport_width (fb),
* cogl_framebuffer_get_viewport_width (fb));
*
* The projection matrix will be an identity matrix.
*
* The modelview matrix will be an identity matrix, and this will
* create a coordinate system - like OpenGL - with the viewport
* being mapped to a unit cube with the origin (0, 0, 0) in the
* center, x, y and z ranging from -1 to 1 with (-1, -1) being top
* left and (1, 1) bottom right.
*
* This sets up a Clutter like coordinate system for a Cogl
* framebuffer
*/
static void
setup_viewport (unsigned int width,
unsigned int height,
float fovy,
float aspect,
float z_near,
float z_far)
{
float z_camera;
CoglMatrix projection_matrix;
CoglMatrix mv_matrix;
cogl_set_viewport (0, 0, width, height);
/* For Ortho projection.
* _cogl_matrix_stack_ortho (projection_stack, 0, width, 0, height, -1, 1);
*/
cogl_perspective (fovy, aspect, z_near, z_far);
/*
* In theory, we can compute the camera distance from screen as:
*
* 0.5 * tan (FOV)
*
* However, it's better to compute the z_camera from our projection
* matrix so that we get a 1:1 mapping at the screen distance. Consider
* the upper-left corner of the screen. It has object coordinates
* (0,0,0), so by the transform below, ends up with eye coordinate
*
* x_eye = x_object / width - 0.5 = - 0.5
* y_eye = (height - y_object) / width - 0.5 = 0.5
* z_eye = z_object / width - z_camera = - z_camera
*
* From cogl_perspective(), we know that the projection matrix has
* the form:
*
* (x, 0, 0, 0)
* (0, y, 0, 0)
* (0, 0, c, d)
* (0, 0, -1, 0)
*
* Applied to the above, we get clip coordinates of
*
* x_clip = x * (- 0.5)
* y_clip = y * 0.5
* w_clip = - 1 * (- z_camera) = z_camera
*
* Dividing through by w to get normalized device coordinates, we
* have, x_nd = x * 0.5 / z_camera, y_nd = - y * 0.5 / z_camera.
* The upper left corner of the screen has normalized device coordinates,
* (-1, 1), so to have the correct 1:1 mapping, we have to have:
*
* z_camera = 0.5 * x = 0.5 * y
*
* If x != y, then we have a non-uniform aspect ration, and a 1:1 mapping
* doesn't make sense.
*/
cogl_get_projection_matrix (&projection_matrix);
z_camera = 0.5 * projection_matrix.xx;
cogl_matrix_init_identity (&mv_matrix);
cogl_matrix_translate (&mv_matrix, -0.5f, -0.5f, -z_camera);
cogl_matrix_scale (&mv_matrix, 1.0f / width, -1.0f / height, 1.0f / width);
cogl_matrix_translate (&mv_matrix, 0.0f, -1.0 * height, 0.0f);
cogl_set_modelview_matrix (&mv_matrix);
}
static void
test_coglbox_map (ClutterActor *actor)
{
TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (actor);
ClutterActor *stage;
ClutterPerspective perspective;
float stage_width;
float stage_height;
CLUTTER_ACTOR_CLASS (test_coglbox_parent_class)->map (actor);
printf ("Creating offscreen\n");
priv->offscreen_id = cogl_offscreen_new_to_texture (priv->texture_id);
stage = clutter_actor_get_stage (actor);
clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective);
clutter_actor_get_size (stage, &stage_width, &stage_height);
cogl_push_framebuffer (priv->offscreen_id);
setup_viewport (stage_width, stage_height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
cogl_pop_framebuffer ();
if (priv->offscreen_id == COGL_INVALID_HANDLE)
printf ("Failed creating offscreen to texture!\n");
}
static void
test_coglbox_init (TestCoglbox *self)
{
TestCoglboxPrivate *priv;
gchar *file;
self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self);
printf ("Loading redhand.png\n");
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
priv->texhand_id = cogl_texture_new_from_file (file,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_ANY,
NULL);
g_free (file);
printf ("Creating texture with size\n");
priv->texture_id = cogl_texture_new_with_size (200, 200,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGB_888);
if (priv->texture_id == COGL_INVALID_HANDLE)
printf ("Failed creating texture with size!\n");
}
static void
test_coglbox_class_init (TestCoglboxClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->finalize = test_coglbox_finalize;
gobject_class->dispose = test_coglbox_dispose;
actor_class->map = test_coglbox_map;
actor_class->paint = test_coglbox_paint;
}
static ClutterActor*
test_coglbox_new (void)
{
return g_object_new (TEST_TYPE_COGLBOX, NULL);
}
G_MODULE_EXPORT int
test_cogl_offscreen_main (int argc, char *argv[])
{
ClutterActor *stage;
ClutterActor *coglbox;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
/* Stage */
stage = clutter_stage_new ();
clutter_actor_set_size (stage, 400, 400);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Offscreen Buffers");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* Cogl Box */
coglbox = test_coglbox_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox);
clutter_actor_show_all (stage);
clutter_main ();
return 0;
}
G_MODULE_EXPORT const char *
test_cogl_offscreen_describe (void)
{
return "Offscreen buffer support in Cogl.";
}

View File

@ -0,0 +1,294 @@
#include <stdlib.h>
#include <clutter/clutter.h>
#include <math.h>
#include <gmodule.h>
#include <string.h>
#define N_FIREWORKS 32
/* Units per second per second */
#define GRAVITY -1.5f
#define N_SPARKS (N_FIREWORKS * 32) /* Must be a power of two */
#define TIME_PER_SPARK 0.01f /* in seconds */
#define TEXTURE_SIZE 32
typedef struct _Firework Firework;
struct _Firework
{
float size;
float x, y;
float start_x, start_y;
ClutterColor color;
/* Velocities are in units per second */
float initial_x_velocity;
float initial_y_velocity;
GTimer *timer;
};
typedef struct _Spark Spark;
struct _Spark
{
float x, y;
ClutterColor color;
ClutterColor base_color;
};
typedef struct _Data Data;
struct _Data
{
Firework fireworks[N_FIREWORKS];
int next_spark_num;
Spark sparks[N_SPARKS];
GTimer *last_spark_time;
CoglMaterial *material;
};
int
test_cogl_point_sprites_main (int argc, char *argv[]);
const char *
test_cogl_point_sprites_describe (void);
static CoglHandle
generate_round_texture (void)
{
guint8 *p, *data;
int x, y;
CoglHandle tex;
p = data = g_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4);
/* Generate a yellow circle which gets transparent towards the edges */
for (y = 0; y < TEXTURE_SIZE; y++)
for (x = 0; x < TEXTURE_SIZE; x++)
{
int dx = x - TEXTURE_SIZE / 2;
int dy = y - TEXTURE_SIZE / 2;
float value = sqrtf (dx * dx + dy * dy) * 255.0 / (TEXTURE_SIZE / 2);
if (value > 255.0f)
value = 255.0f;
value = 255.0f - value;
*(p++) = value;
*(p++) = value;
*(p++) = value;
*(p++) = value;
}
tex = cogl_texture_new_from_data (TEXTURE_SIZE, TEXTURE_SIZE,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
COGL_PIXEL_FORMAT_ANY,
TEXTURE_SIZE * 4,
data);
g_free (data);
return tex;
}
static void
paint_cb (ClutterActor *stage, Data *data)
{
CoglMatrix old_matrix, new_matrix;
int i;
float diff_time;
CoglHandle vbo;
cogl_get_projection_matrix (&old_matrix);
/* Use an orthogonal projection from -1 -> 1 in both axes */
cogl_matrix_init_identity (&new_matrix);
cogl_set_projection_matrix (&new_matrix);
cogl_push_matrix ();
cogl_set_modelview_matrix (&new_matrix);
/* Update all of the firework's positions */
for (i = 0; i < N_FIREWORKS; i++)
{
Firework *firework = data->fireworks + i;
if ((fabsf (firework->x - firework->start_x) > 2.0f) ||
firework->y < -1.0f)
{
firework->size = g_random_double_range (0.001f, 0.1f);
firework->start_x = 1.0f + firework->size;
firework->start_y = -1.0f;
firework->initial_x_velocity = g_random_double_range (-0.1f, -2.0f);
firework->initial_y_velocity = g_random_double_range (0.1f, 4.0f);
g_timer_reset (firework->timer);
/* Pick a random color out of six */
if (g_random_boolean ())
{
memset (&firework->color, 0, sizeof (ClutterColor));
((guint8 *) &firework->color)[g_random_int_range (0, 3)] = 255;
}
else
{
memset (&firework->color, 255, sizeof (ClutterColor));
((guint8 *) &firework->color)[g_random_int_range (0, 3)] = 0;
}
firework->color.alpha = 255;
/* Fire some of the fireworks from the other side */
if (g_random_boolean ())
{
firework->start_x = -firework->start_x;
firework->initial_x_velocity = -firework->initial_x_velocity;
}
}
diff_time = g_timer_elapsed (firework->timer, NULL);
firework->x = (firework->start_x +
firework->initial_x_velocity * diff_time);
firework->y = ((firework->initial_y_velocity * diff_time +
0.5f * GRAVITY * diff_time * diff_time) +
firework->start_y);
}
diff_time = g_timer_elapsed (data->last_spark_time, NULL);
if (diff_time < 0.0f || diff_time >= TIME_PER_SPARK)
{
/* Add a new spark for each firework, overwriting the oldest ones */
for (i = 0; i < N_FIREWORKS; i++)
{
Spark *spark = data->sparks + data->next_spark_num;
Firework *firework = data->fireworks + i;
spark->x = (firework->x +
g_random_double_range (-firework->size / 2.0f,
firework->size / 2.0f));
spark->y = (firework->y +
g_random_double_range (-firework->size / 2.0f,
firework->size / 2.0f));
spark->base_color = firework->color;
data->next_spark_num = (data->next_spark_num + 1) & (N_SPARKS - 1);
}
/* Update the colour of each spark */
for (i = 0; i < N_SPARKS; i++)
{
float color_value;
/* First spark is the oldest */
Spark *spark = data->sparks + ((data->next_spark_num + i)
& (N_SPARKS - 1));
color_value = i / (N_SPARKS - 1.0f);
spark->color.red = spark->base_color.red * color_value;
spark->color.green = spark->base_color.green * color_value;
spark->color.blue = spark->base_color.blue * color_value;
spark->color.alpha = 255.0f * color_value;
}
g_timer_reset (data->last_spark_time);
}
vbo = cogl_vertex_buffer_new (N_SPARKS);
cogl_vertex_buffer_add (vbo, "gl_Vertex", 2,
COGL_ATTRIBUTE_TYPE_FLOAT, FALSE,
sizeof (Spark),
&data->sparks[0].x);
cogl_vertex_buffer_add (vbo, "gl_Color", 4,
COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, TRUE,
sizeof (Spark),
&data->sparks[0].color.red);
cogl_vertex_buffer_submit (vbo);
cogl_set_source (data->material);
cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_POINTS, 0, N_SPARKS);
cogl_handle_unref (vbo);
cogl_set_projection_matrix (&old_matrix);
cogl_pop_matrix ();
}
static gboolean
idle_cb (gpointer data)
{
clutter_actor_queue_redraw (data);
return G_SOURCE_CONTINUE;
}
G_MODULE_EXPORT int
test_cogl_point_sprites_main (int argc, char *argv[])
{
ClutterActor *stage;
CoglHandle tex;
Data data;
GError *error = NULL;
int i;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
data.material = cogl_material_new ();
data.last_spark_time = g_timer_new ();
data.next_spark_num = 0;
cogl_material_set_point_size (data.material, TEXTURE_SIZE);
tex = generate_round_texture ();
cogl_material_set_layer (data.material, 0, tex);
cogl_handle_unref (tex);
if (!cogl_material_set_layer_point_sprite_coords_enabled (data.material,
0, TRUE,
&error))
{
g_warning ("Failed to enable point sprite coords: %s", error->message);
g_clear_error (&error);
}
for (i = 0; i < N_FIREWORKS; i++)
{
data.fireworks[i].x = -FLT_MAX;
data.fireworks[i].y = FLT_MAX;
data.fireworks[i].size = 0.0f;
data.fireworks[i].timer = g_timer_new ();
}
for (i = 0; i < N_SPARKS; i++)
{
data.sparks[i].x = 2.0f;
data.sparks[i].y = 2.0f;
}
stage = clutter_stage_new ();
clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Point Sprites");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
g_signal_connect_after (stage, "paint", G_CALLBACK (paint_cb), &data);
clutter_actor_show (stage);
clutter_threads_add_idle (idle_cb, stage);
clutter_main ();
cogl_object_unref (data.material);
g_timer_destroy (data.last_spark_time);
for (i = 0; i < N_FIREWORKS; i++)
g_timer_destroy (data.fireworks[i].timer);
return 0;
}
G_MODULE_EXPORT const char *
test_cogl_point_sprites_describe (void)
{
return "Point sprites support in Cogl.";
}

View File

@ -0,0 +1,351 @@
#include <clutter/clutter.h>
#include <errno.h>
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
typedef struct
{
const char *name;
const char *source;
} ShaderSource;
int
test_cogl_shader_glsl_main (int argc, char *argv[]);
/* a couple of boilerplate defines that are common amongst all the
* sample shaders
*/
/* FRAGMENT_SHADER_BEGIN: generate boilerplate with a local vec4 color already
* initialized, from a sampler2D in a variable tex.
*/
#define FRAGMENT_SHADER_VARS \
"uniform sampler2D tex;" \
"uniform float x_step, y_step;"
#define FRAGMENT_SHADER_BEGIN \
"void main (){" \
" vec4 color = texture2D (tex, vec2(cogl_tex_coord_in[0]));"
/* FRAGMENT_SHADER_END: apply the changed color to the output buffer correctly
* blended with the gl specified color (makes the opacity of actors work
* correctly).
*/
#define FRAGMENT_SHADER_END \
" cogl_color_out = color;" \
" cogl_color_out = cogl_color_out * cogl_color_in;" \
"}"
static ShaderSource shaders[]=
{
{"brightness-contrast",
FRAGMENT_SHADER_VARS
"uniform float brightness, contrast;"
FRAGMENT_SHADER_BEGIN
" color.rgb /= color.a;"
" color.rgb = (color.rgb - vec3(0.5, 0.5, 0.5)) * contrast + "
"vec3 (brightness + 0.5, brightness + 0.5, brightness + 0.5);"
" color.rgb *= color.a;"
FRAGMENT_SHADER_END
},
{"box-blur",
FRAGMENT_SHADER_VARS
"vec4 get_rgba_rel(sampler2D tex, float dx, float dy)"
"{"
" return texture2D (tex, cogl_tex_coord_in[0].st "
" + vec2(dx, dy) * 2.0);"
"}"
FRAGMENT_SHADER_BEGIN
" float count = 1.0;"
" color += get_rgba_rel (tex, -x_step, -y_step); count++;"
" color += get_rgba_rel (tex, -x_step, 0.0); count++;"
" color += get_rgba_rel (tex, -x_step, y_step); count++;"
" color += get_rgba_rel (tex, 0.0, -y_step); count++;"
" color += get_rgba_rel (tex, 0.0, 0.0); count++;"
" color += get_rgba_rel (tex, 0.0, y_step); count++;"
" color += get_rgba_rel (tex, x_step, -y_step); count++;"
" color += get_rgba_rel (tex, x_step, 0.0); count++;"
" color += get_rgba_rel (tex, x_step, y_step); count++;"
" color = color / count;"
FRAGMENT_SHADER_END
},
{"invert",
FRAGMENT_SHADER_VARS
FRAGMENT_SHADER_BEGIN
" color.rgb /= color.a;"
" color.rgb = vec3(1.0, 1.0, 1.0) - color.rgb;\n"
" color.rgb *= color.a;"
FRAGMENT_SHADER_END
},
{"brightness-contrast",
FRAGMENT_SHADER_VARS
"uniform float brightness;"
"uniform float contrast;"
FRAGMENT_SHADER_BEGIN
" color.rgb /= color.a;"
" color.r = (color.r - 0.5) * contrast + brightness + 0.5;"
" color.g = (color.g - 0.5) * contrast + brightness + 0.5;"
" color.b = (color.b - 0.5) * contrast + brightness + 0.5;"
" color.rgb *= color.a;"
FRAGMENT_SHADER_END
},
{"gray",
FRAGMENT_SHADER_VARS
FRAGMENT_SHADER_BEGIN
" float avg = (color.r + color.g + color.b) / 3.0;"
" color.r = avg;"
" color.g = avg;"
" color.b = avg;"
FRAGMENT_SHADER_END
},
{"combined-mirror",
FRAGMENT_SHADER_VARS
FRAGMENT_SHADER_BEGIN
" vec4 colorB = texture2D (tex, vec2(cogl_tex_coord_in[0].ts));"
" float avg = (color.r + color.g + color.b) / 3.0;"
" color.r = avg;"
" color.g = avg;"
" color.b = avg;"
" color = (color + colorB)/2.0;"
FRAGMENT_SHADER_END
},
{"edge-detect",
FRAGMENT_SHADER_VARS
"float get_avg_rel(sampler2D texB, float dx, float dy)"
"{"
" vec4 colorB = texture2D (texB, cogl_tex_coord_in[0].st + vec2(dx, dy));"
" return (colorB.r + colorB.g + colorB.b) / 3.0;"
"}"
FRAGMENT_SHADER_BEGIN
" mat3 sobel_h = mat3( 1.0, 2.0, 1.0,"
" 0.0, 0.0, 0.0,"
" -1.0, -2.0, -1.0);"
" mat3 sobel_v = mat3( 1.0, 0.0, -1.0,"
" 2.0, 0.0, -2.0,"
" 1.0, 0.0, -1.0);"
" mat3 map = mat3( get_avg_rel(tex, -x_step, -y_step),"
" get_avg_rel(tex, -x_step, 0.0),"
" get_avg_rel(tex, -x_step, y_step),"
" get_avg_rel(tex, 0.0, -y_step),"
" get_avg_rel(tex, 0.0, 0.0),"
" get_avg_rel(tex, 0.0, y_step),"
" get_avg_rel(tex, x_step, -y_step),"
" get_avg_rel(tex, x_step, 0.0),"
" get_avg_rel(tex, x_step, y_step) );"
" mat3 gh = sobel_h * map;"
" mat3 gv = map * sobel_v;"
" float avgh = (gh[0][0] + gh[0][1] + gh[0][2] +"
" gh[1][0] + gh[1][1] + gh[1][2] +"
" gh[2][0] + gh[2][1] + gh[2][2]) / 18.0 + 0.5;"
" float avgv = (gv[0][0] + gv[0][1] + gv[0][2] +"
" gv[1][0] + gv[1][1] + gv[1][2] +"
" gv[2][0] + gv[2][1] + gv[2][2]) / 18.0 + 0.5;"
" float avg = (avgh + avgv) / 2.0;"
" color.r = avg * color.r;"
" color.g = avg * color.g;"
" color.b = avg * color.b;"
FRAGMENT_SHADER_END
}
};
static CoglHandle redhand;
static CoglMaterial *material;
static unsigned int timeout_id = 0;
static int shader_no = 0;
static void
paint_cb (ClutterActor *actor)
{
float stage_width = clutter_actor_get_width (actor);
float stage_height = clutter_actor_get_height (actor);
float image_width = cogl_texture_get_width (redhand);
float image_height = cogl_texture_get_height (redhand);
cogl_set_source (material);
cogl_rectangle (stage_width/2.0f - image_width/2.0f,
stage_height/2.0f - image_height/2.0f,
stage_width/2.0f + image_width/2.0f,
stage_height/2.0f + image_height/2.0f);
}
static void
set_shader_num (int new_no)
{
CoglHandle shader;
CoglHandle program;
int image_width = cogl_texture_get_width (redhand);
int image_height = cogl_texture_get_height (redhand);
int uniform_no;
g_print ("setting shaders[%i] named '%s'\n",
new_no,
shaders[new_no].name);
shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
cogl_shader_source (shader, shaders[new_no].source);
cogl_shader_compile (shader);
program = cogl_create_program ();
cogl_program_attach_shader (program, shader);
cogl_handle_unref (shader);
cogl_program_link (program);
uniform_no = cogl_program_get_uniform_location (program, "tex");
cogl_program_set_uniform_1i (program, uniform_no, 0);
uniform_no = cogl_program_get_uniform_location (program, "radius");
cogl_program_set_uniform_1f (program, uniform_no, 3.0);
uniform_no = cogl_program_get_uniform_location (program, "brightness");
cogl_program_set_uniform_1f (program, uniform_no, 0.4);
uniform_no = cogl_program_get_uniform_location (program, "contrast");
cogl_program_set_uniform_1f (program, uniform_no, -1.9);
uniform_no = cogl_program_get_uniform_location (program, "x_step");
cogl_program_set_uniform_1f (program, uniform_no, 1.0f / image_width);
uniform_no = cogl_program_get_uniform_location (program, "y_step");
cogl_program_set_uniform_1f (program, uniform_no, 1.0f / image_height);
cogl_material_set_user_program (material, program);
cogl_handle_unref (program);
shader_no = new_no;
}
static gboolean
button_release_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
int new_no;
/* Stop the automatic cycling if the user want to manually control
* which shader to display */
if (timeout_id)
{
g_source_remove (timeout_id);
timeout_id = 0;
}
if (event->button.button == 1)
{
new_no = shader_no - 1;
if (new_no < 0)
new_no = G_N_ELEMENTS (shaders) - 1;
}
else
{
new_no = shader_no + 1;
if (new_no >= G_N_ELEMENTS (shaders))
new_no = 0;
}
set_shader_num (new_no);
return CLUTTER_EVENT_STOP;
}
static gboolean
key_release_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
guint keysym = clutter_event_get_key_symbol (event);
ClutterModifierType mods = clutter_event_get_state (event);
if (keysym == CLUTTER_KEY_q ||
((mods & CLUTTER_SHIFT_MASK) && keysym == CLUTTER_KEY_q))
clutter_main_quit ();
return CLUTTER_EVENT_STOP;
}
static gboolean
timeout_cb (gpointer user_data)
{
shader_no++;
if (shader_no > (G_N_ELEMENTS (shaders) - 1))
shader_no = 0;
set_shader_num (shader_no);
return G_SOURCE_CONTINUE;
}
static gboolean
idle_cb (gpointer data)
{
clutter_actor_queue_redraw (data);
return G_SOURCE_CONTINUE;
}
static gboolean
destroy_window_cb (ClutterStage *stage,
ClutterEvent *event,
gpointer user_data)
{
clutter_main_quit ();
return CLUTTER_EVENT_STOP;
}
G_MODULE_EXPORT int
test_cogl_shader_glsl_main (int argc, char *argv[])
{
ClutterActor *stage;
char *file;
GError *error;
ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff };
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Assembly Shader Test");
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
error = NULL;
redhand = cogl_texture_new_from_file (file,
COGL_TEXTURE_NO_ATLAS,
COGL_PIXEL_FORMAT_ANY,
&error);
if (redhand == COGL_INVALID_HANDLE)
g_error ("image load failed: %s", error->message);
material = cogl_material_new ();
cogl_material_set_layer (material, 0, redhand);
set_shader_num (0);
g_signal_connect_after (stage, "paint", G_CALLBACK (paint_cb), NULL);
clutter_actor_set_reactive (stage, TRUE);
g_signal_connect (stage, "button-release-event",
G_CALLBACK (button_release_cb), NULL);
g_signal_connect (stage, "key-release-event",
G_CALLBACK (key_release_cb), NULL);
g_signal_connect (stage, "delete-event",
G_CALLBACK (destroy_window_cb), NULL);
timeout_id = clutter_threads_add_timeout (1000, timeout_cb, NULL);
clutter_threads_add_idle (idle_cb, stage);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,229 @@
#include <glib.h>
#include <gmodule.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
/* Coglbox declaration
*--------------------------------------------------*/
G_BEGIN_DECLS
#define TEST_TYPE_COGLBOX test_coglbox_get_type()
#define TEST_COGLBOX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
TEST_TYPE_COGLBOX, TestCoglbox))
#define TEST_COGLBOX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
TEST_TYPE_COGLBOX, TestCoglboxClass))
#define TEST_IS_COGLBOX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
TEST_TYPE_COGLBOX))
#define TEST_IS_COGLBOX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
TEST_TYPE_COGLBOX))
#define TEST_COGLBOX_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
TEST_TYPE_COGLBOX, TestCoglboxClass))
typedef struct _TestCoglbox TestCoglbox;
typedef struct _TestCoglboxClass TestCoglboxClass;
typedef struct _TestCoglboxPrivate TestCoglboxPrivate;
struct _TestCoglbox
{
ClutterActor parent;
/*< private >*/
TestCoglboxPrivate *priv;
};
struct _TestCoglboxClass
{
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_test_coglbox1) (void);
void (*_test_coglbox2) (void);
void (*_test_coglbox3) (void);
void (*_test_coglbox4) (void);
};
static GType test_coglbox_get_type (void) G_GNUC_CONST;
int
test_cogl_tex_convert_main (int argc, char *argv[]);
const char *
test_cogl_tex_convert_describe (void);
G_END_DECLS
/* Coglbox private declaration
*--------------------------------------------------*/
struct _TestCoglboxPrivate
{
CoglHandle cogl_tex_id[4];
gint frame;
};
G_DEFINE_TYPE_WITH_PRIVATE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR);
#define TEST_COGLBOX_GET_PRIVATE(obj) \
(test_coglbox_get_instance_private (TEST_COGLBOX ((obj))))
/* Coglbox implementation
*--------------------------------------------------*/
static void
test_coglbox_paint(ClutterActor *self)
{
TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self);
gfloat texcoords[4] = { 0.0, 0.0, 1.0, 1.0 };
priv = TEST_COGLBOX_GET_PRIVATE (self);
cogl_set_source_color4ub (0x66, 0x66, 0xdd, 0xff);
cogl_rectangle (0, 0, 400, 400);
cogl_push_matrix ();
cogl_set_source_texture (priv->cogl_tex_id[0]);
cogl_rectangle_with_texture_coords (0, 0, 200, 213,
texcoords[0], texcoords[1],
texcoords[2], texcoords[3]);
cogl_pop_matrix ();
cogl_push_matrix ();
cogl_translate (200, 0, 0);
cogl_set_source_texture (priv->cogl_tex_id[1]);
cogl_rectangle_with_texture_coords (0, 0, 200, 213,
texcoords[0], texcoords[1],
texcoords[2], texcoords[3]);
cogl_pop_matrix ();
cogl_push_matrix ();
cogl_translate (0, 200, 0);
cogl_set_source_texture (priv->cogl_tex_id[2]);
cogl_rectangle_with_texture_coords (0, 0, 200, 213,
texcoords[0], texcoords[1],
texcoords[2], texcoords[3]);
cogl_pop_matrix ();
cogl_push_matrix ();
cogl_translate (200, 200, 0);
cogl_set_source_texture (priv->cogl_tex_id[3]);
cogl_rectangle_with_texture_coords (0, 0, 200, 213,
texcoords[0], texcoords[1],
texcoords[2], texcoords[3]);
cogl_pop_matrix();
}
static void
test_coglbox_finalize (GObject *object)
{
G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object);
}
static void
test_coglbox_dispose (GObject *object)
{
TestCoglboxPrivate *priv;
priv = TEST_COGLBOX_GET_PRIVATE (object);
cogl_handle_unref (priv->cogl_tex_id);
G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object);
}
static void
test_coglbox_init (TestCoglbox *self)
{
TestCoglboxPrivate *priv;
gchar *file;
self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self);
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
priv->cogl_tex_id[0] =
cogl_texture_new_from_file (file,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_ANY,
NULL);
priv->cogl_tex_id[1] =
cogl_texture_new_from_file (file,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_BGRA_8888,
NULL);
priv->cogl_tex_id[2] =
cogl_texture_new_from_file (file,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_ARGB_8888,
NULL);
priv->cogl_tex_id[3] =
cogl_texture_new_from_file (file,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_G_8,
NULL);
g_free (file);
}
static void
test_coglbox_class_init (TestCoglboxClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->finalize = test_coglbox_finalize;
gobject_class->dispose = test_coglbox_dispose;
actor_class->paint = test_coglbox_paint;
}
static ClutterActor*
test_coglbox_new (void)
{
return g_object_new (TEST_TYPE_COGLBOX, NULL);
}
G_MODULE_EXPORT int
test_cogl_tex_convert_main (int argc, char *argv[])
{
ClutterActor *stage;
ClutterActor *coglbox;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
/* Stage */
stage = clutter_stage_new ();
clutter_actor_set_size (stage, 400, 400);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Texture Conversion");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* Cogl Box */
coglbox = test_coglbox_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox);
clutter_actor_show_all (stage);
clutter_main ();
return 0;
}
G_MODULE_EXPORT const char *
test_cogl_tex_convert_describe (void)
{
return "Pixel format conversion of Cogl textures.";
}

View File

@ -0,0 +1,425 @@
#include <glib.h>
#include <gmodule.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
/* Coglbox declaration
*--------------------------------------------------*/
G_BEGIN_DECLS
#define TEST_TYPE_COGLBOX test_coglbox_get_type()
#define TEST_COGLBOX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
TEST_TYPE_COGLBOX, TestCoglbox))
#define TEST_COGLBOX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
TEST_TYPE_COGLBOX, TestCoglboxClass))
#define TEST_IS_COGLBOX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
TEST_TYPE_COGLBOX))
#define TEST_IS_COGLBOX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
TEST_TYPE_COGLBOX))
#define TEST_COGLBOX_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
TEST_TYPE_COGLBOX, TestCoglboxClass))
typedef struct _TestCoglbox TestCoglbox;
typedef struct _TestCoglboxClass TestCoglboxClass;
typedef struct _TestCoglboxPrivate TestCoglboxPrivate;
struct _TestCoglbox
{
ClutterActor parent;
/*< private >*/
TestCoglboxPrivate *priv;
};
struct _TestCoglboxClass
{
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_test_coglbox1) (void);
void (*_test_coglbox2) (void);
void (*_test_coglbox3) (void);
void (*_test_coglbox4) (void);
};
static GType test_coglbox_get_type (void) G_GNUC_CONST;
int
test_cogl_tex_polygon_main (int argc, char *argv[]);
const char *
test_cogl_tex_polygon_describe (void);
G_END_DECLS
/* Coglbox private declaration
*--------------------------------------------------*/
struct _TestCoglboxPrivate
{
CoglHandle sliced_tex, not_sliced_tex;
gint frame;
gboolean use_sliced;
gboolean use_linear_filtering;
};
G_DEFINE_TYPE_WITH_PRIVATE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR);
#define TEST_COGLBOX_GET_PRIVATE(obj) \
((TestCoglboxPrivate *)test_coglbox_get_instance_private (TEST_COGLBOX ((obj))))
/* Coglbox implementation
*--------------------------------------------------*/
static void
test_coglbox_fade_texture (gfloat x1,
gfloat y1,
gfloat x2,
gfloat y2,
gfloat tx1,
gfloat ty1,
gfloat tx2,
gfloat ty2)
{
CoglTextureVertex vertices[4];
int i;
vertices[0].x = x1;
vertices[0].y = y1;
vertices[0].z = 0;
vertices[0].tx = tx1;
vertices[0].ty = ty1;
vertices[1].x = x1;
vertices[1].y = y2;
vertices[1].z = 0;
vertices[1].tx = tx1;
vertices[1].ty = ty2;
vertices[2].x = x2;
vertices[2].y = y2;
vertices[2].z = 0;
vertices[2].tx = tx2;
vertices[2].ty = ty2;
vertices[3].x = x2;
vertices[3].y = y1;
vertices[3].z = 0;
vertices[3].tx = tx2;
vertices[3].ty = ty1;
for (i = 0; i < 4; i++)
{
cogl_color_init_from_4ub (&(vertices[i].color),
255,
255,
255,
((i ^ (i >> 1)) & 1) ? 0 : 128);
cogl_color_premultiply (&(vertices[i].color));
}
cogl_polygon (vertices, 4, TRUE);
}
static void
test_coglbox_triangle_texture (int tex_width,
int tex_height,
gfloat x,
gfloat y,
gfloat tx1,
gfloat ty1,
gfloat tx2,
gfloat ty2,
gfloat tx3,
gfloat ty3)
{
CoglTextureVertex vertices[3];
vertices[0].x = x + tx1 * tex_width;
vertices[0].y = y + ty1 * tex_height;
vertices[0].z = 0;
vertices[0].tx = tx1;
vertices[0].ty = ty1;
vertices[1].x = x + tx2 * tex_width;
vertices[1].y = y + ty2 * tex_height;
vertices[1].z = 0;
vertices[1].tx = tx2;
vertices[1].ty = ty2;
vertices[2].x = x + tx3 * tex_width;
vertices[2].y = y + ty3 * tex_height;
vertices[2].z = 0;
vertices[2].tx = tx3;
vertices[2].ty = ty3;
cogl_polygon (vertices, 3, FALSE);
}
static void
test_coglbox_paint (ClutterActor *self)
{
TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self);
CoglHandle tex_handle = priv->use_sliced ? priv->sliced_tex
: priv->not_sliced_tex;
int tex_width = cogl_texture_get_width (tex_handle);
int tex_height = cogl_texture_get_height (tex_handle);
CoglHandle material = cogl_material_new ();
cogl_material_set_layer (material, 0, tex_handle);
cogl_material_set_layer_filters (material, 0,
priv->use_linear_filtering
? COGL_MATERIAL_FILTER_LINEAR :
COGL_MATERIAL_FILTER_NEAREST,
priv->use_linear_filtering
? COGL_MATERIAL_FILTER_LINEAR :
COGL_MATERIAL_FILTER_NEAREST);
cogl_push_matrix ();
cogl_translate (tex_width / 2, 0, 0);
cogl_rotate (priv->frame, 0, 1, 0);
cogl_translate (-tex_width / 2, 0, 0);
/* Draw a hand and refect it */
cogl_set_source (material);
cogl_rectangle_with_texture_coords (0, 0, tex_width, tex_height,
0, 0, 1, 1);
test_coglbox_fade_texture (0, tex_height,
tex_width, (tex_height * 3 / 2),
0.0, 1.0,
1.0, 0.5);
cogl_pop_matrix ();
cogl_push_matrix ();
cogl_translate (tex_width * 3 / 2 + 60, 0, 0);
cogl_rotate (priv->frame, 0, 1, 0);
cogl_translate (-tex_width / 2 - 10, 0, 0);
/* Draw the texture split into two triangles */
test_coglbox_triangle_texture (tex_width, tex_height,
0, 0,
0, 0,
0, 1,
1, 1);
test_coglbox_triangle_texture (tex_width, tex_height,
20, 0,
0, 0,
1, 0,
1, 1);
cogl_pop_matrix ();
cogl_handle_unref (material);
}
static void
test_coglbox_finalize (GObject *object)
{
G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object);
}
static void
test_coglbox_dispose (GObject *object)
{
TestCoglboxPrivate *priv;
priv = TEST_COGLBOX_GET_PRIVATE (object);
cogl_handle_unref (priv->not_sliced_tex);
cogl_handle_unref (priv->sliced_tex);
G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object);
}
static void
test_coglbox_init (TestCoglbox *self)
{
TestCoglboxPrivate *priv;
GError *error = NULL;
gchar *file;
self->priv = priv = TEST_COGLBOX_GET_PRIVATE (self);
priv->use_linear_filtering = FALSE;
priv->use_sliced = FALSE;
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
priv->sliced_tex =
cogl_texture_new_from_file (file,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_ANY,
&error);
if (priv->sliced_tex == COGL_INVALID_HANDLE)
{
if (error)
{
g_warning ("Texture loading failed: %s", error->message);
g_error_free (error);
error = NULL;
}
else
g_warning ("Texture loading failed: <unknown>");
}
priv->not_sliced_tex =
cogl_texture_new_from_file (file,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY,
&error);
if (priv->not_sliced_tex == COGL_INVALID_HANDLE)
{
if (error)
{
g_warning ("Texture loading failed: %s", error->message);
g_error_free (error);
}
else
g_warning ("Texture loading failed: <unknown>");
}
g_free (file);
}
static void
test_coglbox_class_init (TestCoglboxClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->finalize = test_coglbox_finalize;
gobject_class->dispose = test_coglbox_dispose;
actor_class->paint = test_coglbox_paint;
}
static ClutterActor*
test_coglbox_new (void)
{
return g_object_new (TEST_TYPE_COGLBOX, NULL);
}
static void
frame_cb (ClutterTimeline *timeline,
gint elapsed_msecs,
gpointer data)
{
TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (data);
gdouble progress = clutter_timeline_get_progress (timeline);
priv->frame = 360.0 * progress;
clutter_actor_queue_redraw (CLUTTER_ACTOR (data));
}
static void
update_toggle_text (ClutterText *button, gboolean val)
{
clutter_text_set_text (button, val ? "Enabled" : "Disabled");
}
static gboolean
on_toggle_click (ClutterActor *button, ClutterEvent *event,
gboolean *toggle_val)
{
update_toggle_text (CLUTTER_TEXT (button), *toggle_val = !*toggle_val);
return TRUE;
}
static ClutterActor *
make_toggle (const char *label_text, gboolean *toggle_val)
{
ClutterActor *group = clutter_group_new ();
ClutterActor *label = clutter_text_new_with_text ("Sans 14", label_text);
ClutterActor *button = clutter_text_new_with_text ("Sans 14", "");
clutter_actor_set_reactive (button, TRUE);
update_toggle_text (CLUTTER_TEXT (button), *toggle_val);
clutter_actor_set_position (button, clutter_actor_get_width (label) + 10, 0);
clutter_container_add (CLUTTER_CONTAINER (group), label, button, NULL);
g_signal_connect (button, "button-press-event", G_CALLBACK (on_toggle_click),
toggle_val);
return group;
}
G_MODULE_EXPORT int
test_cogl_tex_polygon_main (int argc, char *argv[])
{
ClutterActor *stage;
ClutterActor *coglbox;
ClutterActor *filtering_toggle;
ClutterActor *slicing_toggle;
ClutterActor *note;
ClutterTimeline *timeline;
ClutterColor blue = { 0x30, 0x30, 0xff, 0xff };
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
/* Stage */
stage = clutter_stage_new ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &blue);
clutter_actor_set_size (stage, 640, 480);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Texture Polygon");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* Cogl Box */
coglbox = test_coglbox_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox);
/* Timeline for animation */
timeline = clutter_timeline_new (6000);
clutter_timeline_set_loop (timeline, TRUE);
g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), coglbox);
clutter_timeline_start (timeline);
/* Labels for toggling settings */
slicing_toggle = make_toggle ("Texture slicing: ",
&(TEST_COGLBOX_GET_PRIVATE (coglbox)
->use_sliced));
clutter_actor_set_position (slicing_toggle, 0,
clutter_actor_get_height (stage)
- clutter_actor_get_height (slicing_toggle));
filtering_toggle = make_toggle ("Linear filtering: ",
&(TEST_COGLBOX_GET_PRIVATE (coglbox)
->use_linear_filtering));
clutter_actor_set_position (filtering_toggle, 0,
clutter_actor_get_y (slicing_toggle)
- clutter_actor_get_height (filtering_toggle));
note = clutter_text_new_with_text ("Sans 10", "<- Click to change");
clutter_actor_set_position (note,
clutter_actor_get_width (filtering_toggle) + 10,
(clutter_actor_get_height (stage)
+ clutter_actor_get_y (filtering_toggle)) / 2
- clutter_actor_get_height (note) / 2);
clutter_container_add (CLUTTER_CONTAINER (stage),
slicing_toggle,
filtering_toggle,
note,
NULL);
clutter_actor_show (stage);
clutter_main ();
return 0;
}
G_MODULE_EXPORT const char *
test_cogl_tex_polygon_describe (void)
{
return "Texture polygon primitive.";
}

View File

@ -0,0 +1,223 @@
#include <glib.h>
#include <gmodule.h>
#include <stdlib.h>
#include <math.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
/* Coglbox declaration
*--------------------------------------------------*/
G_BEGIN_DECLS
#define TEST_TYPE_COGLBOX test_coglbox_get_type()
#define TEST_COGLBOX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
TEST_TYPE_COGLBOX, TestCoglbox))
#define TEST_COGLBOX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
TEST_TYPE_COGLBOX, TestCoglboxClass))
#define TEST_IS_COGLBOX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
TEST_TYPE_COGLBOX))
#define TEST_IS_COGLBOX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
TEST_TYPE_COGLBOX))
#define TEST_COGLBOX_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
TEST_TYPE_COGLBOX, TestCoglboxClass))
typedef struct _TestCoglbox TestCoglbox;
typedef struct _TestCoglboxClass TestCoglboxClass;
typedef struct _TestCoglboxPrivate TestCoglboxPrivate;
struct _TestCoglbox
{
ClutterActor parent;
/*< private >*/
TestCoglboxPrivate *priv;
};
struct _TestCoglboxClass
{
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_test_coglbox1) (void);
void (*_test_coglbox2) (void);
void (*_test_coglbox3) (void);
void (*_test_coglbox4) (void);
};
static GType test_coglbox_get_type (void) G_GNUC_CONST;
int
test_cogl_tex_tile_main (int argc, char *argv[]);
const char *
test_cogl_tex_tile_describe (void);
G_END_DECLS
/* Coglbox private declaration
*--------------------------------------------------*/
struct _TestCoglboxPrivate
{
CoglHandle cogl_tex_id;
gdouble animation_progress;
};
G_DEFINE_TYPE_WITH_PRIVATE (TestCoglbox, test_coglbox, CLUTTER_TYPE_ACTOR);
#define TEST_COGLBOX_GET_PRIVATE(obj) \
(test_coglbox_get_instance_private (TEST_COGLBOX ((obj))))
/* Coglbox implementation
*--------------------------------------------------*/
static void
test_coglbox_paint (ClutterActor *self)
{
TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (self);
gfloat texcoords[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
gfloat angle;
gfloat frac;
gint t;
angle = priv->animation_progress * 2 * G_PI;
frac = ((priv->animation_progress <= 0.5f
? priv->animation_progress
: 1.0f - priv->animation_progress) + 0.5f) * 2.0f;
for (t=0; t<4; t+=2)
{
texcoords[t] += cos (angle);
texcoords[t+1] += sin (angle);
texcoords[t] *= frac;
texcoords[t+1] *= frac;
}
priv = TEST_COGLBOX_GET_PRIVATE (self);
cogl_push_matrix ();
cogl_set_source_color4ub (0x66, 0x66, 0xdd, 0xff);
cogl_rectangle (0, 0, 400, 400);
cogl_translate (100, 100, 0);
cogl_set_source_texture (priv->cogl_tex_id);
cogl_rectangle_with_texture_coords (0, 0, 200, 213,
texcoords[0], texcoords[1],
texcoords[2], texcoords[3]);
cogl_pop_matrix();
}
static void
test_coglbox_finalize (GObject *object)
{
G_OBJECT_CLASS (test_coglbox_parent_class)->finalize (object);
}
static void
test_coglbox_dispose (GObject *object)
{
TestCoglboxPrivate *priv;
priv = TEST_COGLBOX_GET_PRIVATE (object);
cogl_handle_unref (priv->cogl_tex_id);
G_OBJECT_CLASS (test_coglbox_parent_class)->dispose (object);
}
static void
test_coglbox_init (TestCoglbox *self)
{
TestCoglboxPrivate *priv;
gchar *file;
self->priv = priv = TEST_COGLBOX_GET_PRIVATE(self);
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
priv->cogl_tex_id = cogl_texture_new_from_file (file,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_ANY,
NULL);
g_free (file);
}
static void
test_coglbox_class_init (TestCoglboxClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->finalize = test_coglbox_finalize;
gobject_class->dispose = test_coglbox_dispose;
actor_class->paint = test_coglbox_paint;
}
static ClutterActor*
test_coglbox_new (void)
{
return g_object_new (TEST_TYPE_COGLBOX, NULL);
}
static void
frame_cb (ClutterTimeline *timeline,
gint msecs,
gpointer data)
{
TestCoglboxPrivate *priv = TEST_COGLBOX_GET_PRIVATE (data);
priv->animation_progress = clutter_timeline_get_progress (timeline);
clutter_actor_queue_redraw (CLUTTER_ACTOR (data));
}
G_MODULE_EXPORT int
test_cogl_tex_tile_main (int argc, char *argv[])
{
ClutterActor *stage;
ClutterActor *coglbox;
ClutterTimeline *timeline;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
/* Stage */
stage = clutter_stage_new ();
clutter_actor_set_size (stage, 400, 400);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Texture Tiling");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* Cogl Box */
coglbox = test_coglbox_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), coglbox);
/* Timeline for animation */
timeline = clutter_timeline_new (6000); /* 6 second duration */
clutter_timeline_set_loop (timeline, TRUE);
g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), coglbox);
clutter_timeline_start (timeline);
clutter_actor_show_all (stage);
clutter_main ();
return 0;
}
G_MODULE_EXPORT const char *
test_cogl_tex_tile_describe (void)
{
return "Texture tiling.";
}

View File

@ -0,0 +1,396 @@
#include <glib.h>
#include <gmodule.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <math.h>
/* Defines the size and resolution of the quad mesh we morph:
*/
#define MESH_WIDTH 100.0 /* number of quads along x axis */
#define MESH_HEIGHT 100.0 /* number of quads along y axis */
#define QUAD_WIDTH 5.0 /* width in pixels of a single quad */
#define QUAD_HEIGHT 5.0 /* height in pixels of a single quad */
/* Defines a sine wave that sweeps across the mesh:
*/
#define WAVE_DEPTH ((MESH_WIDTH * QUAD_WIDTH) / 16.0) /* peak amplitude */
#define WAVE_PERIODS 4.0
#define WAVE_SPEED 10.0
/* Defines a rippling sine wave emitted from a point:
*/
#define RIPPLE_CENTER_X ((MESH_WIDTH / 2.0) * QUAD_WIDTH)
#define RIPPLE_CENTER_Y ((MESH_HEIGHT / 2.0) * QUAD_HEIGHT)
#define RIPPLE_RADIUS (MESH_WIDTH * QUAD_WIDTH)
#define RIPPLE_DEPTH ((MESH_WIDTH * QUAD_WIDTH) / 16.0) /* peak amplitude */
#define RIPPLE_PERIODS 4.0
#define RIPPLE_SPEED -10.0
/* Defines the width of the gaussian bell used to fade out the alpha
* towards the edges of the mesh (starting from the ripple center):
*/
#define GAUSSIAN_RADIUS ((MESH_WIDTH * QUAD_WIDTH) / 6.0)
/* Our hues lie in the range [0, 1], and this defines how we map amplitude
* to hues (before scaling by {WAVE,RIPPLE}_DEPTH)
* As we are interferring two sine waves together; amplitudes lie in the
* range [-2, 2]
*/
#define HSL_OFFSET 0.5 /* the hue that we map an amplitude of 0 too */
#define HSL_SCALE 0.25
typedef struct _TestState
{
ClutterActor *dummy;
CoglHandle buffer;
float *quad_mesh_verts;
guint8 *quad_mesh_colors;
guint16 *static_indices;
guint n_static_indices;
CoglHandle indices;
ClutterTimeline *timeline;
guint frame_id;
} TestState;
int
test_cogl_vertex_buffer_main (int argc, char *argv[]);
const char *
test_cogl_vertex_buffer_describe (void);
static void
frame_cb (ClutterTimeline *timeline,
gint elapsed_msecs,
TestState *state)
{
guint x, y;
float period_progress = clutter_timeline_get_progress (timeline);
float period_progress_sin = sinf (period_progress);
float wave_shift = period_progress * WAVE_SPEED;
float ripple_shift = period_progress * RIPPLE_SPEED;
for (y = 0; y <= MESH_HEIGHT; y++)
for (x = 0; x <= MESH_WIDTH; x++)
{
guint vert_index = (MESH_WIDTH + 1) * y + x;
float *vert = &state->quad_mesh_verts[3 * vert_index];
float real_x = x * QUAD_WIDTH;
float real_y = y * QUAD_HEIGHT;
float wave_offset = (float)x / (MESH_WIDTH + 1);
float wave_angle =
(WAVE_PERIODS * 2 * G_PI * wave_offset) + wave_shift;
float wave_sin = sinf (wave_angle);
float a_sqr = (RIPPLE_CENTER_X - real_x) * (RIPPLE_CENTER_X - real_x);
float b_sqr = (RIPPLE_CENTER_Y - real_y) * (RIPPLE_CENTER_Y - real_y);
float ripple_offset = sqrtf (a_sqr + b_sqr) / RIPPLE_RADIUS;
float ripple_angle =
(RIPPLE_PERIODS * 2 * G_PI * ripple_offset) + ripple_shift;
float ripple_sin = sinf (ripple_angle);
float h, s, l;
guint8 *color;
vert[2] = (wave_sin * WAVE_DEPTH) + (ripple_sin * RIPPLE_DEPTH);
/* Burn some CPU time picking a pretty color... */
h = (HSL_OFFSET
+ wave_sin
+ ripple_sin
+ period_progress_sin) * HSL_SCALE;
s = 0.5;
l = 0.25 + (period_progress_sin + 1.0) / 4.0;
color = &state->quad_mesh_colors[4 * vert_index];
/* A bit of a sneaky cast, but it seems safe to assume the ClutterColor
* typedef is set in stone... */
clutter_color_from_hls ((ClutterColor *)color, h * 360.0, l, s);
color[0] = (color[0] * color[3] + 128) / 255;
color[1] = (color[1] * color[3] + 128) / 255;
color[2] = (color[2] * color[3] + 128) / 255;
}
cogl_vertex_buffer_add (state->buffer,
"gl_Vertex",
3, /* n components */
COGL_ATTRIBUTE_TYPE_FLOAT,
FALSE, /* normalized */
0, /* stride */
state->quad_mesh_verts);
cogl_vertex_buffer_add (state->buffer,
"gl_Color",
4, /* n components */
COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE,
FALSE, /* normalized */
0, /* stride */
state->quad_mesh_colors);
cogl_vertex_buffer_submit (state->buffer);
clutter_actor_set_rotation (state->dummy,
CLUTTER_Z_AXIS,
360 * period_progress,
(MESH_WIDTH * QUAD_WIDTH) / 2,
(MESH_HEIGHT * QUAD_HEIGHT) / 2,
0);
clutter_actor_set_rotation (state->dummy,
CLUTTER_X_AXIS,
360 * period_progress,
(MESH_WIDTH * QUAD_WIDTH) / 2,
(MESH_HEIGHT * QUAD_HEIGHT) / 2,
0);
}
static void
on_paint (ClutterActor *actor, TestState *state)
{
cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff);
cogl_vertex_buffer_draw_elements (state->buffer,
COGL_VERTICES_MODE_TRIANGLE_STRIP,
state->indices,
0, /* min index */
(MESH_WIDTH + 1) *
(MESH_HEIGHT + 1) - 1, /* max index */
0, /* indices offset */
state->n_static_indices);
}
static void
init_static_index_arrays (TestState *state)
{
guint n_indices;
int x, y;
guint16 *i;
guint dir;
/* - Each row takes (2 + 2 * MESH_WIDTH indices)
* - Thats 2 to start the triangle strip then 2 indices to add 2 triangles
* per mesh quad.
* - We have MESH_HEIGHT rows
* - It takes one extra index for linking between rows (MESH_HEIGHT - 1)
* - A 2 x 3 mesh == 20 indices... */
n_indices = (2 + 2 * MESH_WIDTH) * MESH_HEIGHT + (MESH_HEIGHT - 1);
state->static_indices = g_malloc (sizeof (guint16) * n_indices);
state->n_static_indices = n_indices;
#define MESH_INDEX(X, Y) (Y) * (MESH_WIDTH + 1) + (X)
i = state->static_indices;
/* NB: front facing == anti-clockwise winding */
i[0] = MESH_INDEX (0, 0);
i[1] = MESH_INDEX (0, 1);
i += 2;
#define LEFT 0
#define RIGHT 1
dir = RIGHT;
for (y = 0; y < MESH_HEIGHT; y++)
{
for (x = 0; x < MESH_WIDTH; x++)
{
/* Add 2 triangles per mesh quad... */
if (dir == RIGHT)
{
i[0] = MESH_INDEX (x + 1, y);
i[1] = MESH_INDEX (x + 1, y + 1);
}
else
{
i[0] = MESH_INDEX (MESH_WIDTH - x - 1, y);
i[1] = MESH_INDEX (MESH_WIDTH - x - 1, y + 1);
}
i += 2;
}
/* Link rows... */
if (y == (MESH_HEIGHT - 1))
break;
if (dir == RIGHT)
{
i[0] = MESH_INDEX (MESH_WIDTH, y + 1);
i[1] = MESH_INDEX (MESH_WIDTH, y + 1);
i[2] = MESH_INDEX (MESH_WIDTH, y + 2);
}
else
{
i[0] = MESH_INDEX (0, y + 1);
i[1] = MESH_INDEX (0, y + 1);
i[2] = MESH_INDEX (0, y + 2);
}
i += 3;
dir = !dir;
}
#undef MESH_INDEX
state->indices =
cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT,
state->static_indices,
state->n_static_indices);
}
static float
gaussian (float x, float y)
{
/* Bell width */
float c = GAUSSIAN_RADIUS;
/* Peak amplitude */
float a = 1.0;
/* float a = 1.0 / (c * sqrtf (2.0 * G_PI)); */
/* Center offset */
float b = 0.0;
float dist;
x = x - RIPPLE_CENTER_X;
y = y - RIPPLE_CENTER_Y;
dist = sqrtf (x*x + y*y);
return a * exp ((- ((dist - b) * (dist - b))) / (2.0 * c * c));
}
static void
init_quad_mesh (TestState *state)
{
int x, y;
float *vert;
guint8 *color;
/* Note: we maintain the minimum number of vertices possible. This minimizes
* the work required when we come to morph the geometry.
*
* We use static indices into our mesh so that we can treat the data like a
* single triangle list and drawing can be done in one operation (Note: We
* are using degenerate triangles at the edges to link to the next row)
*/
state->quad_mesh_verts =
g_malloc0 (sizeof (float) * 3 * (MESH_WIDTH + 1) * (MESH_HEIGHT + 1));
state->quad_mesh_colors =
g_malloc0 (sizeof (guint8) * 4 * (MESH_WIDTH + 1) * (MESH_HEIGHT + 1));
vert = state->quad_mesh_verts;
color = state->quad_mesh_colors;
for (y = 0; y <= MESH_HEIGHT; y++)
for (x = 0; x <= MESH_WIDTH; x++)
{
vert[0] = x * QUAD_WIDTH;
vert[1] = y * QUAD_HEIGHT;
vert += 3;
color[3] = gaussian (x * QUAD_WIDTH,
y * QUAD_HEIGHT) * 255.0;
color += 4;
}
state->buffer = cogl_vertex_buffer_new ((MESH_WIDTH + 1)*(MESH_HEIGHT + 1));
cogl_vertex_buffer_add (state->buffer,
"gl_Vertex",
3, /* n components */
COGL_ATTRIBUTE_TYPE_FLOAT,
FALSE, /* normalized */
0, /* stride */
state->quad_mesh_verts);
cogl_vertex_buffer_add (state->buffer,
"gl_Color",
4, /* n components */
COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE,
FALSE, /* normalized */
0, /* stride */
state->quad_mesh_colors);
cogl_vertex_buffer_submit (state->buffer);
init_static_index_arrays (state);
}
/* This creates an actor that has a specific size but that does not result
* in any drawing so we can do our own drawing using Cogl... */
static ClutterActor *
create_dummy_actor (guint width, guint height)
{
ClutterActor *group, *rect;
ClutterColor clr = { 0xff, 0xff, 0xff, 0xff};
group = clutter_group_new ();
rect = clutter_rectangle_new_with_color (&clr);
clutter_actor_set_size (rect, width, height);
clutter_actor_hide (rect);
clutter_container_add_actor (CLUTTER_CONTAINER (group), rect);
return group;
}
static void
stop_and_quit (ClutterActor *actor,
TestState *state)
{
clutter_timeline_stop (state->timeline);
clutter_main_quit ();
}
G_MODULE_EXPORT int
test_cogl_vertex_buffer_main (int argc, char *argv[])
{
TestState state;
ClutterActor *stage;
gfloat stage_w, stage_h;
gint dummy_width, dummy_height;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Vertex Buffers");
clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black);
g_signal_connect (stage, "destroy", G_CALLBACK (stop_and_quit), &state);
clutter_actor_get_size (stage, &stage_w, &stage_h);
dummy_width = MESH_WIDTH * QUAD_WIDTH;
dummy_height = MESH_HEIGHT * QUAD_HEIGHT;
state.dummy = create_dummy_actor (dummy_width, dummy_height);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), state.dummy);
clutter_actor_set_position (state.dummy,
(stage_w / 2.0) - (dummy_width / 2.0),
(stage_h / 2.0) - (dummy_height / 2.0));
state.timeline = clutter_timeline_new (1000);
clutter_timeline_set_loop (state.timeline, TRUE);
state.frame_id = g_signal_connect (state.timeline,
"new-frame",
G_CALLBACK (frame_cb),
&state);
g_signal_connect (state.dummy, "paint", G_CALLBACK (on_paint), &state);
init_quad_mesh (&state);
clutter_actor_show_all (stage);
clutter_timeline_start (state.timeline);
clutter_main ();
cogl_handle_unref (state.buffer);
cogl_handle_unref (state.indices);
return 0;
}
G_MODULE_EXPORT const char *
test_cogl_vertex_buffer_describe (void)
{
return "Vertex buffers support in Cogl.";
}

View File

@ -0,0 +1,240 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
typedef struct _ColorContent {
GObject parent_instance;
double red;
double green;
double blue;
double alpha;
float padding;
} ColorContent;
typedef struct _ColorContentClass {
GObjectClass parent_class;
} ColorContentClass;
static void clutter_content_iface_init (ClutterContentInterface *iface);
GType color_content_get_type (void);
int
test_content_main (int argc, char *argv[]);
const char *
test_content_describe (void);
G_DEFINE_TYPE_WITH_CODE (ColorContent, color_content, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
clutter_content_iface_init))
static void
color_content_paint_content (ClutterContent *content,
ClutterActor *actor,
ClutterPaintNode *root)
{
ColorContent *self = (ColorContent *) content;
ClutterActorBox box, content_box;
ClutterColor 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 = self->alpha * 255;
color.red = self->red * 255;
color.green = self->green * 255;
color.blue = 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 = (1.0 - self->red) * 255;
color.green = (1.0 - self->green) * 255;
color.blue = (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.0;
box.y1 = clutter_actor_box_get_y (&content_box)
+ (clutter_actor_box_get_height (&content_box) - logical.height) / 2.0;
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 = color_content_paint_content;
}
static void
color_content_class_init (ColorContentClass *klass)
{
}
static void
color_content_init (ColorContent *self)
{
}
static ClutterContent *
color_content_new (double red,
double green,
double blue,
double alpha,
float padding)
{
ColorContent *self = g_object_new (color_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 int
test_content_main (int argc, char *argv[])
{
ClutterActor *stage, *grid;
ClutterContent *content;
int i, n_rects;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
stage = clutter_stage_new ();
clutter_actor_set_name (stage, "Stage");
clutter_stage_set_title (CLUTTER_STAGE (stage), "Content");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_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_FLOW_HORIZONTAL));
clutter_actor_add_constraint (grid, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0));
clutter_actor_add_child (stage, grid);
content = color_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);
n_rects = g_random_int_range (12, 24);
for (i = 0; i < n_rects; i++)
{
ClutterActor *box = clutter_actor_new ();
ClutterColor bg_color = {
g_random_int_range (0, 255),
g_random_int_range (0, 255),
g_random_int_range (0, 255),
255
};
char *name, *color;
color = clutter_color_to_string (&bg_color);
name = g_strconcat ("Box <", color, ">", NULL);
clutter_actor_set_name (box, name);
g_free (name);
g_free (color);
clutter_actor_set_background_color (box, &bg_color);
clutter_actor_set_content (box, content);
clutter_actor_set_size (box, 64, 64);
clutter_actor_add_child (grid, box);
}
clutter_main ();
g_object_unref (content);
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_content_describe (void)
{
return "A simple test for ClutterContent";
}

View File

@ -0,0 +1,289 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#ifdef CLUTTER_WINDOWING_X11
#include <clutter/x11/clutter-x11.h>
#endif
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 const gchar *
axis_type_name (ClutterInputAxis axis)
{
switch (axis)
{
case CLUTTER_INPUT_AXIS_X:
return "Absolute X";
case CLUTTER_INPUT_AXIS_Y:
return "Absolute Y";
case CLUTTER_INPUT_AXIS_PRESSURE:
return "Pressure";
case CLUTTER_INPUT_AXIS_XTILT:
return "X Tilt";
case CLUTTER_INPUT_AXIS_YTILT:
return "Y Tilt";
case CLUTTER_INPUT_AXIS_WHEEL:
return "Wheel";
default:
return "Unknown";
}
}
static gboolean
stage_button_event_cb (ClutterActor *actor,
ClutterEvent *event,
TestDevicesApp *app)
{
ClutterInputDevice *device;
ClutterInputDevice *source_device;
ClutterActor *hand = NULL;
gdouble *axes;
guint n_axes, i;
device = clutter_event_get_device (event);
source_device = clutter_event_get_source_device (event);
hand = g_hash_table_lookup (app->devices, device);
g_print ("Device: '%s' (id:%d, type: %s, source: '%s', axes: %d)\n",
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device),
device_type_name (device),
source_device != device
? clutter_input_device_get_device_name (source_device)
: "<same>",
clutter_input_device_get_n_axes (device));
if (hand != NULL)
{
gfloat event_x, event_y;
clutter_event_get_coords (event, &event_x, &event_y);
clutter_actor_set_position (hand, event_x, event_y);
}
axes = clutter_event_get_axes (event, &n_axes);
for (i = 0; i < n_axes; i++)
{
ClutterInputAxis axis;
axis = clutter_input_device_get_axis (device, i);
if (axis == CLUTTER_INPUT_AXIS_IGNORE)
continue;
g_print ("\tAxis[%2d][%s].value: %.2f\n",
i,
axis_type_name (axis),
axes[i]);
}
return FALSE;
}
static gboolean
stage_motion_event_cb (ClutterActor *actor,
ClutterEvent *event,
TestDevicesApp *app)
{
ClutterInputDevice *device;
ClutterActor *hand = NULL;
device = clutter_event_get_device (event);
hand = g_hash_table_lookup (app->devices, device);
if (hand != NULL)
{
gfloat event_x, event_y;
clutter_event_get_coords (event, &event_x, &event_y);
clutter_actor_set_position (hand, event_x, event_y);
return TRUE;
}
return FALSE;
}
static void
manager_device_added_cb (ClutterDeviceManager *manager,
ClutterInputDevice *device,
TestDevicesApp *app)
{
ClutterInputDeviceType device_type;
ClutterActor *hand = NULL;
g_print ("got a %s device '%s' with id %d\n",
device_type_name (device),
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device));
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{
g_print ("*** enabling device '%s' ***\n",
clutter_input_device_get_device_name (device));
clutter_input_device_set_enabled (device, TRUE);
hand = clutter_texture_new_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",
NULL);
g_hash_table_insert (app->devices, device, hand);
clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand);
}
}
static void
manager_device_removed_cb (ClutterDeviceManager *manager,
ClutterInputDevice *device,
TestDevicesApp *app)
{
ClutterInputDeviceType device_type;
ClutterActor *hand = NULL;
g_print ("removed a %s device '%s' with id %d\n",
device_type_name (device),
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device));
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{
hand = g_hash_table_lookup (app->devices, device);
if (hand != NULL)
clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand);
g_hash_table_remove (app->devices, device);
}
}
G_MODULE_EXPORT int
test_devices_main (int argc, char **argv)
{
ClutterActor *stage;
TestDevicesApp *app;
ClutterDeviceManager *manager;
const GSList *stage_devices, *l;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
app = g_new0 (TestDevicesApp, 1);
app->devices = g_hash_table_new (g_direct_hash, g_direct_equal) ;
stage = clutter_stage_new ();
clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Devices");
clutter_stage_hide_cursor (CLUTTER_STAGE (stage));
g_signal_connect (stage,
"destroy", G_CALLBACK (clutter_main_quit),
NULL);
g_signal_connect (stage,
"motion-event", G_CALLBACK (stage_motion_event_cb),
app);
g_signal_connect (stage,
"button-press-event", G_CALLBACK (stage_button_event_cb),
app);
app->stage = stage;
clutter_actor_show_all (stage);
manager = clutter_device_manager_get_default ();
g_signal_connect (manager,
"device-added", G_CALLBACK (manager_device_added_cb),
app);
g_signal_connect (manager,
"device-removed", G_CALLBACK (manager_device_removed_cb),
app);
stage_devices = clutter_device_manager_peek_devices (manager);
if (stage_devices == NULL)
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' with id %d\n",
device_type_name (device),
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device));
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{
g_print ("*** enabling device '%s' ***\n",
clutter_input_device_get_device_name (device));
clutter_input_device_set_enabled (device, TRUE);
hand = clutter_texture_new_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",
NULL);
g_hash_table_insert (app->devices, device, hand);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), hand);
}
}
clutter_main ();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,276 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
/* all the easing modes provided by Clutter */
static const struct {
const gchar *name;
ClutterAnimationMode mode;
} easing_modes[] = {
{ "linear", CLUTTER_LINEAR },
{ "easeInQuad", CLUTTER_EASE_IN_QUAD },
{ "easeOutQuad", CLUTTER_EASE_OUT_QUAD },
{ "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD },
{ "easeInCubic", CLUTTER_EASE_IN_CUBIC },
{ "easeOutCubic", CLUTTER_EASE_OUT_CUBIC },
{ "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC },
{ "easeInQuart", CLUTTER_EASE_IN_QUART },
{ "easeOutQuart", CLUTTER_EASE_OUT_QUART },
{ "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART },
{ "easeInQuint", CLUTTER_EASE_IN_QUINT },
{ "easeOutQuint", CLUTTER_EASE_OUT_QUINT },
{ "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT },
{ "easeInSine", CLUTTER_EASE_IN_SINE },
{ "easeOutSine", CLUTTER_EASE_OUT_SINE },
{ "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE },
{ "easeInExpo", CLUTTER_EASE_IN_EXPO },
{ "easeOutExpo", CLUTTER_EASE_OUT_EXPO },
{ "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO },
{ "easeInCirc", CLUTTER_EASE_IN_CIRC },
{ "easeOutCirc", CLUTTER_EASE_OUT_CIRC },
{ "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC },
{ "easeInElastic", CLUTTER_EASE_IN_ELASTIC },
{ "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC },
{ "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC },
{ "easeInBack", CLUTTER_EASE_IN_BACK },
{ "easeOutBack", CLUTTER_EASE_OUT_BACK },
{ "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK },
{ "easeInBounce", CLUTTER_EASE_IN_BOUNCE },
{ "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE },
{ "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE },
};
#define HELP_TEXT "Easing mode: %s (%d of %d)\n" \
"Left click to tween\n" \
"Right click to change the easing mode"
static const gint n_easing_modes = G_N_ELEMENTS (easing_modes);
static gint current_mode = 0;
static gint duration = 1;
static gboolean recenter = FALSE;
static ClutterActor *main_stage = NULL;
static ClutterActor *easing_mode_label = NULL;
static ClutterAnimation *last_animation = NULL;
int
test_easing_main (int argc, char *argv[]);
const char *
test_easing_describe (void);
/* recenter_bouncer:
*
* repositions (through an animation) the bouncer at the center of the stage
*/
static void
recenter_bouncer (ClutterAnimation *animation,
ClutterActor *rectangle)
{
gfloat base_x, base_y;
gint cur_mode;
base_x = clutter_actor_get_width (main_stage) / 2;
base_y = clutter_actor_get_height (main_stage) / 2;
cur_mode = easing_modes[current_mode].mode;
clutter_actor_animate (rectangle, cur_mode, 250,
"x", base_x,
"y", base_y,
NULL);
}
static gboolean
on_button_press (ClutterActor *actor,
ClutterButtonEvent *event,
ClutterActor *rectangle)
{
if (event->button == CLUTTER_BUTTON_SECONDARY)
{
gchar *text;
/* cycle through the various easing modes */
current_mode = (current_mode + 1 < n_easing_modes)
? current_mode + 1
: 0;
/* update the text of the label */
text = g_strdup_printf (HELP_TEXT,
easing_modes[current_mode].name,
current_mode + 1,
n_easing_modes);
clutter_text_set_text (CLUTTER_TEXT (easing_mode_label), text);
g_free (text);
}
else if (event->button == CLUTTER_BUTTON_PRIMARY)
{
ClutterAnimation *animation;
ClutterAnimationMode cur_mode;
cur_mode = easing_modes[current_mode].mode;
/* tween the actor using the current easing mode */
animation =
clutter_actor_animate (rectangle, cur_mode, duration * 1000,
"x", event->x,
"y", event->y,
NULL);
/* if we were asked to, recenter the bouncer at the end of the
* animation. we keep track of the animation to avoid connecting
* the signal handler to the same Animation twice.
*/
if (recenter && last_animation != animation)
g_signal_connect_after (animation, "completed",
G_CALLBACK (recenter_bouncer),
rectangle);
last_animation = animation;
}
return TRUE;
}
static gboolean
draw_bouncer (ClutterCairoTexture *texture,
cairo_t *cr)
{
const ClutterColor *bouncer_color;
cairo_pattern_t *pattern;
guint width, height;
float radius;
clutter_cairo_texture_get_surface_size (texture, &width, &height);
radius = MAX (width, height);
clutter_cairo_texture_clear (texture);
cairo_arc (cr, radius / 2, radius / 2, radius / 2, 0.0, 2.0 * G_PI);
bouncer_color = CLUTTER_COLOR_DarkScarletRed;
pattern = cairo_pattern_create_radial (radius / 2, radius / 2, 0,
radius, radius, radius);
cairo_pattern_add_color_stop_rgba (pattern,
0,
bouncer_color->red / 255.0,
bouncer_color->green / 255.0,
bouncer_color->blue / 255.0,
bouncer_color->alpha / 255.0);
cairo_pattern_add_color_stop_rgba (pattern,
0.85,
bouncer_color->red / 255.0,
bouncer_color->green / 255.0,
bouncer_color->blue / 255.0,
0.25);
cairo_set_source (cr, pattern);
cairo_fill_preserve (cr);
cairo_pattern_destroy (pattern);
return TRUE;
}
static ClutterActor *
make_bouncer (gfloat width,
gfloat height)
{
ClutterActor *retval;
retval = clutter_cairo_texture_new (width, height);
g_signal_connect (retval, "draw", G_CALLBACK (draw_bouncer), NULL);
clutter_actor_set_name (retval, "bouncer");
clutter_actor_set_size (retval, width, height);
clutter_actor_set_anchor_point (retval, width / 2, height / 2);
clutter_actor_set_reactive (retval, TRUE);
/* make sure we draw the bouncer immediately */
clutter_cairo_texture_invalidate (CLUTTER_CAIRO_TEXTURE (retval));
return retval;
}
static GOptionEntry test_easing_entries[] = {
{
"re-center", 'r',
0,
G_OPTION_ARG_NONE, &recenter,
"Re-center the actor when the animation ends",
NULL
},
{
"duration", 'd',
0,
G_OPTION_ARG_INT, &duration,
"Duration of the animation",
"SECONDS"
},
{ NULL }
};
G_MODULE_EXPORT int
test_easing_main (int argc, char *argv[])
{
ClutterActor *stage, *rect, *label;
gchar *text;
gfloat stage_width, stage_height;
GError *error = NULL;
if (clutter_init_with_args (&argc, &argv,
NULL,
test_easing_entries,
NULL,
&error) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Easing Modes");
clutter_actor_set_background_color (stage, CLUTTER_COLOR_LightSkyBlue);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
main_stage = stage;
clutter_actor_get_size (stage, &stage_width, &stage_height);
/* create the actor that we want to tween */
rect = make_bouncer (50, 50);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
clutter_actor_set_position (rect, stage_width / 2, stage_height / 2);
text = g_strdup_printf (HELP_TEXT,
easing_modes[current_mode].name,
current_mode + 1,
n_easing_modes);
label = clutter_text_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), label);
clutter_text_set_text (CLUTTER_TEXT (label), text);
clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_X_AXIS, 0.95));
clutter_actor_add_constraint (label, clutter_align_constraint_new (stage, CLUTTER_ALIGN_Y_AXIS, 0.95));
easing_mode_label = label;
g_free (text);
g_signal_connect (stage,
"button-press-event", G_CALLBACK (on_button_press),
rect);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_easing_describe (void)
{
return "Visualize all easing modes provided by Clutter";
}

View File

@ -0,0 +1,494 @@
#include <gmodule.h>
#include <clutter/clutter.h>
#include <string.h>
gboolean IsMotion = TRUE;
int
test_events_main (int argc, char *argv[]);
const char *
test_events_describe (void);
static const gchar *
get_event_type_name (const ClutterEvent *event)
{
switch (event->type)
{
case CLUTTER_BUTTON_PRESS:
return "BUTTON PRESS";
case CLUTTER_BUTTON_RELEASE:
return "BUTTON_RELEASE";
case CLUTTER_KEY_PRESS:
return "KEY PRESS";
case CLUTTER_KEY_RELEASE:
return "KEY RELEASE";
case CLUTTER_ENTER:
return "ENTER";
case CLUTTER_LEAVE:
return "LEAVE";
case CLUTTER_MOTION:
return "MOTION";
case CLUTTER_DELETE:
return "DELETE";
case CLUTTER_TOUCH_BEGIN:
return "TOUCH BEGIN";
case CLUTTER_TOUCH_UPDATE:
return "TOUCH UPDATE";
case CLUTTER_TOUCH_END:
return "TOUCH END";
case CLUTTER_TOUCH_CANCEL:
return "TOUCH CANCEL";
default:
return "EVENT";
}
}
static gchar *
get_event_state_string (const ClutterEvent *event)
{
const char *mods[18];
int i = 0;
ClutterModifierType state = clutter_event_get_state (event);
if (state & CLUTTER_SHIFT_MASK)
mods[i++] = "shift";
if (state & CLUTTER_LOCK_MASK)
mods[i++] = "lock";
if (state & CLUTTER_CONTROL_MASK)
mods[i++] = "ctrl";
if (state & CLUTTER_MOD1_MASK)
mods[i++] = "mod1";
if (state & CLUTTER_MOD2_MASK)
mods[i++] = "mod2";
if (state & CLUTTER_MOD3_MASK)
mods[i++] = "mod3";
if (state & CLUTTER_MOD4_MASK)
mods[i++] = "mod4";
if (state & CLUTTER_MOD5_MASK)
mods[i++] = "mod5";
if (state & CLUTTER_BUTTON1_MASK)
mods[i++] = "btn1";
if (state & CLUTTER_BUTTON2_MASK)
mods[i++] = "btn2";
if (state & CLUTTER_BUTTON3_MASK)
mods[i++] = "btn3";
if (state & CLUTTER_BUTTON4_MASK)
mods[i++] = "btn4";
if (state & CLUTTER_BUTTON5_MASK)
mods[i++] = "btn5";
if (state & CLUTTER_SUPER_MASK)
mods[i++] = "super";
if (state & CLUTTER_HYPER_MASK)
mods[i++] = "hyper";
if (state & CLUTTER_META_MASK)
mods[i++] = "meta";
if (state & CLUTTER_RELEASE_MASK)
mods[i++] = "release";
if (i == 0)
mods[i++] = "-";
mods[i] = NULL;
return g_strjoinv (",", (char **) mods);
}
static void
stage_state_cb (ClutterStage *stage,
gpointer data)
{
gchar *detail = (gchar*)data;
printf("[stage signal] %s\n", detail);
}
static gboolean
red_button_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterActor *stage;
if (IsMotion)
IsMotion = FALSE;
else
IsMotion = TRUE;
stage = clutter_actor_get_stage (actor);
clutter_stage_set_motion_events_enabled (CLUTTER_STAGE (stage),
IsMotion);
g_print ("*** Per actor motion events %s ***\n",
IsMotion ? "enabled" : "disabled");
return FALSE;
}
static gboolean
capture_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
g_print ("* captured event '%s' for type '%s' *\n",
get_event_type_name (event),
G_OBJECT_TYPE_NAME (actor));
return FALSE;
}
static void
key_focus_in_cb (ClutterActor *actor,
gpointer data)
{
ClutterActor *focus_box = CLUTTER_ACTOR (data);
if (CLUTTER_IS_STAGE (actor))
clutter_actor_hide (focus_box);
else
{
clutter_actor_set_position (focus_box,
clutter_actor_get_x (actor) - 5,
clutter_actor_get_y (actor) - 5);
clutter_actor_set_size (focus_box,
clutter_actor_get_width (actor) + 10,
clutter_actor_get_height (actor) + 10);
clutter_actor_show (focus_box);
}
}
static void
fill_keybuf (char *keybuf, ClutterKeyEvent *event)
{
char utf8[6];
int len;
/* printable character, if any (ß, ∑) */
len = g_unichar_to_utf8 (event->unicode_value, utf8);
utf8[len] = '\0';
sprintf (keybuf, "'%s' ", utf8);
/* key combination (<Mod1>s, <Shift><Mod1>S, <Ctrl><Mod1>Delete) */
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->keyval), utf8);
utf8[len] = '\0';
if (event->modifier_state & CLUTTER_SHIFT_MASK)
strcat (keybuf, "<Shift>");
if (event->modifier_state & CLUTTER_LOCK_MASK)
strcat (keybuf, "<Lock>");
if (event->modifier_state & CLUTTER_CONTROL_MASK)
strcat (keybuf, "<Control>");
if (event->modifier_state & CLUTTER_MOD1_MASK)
strcat (keybuf, "<Mod1>");
if (event->modifier_state & CLUTTER_MOD2_MASK)
strcat (keybuf, "<Mod2>");
if (event->modifier_state & CLUTTER_MOD3_MASK)
strcat (keybuf, "<Mod3>");
if (event->modifier_state & CLUTTER_MOD4_MASK)
strcat (keybuf, "<Mod4>");
if (event->modifier_state & CLUTTER_MOD5_MASK)
strcat (keybuf, "<Mod5>");
strcat (keybuf, utf8);
}
static gboolean
input_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterActor *stage = clutter_actor_get_stage (actor);
ClutterActor *source_actor = clutter_event_get_source (event);
ClutterPoint position;
gchar *state;
gchar keybuf[128];
gint device_id;
gint source_device_id = 0;
device_id = clutter_event_get_device_id (event);
if (clutter_event_get_source_device (event) != NULL)
source_device_id = clutter_input_device_get_device_id (clutter_event_get_source_device (event));
state = get_event_state_string (event);
switch (event->type)
{
case CLUTTER_KEY_PRESS:
fill_keybuf (keybuf, &event->key);
printf ("[%s] KEY PRESS %s",
clutter_actor_get_name (source_actor),
keybuf);
break;
case CLUTTER_KEY_RELEASE:
fill_keybuf (keybuf, &event->key);
printf ("[%s] KEY RELEASE %s",
clutter_actor_get_name (source_actor),
keybuf);
break;
case CLUTTER_MOTION:
clutter_event_get_position (event, &position);
g_print ("[%s] MOTION (coords:%.02f,%.02f device:%d/%d state:%s)",
clutter_actor_get_name (source_actor), position.x, position.y,
device_id, source_device_id, state);
break;
case CLUTTER_ENTER:
g_print ("[%s] ENTER (from:%s device:%d/%d state:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_related (event) != NULL
? clutter_actor_get_name (clutter_event_get_related (event))
: "<out of stage>",
device_id, source_device_id, state);
break;
case CLUTTER_LEAVE:
g_print ("[%s] LEAVE (to:%s device:%d/%d state:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_related (event) != NULL
? clutter_actor_get_name (clutter_event_get_related (event))
: "<out of stage>",
device_id, source_device_id, state);
break;
case CLUTTER_BUTTON_PRESS:
clutter_event_get_position (event, &position);
g_print ("[%s] BUTTON PRESS (button:%i, click count:%i coords:%.02f,%.02f device:%d/%d, state:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_button (event),
clutter_event_get_click_count (event),
position.x, position.y,
device_id, source_device_id, state);
break;
case CLUTTER_BUTTON_RELEASE:
clutter_event_get_position (event, &position);
g_print ("[%s] BUTTON RELEASE (button:%i, click count:%i coords:%.02f,%.02f device:%d/%d state:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_button (event),
clutter_event_get_click_count (event),
position.x, position.y,
device_id, source_device_id, state);
if (source_actor == stage)
clutter_stage_set_key_focus (CLUTTER_STAGE (stage), NULL);
else if (source_actor == actor &&
clutter_actor_get_parent (actor) == stage)
clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor);
break;
case CLUTTER_TOUCH_BEGIN:
clutter_event_get_position (event, &position);
g_print ("[%s] TOUCH BEGIN (seq:%p coords:%.02f,%.02f device:%d/%d state:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_event_sequence (event),
position.x, position.y,
device_id, source_device_id, state);
break;
case CLUTTER_TOUCH_UPDATE:
clutter_event_get_position (event, &position);
g_print ("[%s] TOUCH UPDATE (seq:%p coords:%.02f,%.02f device:%d/%d state:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_event_sequence (event),
position.x, position.y,
device_id, source_device_id, state);
break;
case CLUTTER_TOUCH_END:
clutter_event_get_position (event, &position);
g_print ("[%s] TOUCH END (seq:%p coords:%.02f,%.02f device:%d/%d state:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_event_sequence (event),
position.x, position.y,
device_id, source_device_id, state);
break;
case CLUTTER_TOUCH_CANCEL:
clutter_event_get_position (event, &position);
g_print ("[%s] TOUCH CANCEL (seq:%p coords:%.02f,%.02f device:%d/%d state:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_event_sequence (event),
position.x, position.y,
device_id, source_device_id, state);
break;
case CLUTTER_SCROLL:
{
ClutterScrollDirection dir = clutter_event_get_scroll_direction (event);
if (dir == CLUTTER_SCROLL_SMOOTH)
{
gdouble dx, dy;
clutter_event_get_scroll_delta (event, &dx, &dy);
g_print ("[%s] BUTTON SCROLL (direction:smooth %.02f,%.02f state:%s)",
clutter_actor_get_name (source_actor), dx, dy, state);
}
else
g_print ("[%s] BUTTON SCROLL (direction:%s state:%s)",
clutter_actor_get_name (source_actor),
dir == CLUTTER_SCROLL_UP ? "up" :
dir == CLUTTER_SCROLL_DOWN ? "down" :
dir == CLUTTER_SCROLL_LEFT ? "left" :
dir == CLUTTER_SCROLL_RIGHT ? "right" : "?",
state);
}
break;
case CLUTTER_STAGE_STATE:
g_print ("[%s] STAGE STATE", clutter_actor_get_name (source_actor));
break;
case CLUTTER_DESTROY_NOTIFY:
g_print ("[%s] DESTROY NOTIFY", clutter_actor_get_name (source_actor));
break;
case CLUTTER_CLIENT_MESSAGE:
g_print ("[%s] CLIENT MESSAGE", clutter_actor_get_name (source_actor));
break;
case CLUTTER_DELETE:
g_print ("[%s] DELETE", clutter_actor_get_name (source_actor));
break;
case CLUTTER_TOUCHPAD_PINCH:
g_print ("[%s] TOUCHPAD PINCH", clutter_actor_get_name (source_actor));
break;
case CLUTTER_TOUCHPAD_SWIPE:
g_print ("[%s] TOUCHPAD SWIPE", clutter_actor_get_name (source_actor));
break;
case CLUTTER_PROXIMITY_IN:
g_print ("[%s] PROXIMITY IN", clutter_actor_get_name (source_actor));
break;
case CLUTTER_PROXIMITY_OUT:
g_print ("[%s] PROXIMITY OUT", clutter_actor_get_name (source_actor));
break;
case CLUTTER_PAD_BUTTON_PRESS:
g_print ("[%s] PAD BUTTON PRESS", clutter_actor_get_name (source_actor));
break;
case CLUTTER_PAD_BUTTON_RELEASE:
g_print ("[%s] PAD BUTTON RELEASE", clutter_actor_get_name (source_actor));
break;
case CLUTTER_PAD_STRIP:
g_print ("[%s] PAD STRIP", clutter_actor_get_name (source_actor));
break;
case CLUTTER_PAD_RING:
g_print ("[%s] PAD RING", clutter_actor_get_name (source_actor));
break;
case CLUTTER_NOTHING:
default:
return FALSE;
}
g_free (state);
if (source_actor == actor)
g_print (" *source*");
g_print ("\n");
return FALSE;
}
G_MODULE_EXPORT int
test_events_main (int argc, char *argv[])
{
ClutterActor *stage, *actor, *focus_box, *group;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Events");
clutter_actor_set_name (stage, "Stage");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
g_signal_connect (stage, "event", G_CALLBACK (input_cb), (char *) "stage");
g_signal_connect (stage, "activate",
G_CALLBACK (stage_state_cb), (char *) "activate");
g_signal_connect (stage, "deactivate",
G_CALLBACK (stage_state_cb), (char *) "deactivate");
focus_box = clutter_rectangle_new_with_color (CLUTTER_COLOR_Black);
clutter_actor_set_name (focus_box, "Focus Box");
clutter_container_add (CLUTTER_CONTAINER(stage), focus_box, NULL);
actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Red);
clutter_actor_set_name (actor, "Red Box");
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 100, 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), (char *) "red box");
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
/* Toggle motion - enter/leave capture */
g_signal_connect (actor, "button-press-event",
G_CALLBACK (red_button_cb), NULL);
clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor);
actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Green);
clutter_actor_set_name (actor, "Green Box");
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 250, 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), (char *) "green box");
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
g_signal_connect (actor, "captured-event", G_CALLBACK (capture_cb), NULL);
/* non reactive */
actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Black);
clutter_actor_set_name (actor, "Black Box");
clutter_actor_set_size (actor, 400, 50);
clutter_actor_set_position (actor, 100, 250);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), (char *) "blue box");
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
g_signal_connect (stage, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
/* non reactive group, with reactive child */
actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Yellow);
clutter_actor_set_name (actor, "Yellow Box");
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_reactive (actor, TRUE);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), (char *) "yellow box");
/* note group not reactive */
group = clutter_group_new ();
clutter_container_add (CLUTTER_CONTAINER (group), actor, NULL);
clutter_container_add (CLUTTER_CONTAINER (stage), group, NULL);
clutter_actor_set_position (group, 100, 350);
clutter_actor_show_all (group);
/* border actor */
actor = clutter_rectangle_new_with_color (CLUTTER_COLOR_Magenta);
clutter_actor_set_name (actor, "Border Box");
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor,
(clutter_actor_get_width (stage) - 100) / 2,
clutter_actor_get_height (stage) - 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), NULL);
clutter_actor_show_all (CLUTTER_ACTOR (stage));
clutter_main();
return 0;
}
G_MODULE_EXPORT const char *
test_events_describe (void)
{
return "Event handling and propagation.";
}

View File

@ -0,0 +1,111 @@
#include <clutter/clutter.h>
#include <errno.h>
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
#define STAGE_WIDTH 800
#define STAGE_HEIGHT 600
int
test_fbo_main (int argc, char *argv[]);
const char *
test_fbo_describe (void);
static ClutterActor *
make_source (void)
{
ClutterActor *source, *actor;
GError *error = NULL;
gchar *file;
ClutterColor yellow = {0xff, 0xff, 0x00, 0xff};
source = clutter_group_new ();
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
actor = clutter_texture_new_from_file (file, &error);
if (!actor)
g_error("pixbuf load failed: %s", error ? error->message : "Unknown");
g_free (file);
clutter_container_add_actor (CLUTTER_CONTAINER (source), actor);
actor = clutter_text_new_with_text ("Sans Bold 50px", "Clutter");
clutter_text_set_color (CLUTTER_TEXT (actor), &yellow);
clutter_actor_set_y (actor, clutter_actor_get_height(source) + 5);
clutter_container_add_actor (CLUTTER_CONTAINER (source), actor);
return source;
}
G_MODULE_EXPORT int
test_fbo_main (int argc, char *argv[])
{
ClutterActor *fbo;
ClutterActor *onscreen_source;
ClutterActor *stage;
ClutterAnimation *animation;
int x_pos = 200;
int y_pos = 100;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
if (clutter_feature_available (CLUTTER_FEATURE_OFFSCREEN) == FALSE)
g_error("This test requires CLUTTER_FEATURE_OFFSCREEN");
stage = clutter_stage_new ();
clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT);
clutter_actor_set_background_color (stage, CLUTTER_COLOR_SkyBlue);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Texture from Actor");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* Create the first source */
onscreen_source = make_source();
clutter_actor_show_all (onscreen_source);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), onscreen_source);
y_pos = (STAGE_HEIGHT/2.0) -
(clutter_actor_get_height (onscreen_source)/2.0);
clutter_actor_set_position (onscreen_source, x_pos, y_pos);
x_pos += clutter_actor_get_width (onscreen_source);
animation = clutter_actor_animate (onscreen_source,
CLUTTER_LINEAR,
5000, /* 1 second duration */
"rotation-angle-y", 360.0f,
NULL);
clutter_animation_set_loop (animation, TRUE);
/* Second hand = actor from onscreen_source */
if ((fbo = clutter_texture_new_from_actor (onscreen_source)) == NULL)
g_error("onscreen fbo creation failed");
clutter_actor_set_position (fbo, x_pos, y_pos);
x_pos += clutter_actor_get_width (fbo);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), fbo);
/* Third hand = actor from Second hand */
if ((fbo = clutter_texture_new_from_actor (fbo)) == NULL)
g_error("fbo from fbo creation failed");
clutter_actor_set_position (fbo, x_pos, y_pos);
x_pos += clutter_actor_get_width (fbo);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), fbo);
clutter_actor_show_all (stage);
clutter_main ();
return 0;
}
G_MODULE_EXPORT const char *
test_fbo_describe (void)
{
return "Create a texture from an actor.";
}

View File

@ -0,0 +1,302 @@
#include <gmodule.h>
#include <clutter/clutter.h>
int
test_grab_main (int argc, char *argv[]);
const char *
test_grab_describe (void);
static void
stage_state_cb (ClutterStage *stage,
gpointer data)
{
gchar *detail = (gchar*)data;
printf("[stage signal] %s\n", detail);
}
static gboolean
debug_event_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
gchar keybuf[9], *source = (gchar*)data;
int len = 0;
switch (event->type)
{
case CLUTTER_KEY_PRESS:
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->key.keyval),
keybuf);
keybuf[len] = '\0';
printf ("[%s] KEY PRESS '%s'", source, keybuf);
break;
case CLUTTER_KEY_RELEASE:
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->key.keyval),
keybuf);
keybuf[len] = '\0';
printf ("[%s] KEY RELEASE '%s'", source, keybuf);
break;
case CLUTTER_MOTION:
printf("[%s] MOTION", source);
break;
case CLUTTER_ENTER:
printf("[%s] ENTER", source);
break;
case CLUTTER_LEAVE:
printf("[%s] LEAVE", source);
break;
case CLUTTER_BUTTON_PRESS:
printf("[%s] BUTTON PRESS (click count:%i)",
source, event->button.click_count);
break;
case CLUTTER_BUTTON_RELEASE:
printf("[%s] BUTTON RELEASE", source);
break;
case CLUTTER_SCROLL:
printf("[%s] BUTTON SCROLL", source);
break;
case CLUTTER_STAGE_STATE:
printf("[%s] STAGE STATE", source);
break;
case CLUTTER_DESTROY_NOTIFY:
printf("[%s] DESTROY NOTIFY", source);
break;
case CLUTTER_CLIENT_MESSAGE:
printf("[%s] CLIENT MESSAGE\n", source);
break;
case CLUTTER_DELETE:
printf("[%s] DELETE", source);
break;
case CLUTTER_TOUCH_BEGIN:
g_print ("[%s] TOUCH BEGIN", source);
break;
case CLUTTER_TOUCH_UPDATE:
g_print ("[%s] TOUCH UPDATE", source);
break;
case CLUTTER_TOUCH_END:
g_print ("[%s] TOUCH END", source);
break;
case CLUTTER_TOUCH_CANCEL:
g_print ("[%s] TOUCH CANCEL", source);
break;
case CLUTTER_TOUCHPAD_PINCH:
g_print ("[%s] TOUCHPAD PINCH", source);
break;
case CLUTTER_TOUCHPAD_SWIPE:
g_print ("[%s] TOUCHPAD SWIPE", source);
break;
case CLUTTER_PROXIMITY_IN:
g_print ("[%s] PROXIMITY IN", source);
break;
case CLUTTER_PROXIMITY_OUT:
g_print ("[%s] PROXIMITY OUT", source);
break;
case CLUTTER_PAD_BUTTON_PRESS:
g_print ("[%s] PAD BUTTON PRESS", source);
break;
case CLUTTER_PAD_BUTTON_RELEASE:
g_print ("[%s] PAD BUTTON RELEASE", source);
break;
case CLUTTER_PAD_STRIP:
g_print ("[%s] PAD STRIP", source);
break;
case CLUTTER_PAD_RING:
g_print ("[%s] PAD RING", source);
break;
case CLUTTER_NOTHING:
default:
return FALSE;
}
if (clutter_event_get_source (event) == actor)
printf(" *source*");
printf("\n");
return FALSE;
}
static gboolean
grab_pointer_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterInputDevice *device = clutter_event_get_device (event);
clutter_input_device_grab (device, actor);
return FALSE;
}
static gboolean
red_release_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterInputDevice *device = clutter_event_get_device (event);
clutter_input_device_ungrab (device);
return FALSE;
}
static gboolean
blue_release_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
clutter_actor_destroy (actor);
return FALSE;
}
static gboolean
green_press_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterActor *stage;
gboolean enabled;
stage = clutter_actor_get_stage (actor);
enabled = !clutter_stage_get_motion_events_enabled (CLUTTER_STAGE (stage));
clutter_stage_set_motion_events_enabled (CLUTTER_STAGE (stage), enabled);
g_print ("per actor motion events are now %s\n",
enabled ? "enabled" : "disabled");
return FALSE;
}
static gboolean
toggle_grab_pointer_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterInputDevice *device = clutter_event_get_device (event);
/* we only deal with the event if the source is ourself */
if (event->button.source == actor)
{
if (clutter_input_device_get_grabbed_actor (device) != NULL)
clutter_input_device_ungrab (device);
else
clutter_input_device_grab (device, actor);
}
return FALSE;
}
static gboolean
cyan_press_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
{
ClutterDeviceManager *dm = clutter_device_manager_get_default ();
ClutterInputDevice *device =
clutter_device_manager_get_core_device (dm, CLUTTER_KEYBOARD_DEVICE);
if (clutter_input_device_get_grabbed_actor (device) != NULL)
clutter_input_device_ungrab (device);
else
clutter_input_device_grab (device, actor);
return FALSE;
}
G_MODULE_EXPORT int
test_grab_main (int argc, char *argv[])
{
ClutterActor *stage, *actor;
ClutterColor rcol = { 0xff, 0, 0, 0xff},
bcol = { 0, 0, 0xff, 0xff },
gcol = { 0, 0xff, 0, 0xff },
ccol = { 0, 0xff, 0xff, 0xff },
ycol = { 0xff, 0xff, 0, 0xff };
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
g_print ("Red box: aquire grab on press, releases it on next button release\n");
g_print ("Blue box: aquire grab on press, destroys the blue box actor on release\n");
g_print ("Yellow box: aquire grab on press, releases grab on next press on yellow box\n");
g_print ("Green box: toggle per actor motion events.\n\n");
g_print ("Cyan box: toggle grab (from cyan box) for keyboard events.\n\n");
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Grabs");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
g_signal_connect (stage, "event",
G_CALLBACK (debug_event_cb), (char *) "stage");
g_signal_connect (stage, "activate",
G_CALLBACK (stage_state_cb), (char *) "activate");
g_signal_connect (stage, "deactivate",
G_CALLBACK (stage_state_cb), (char *) "deactivate");
actor = clutter_rectangle_new_with_color (&rcol);
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 100, 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (debug_event_cb), (char *) "red box");
g_signal_connect (actor, "button-press-event",
G_CALLBACK (grab_pointer_cb), NULL);
g_signal_connect (actor, "button-release-event",
G_CALLBACK (red_release_cb), NULL);
actor = clutter_rectangle_new_with_color (&ycol);
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 100, 300);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (debug_event_cb), (char *) "yellow box");
g_signal_connect (actor, "button-press-event",
G_CALLBACK (toggle_grab_pointer_cb), NULL);
actor = clutter_rectangle_new_with_color (&bcol);
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 300, 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event",
G_CALLBACK (debug_event_cb), (char *) "blue box");
g_signal_connect (actor, "button-press-event",
G_CALLBACK (grab_pointer_cb), NULL);
g_signal_connect (actor, "button-release-event",
G_CALLBACK (blue_release_cb), NULL);
actor = clutter_rectangle_new_with_color (&gcol);
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 300, 300);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event",
G_CALLBACK (debug_event_cb), (char *) "green box");
g_signal_connect (actor, "button-press-event",
G_CALLBACK (green_press_cb), NULL);
actor = clutter_rectangle_new_with_color (&ccol);
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 500, 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event",
G_CALLBACK (debug_event_cb), (char *) "cyan box");
g_signal_connect (actor, "button-press-event",
G_CALLBACK (cyan_press_cb), NULL);
clutter_actor_show_all (CLUTTER_ACTOR (stage));
clutter_main();
return 0;
}
G_MODULE_EXPORT const char *
test_grab_describe (void)
{
return "Examples of using actor grabs";
}

View File

@ -0,0 +1,259 @@
#include <stdlib.h>
#include <gmodule.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.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)
{
SolidContent *self = (SolidContent *) content;
ClutterActorBox box, content_box;
ClutterColor 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 = self->alpha * 255;
color.red = self->red * 255;
color.green = self->green * 255;
color.blue = 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 = (1.0 - self->red) * 255;
color.green = (1.0 - self->green) * 255;
color.blue = (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.0;
box.y1 = clutter_actor_box_get_y (&content_box)
+ (clutter_actor_box_get_height (&content_box) - logical.height) / 2.0;
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;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
stage = clutter_stage_new ();
clutter_actor_set_name (stage, "Stage");
clutter_stage_set_title (CLUTTER_STAGE (stage), "Content");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_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_FLOW_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 ();
ClutterColor 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 = clutter_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_main ();
g_object_unref (color);
g_object_unref (image);
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,114 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
static const ClutterColor colors[] = {
{ 255, 0, 0, 255 },
{ 0, 255, 0, 255 },
{ 0, 0, 255, 255 },
};
#define PADDING (64.0f)
#define SIZE (64.0f)
const char *
test_keyframe_transition_describe (void);
int
test_keyframe_transition_main (int argc, char *argv[]);
static void
on_transition_stopped (ClutterActor *actor,
const gchar *transition_name,
gboolean is_finished)
{
g_print ("%s: transition stopped: %s (finished: %s)\n",
clutter_actor_get_name (actor),
transition_name,
is_finished ? "yes" : "no");
}
G_MODULE_EXPORT const char *
test_keyframe_transition_describe (void)
{
return "Demonstrate the keyframe transition.";
}
G_MODULE_EXPORT int
test_keyframe_transition_main (int argc, char *argv[])
{
ClutterActor *stage;
int i;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Keyframe Transitions");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
for (i = 0; i < 3; i++)
{
ClutterTransition *transition, *group;
ClutterActor *rect;
float cur_x, cur_y;
float new_x, new_y;
gchar *name;
cur_x = PADDING;
cur_y = PADDING + ((SIZE + PADDING) * i);
new_x = clutter_actor_get_width (stage) - PADDING - SIZE;
new_y = g_random_double_range (PADDING, clutter_actor_get_height (stage) - PADDING - SIZE);
name = g_strdup_printf ("rect%02d", i);
rect = clutter_actor_new ();
clutter_actor_set_name (rect, name);
clutter_actor_set_background_color (rect, &colors[i]);
clutter_actor_set_size (rect, SIZE, SIZE);
clutter_actor_set_position (rect, PADDING, cur_y);
clutter_actor_add_child (stage, rect);
group = clutter_transition_group_new ();
clutter_timeline_set_duration (CLUTTER_TIMELINE (group), 2000);
clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (group), 1);
clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (group), TRUE);
transition = clutter_keyframe_transition_new ("x");
clutter_transition_set_from (transition, G_TYPE_FLOAT, cur_x);
clutter_transition_set_to (transition, G_TYPE_FLOAT, new_x);
clutter_keyframe_transition_set (CLUTTER_KEYFRAME_TRANSITION (transition),
G_TYPE_FLOAT, 1,
0.5, new_x / 2.0f, CLUTTER_EASE_OUT_EXPO);
clutter_transition_group_add_transition (CLUTTER_TRANSITION_GROUP (group), transition);
g_object_unref (transition);
transition = clutter_keyframe_transition_new ("y");
clutter_transition_set_from (transition, G_TYPE_FLOAT, cur_y);
clutter_transition_set_to (transition, G_TYPE_FLOAT, cur_y);
clutter_keyframe_transition_set (CLUTTER_KEYFRAME_TRANSITION (transition),
G_TYPE_FLOAT, 1,
0.5, new_y, CLUTTER_EASE_OUT_EXPO);
clutter_transition_group_add_transition (CLUTTER_TRANSITION_GROUP (group), transition);
g_object_unref (transition);
clutter_actor_add_transition (rect, "rectAnimation", group);
g_signal_connect (rect, "transition-stopped",
G_CALLBACK (on_transition_stopped),
NULL);
g_object_unref (group);
g_free (name);
}
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,693 @@
#include <stdio.h>
#include <stdlib.h>
#include <gmodule.h>
#include <cogl/cogl.h>
#include <clutter/clutter.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 (min_right >= min_left);
g_assert (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 (min_bottom >= min_top);
g_assert (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,
ClutterAllocationFlags flags)
{
MyThingPrivate *priv;
gfloat current_x, current_y, max_row_height;
ClutterActorIter iter;
ClutterActor *child;
clutter_actor_set_allocation (self, box, flags);
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, flags);
/* 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))
{
ClutterVertex v1 = { 0, }, v2 = { 0, };
ClutterActorBox transformed_box = { 0, };
/* origin */
if (!(flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED))
{
v1.x = 0;
v1.y = 0;
}
else
{
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",
"Spacing",
"Spacing of the thing",
0, G_MAXFLOAT,
0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_PADDING,
g_param_spec_float ("padding",
"Padding",
"Padding around the thing",
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",
"Use Transformed Box",
"Use transformed box when allocating",
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,
"fixed::scale-gravity", CLUTTER_GRAVITY_CENTER,
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_main_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;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_actor_set_size (stage, 800, 600);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Layout");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
main_timeline = clutter_timeline_new (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_texture_new_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,
"fixed::scale-gravity", CLUTTER_GRAVITY_CENTER,
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_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

@ -0,0 +1,221 @@
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <gmodule.h>
#include "test-unit-names.h"
#define MAX_DESC_SIZE 72
static GModule *module = NULL;
static gpointer
get_symbol_with_suffix (const char *unit_name,
const char *suffix)
{
char *main_symbol_name;
gpointer func;
main_symbol_name = g_strconcat (unit_name, "_", suffix, NULL);
main_symbol_name = g_strdelimit (main_symbol_name, "-", '_');
g_module_symbol (module, main_symbol_name, &func);
g_free (main_symbol_name);
return func;
}
static gpointer
get_unit_name_main (const char *unit_name)
{
return get_symbol_with_suffix (unit_name, "main");
}
static char *
get_unit_name_description (const char *unit_name,
gssize max_len)
{
const char *description;
gpointer func;
char *retval;
func = get_symbol_with_suffix (unit_name, "describe");
if (func == NULL)
description = "No description found";
else
{
const char *(* unit_test_describe) (void);
unit_test_describe = func;
description = unit_test_describe ();
}
if (max_len > 0 && strlen (description) >= max_len)
{
GString *buf = g_string_sized_new (max_len);
char *newline;
newline = strchr (description, '\n');
if (newline != NULL)
{
g_string_append_len (buf, description,
MIN (newline - description - 1, max_len - 3));
}
else
g_string_append_len (buf, description, max_len - 3);
g_string_append (buf, "...");
retval = g_string_free (buf, FALSE);
}
else
retval = g_strdup (description);
return retval;
}
static gboolean list_all = FALSE;
static gboolean describe = FALSE;
static char **unit_names = NULL;
static GOptionEntry entries[] = {
{
"describe", 'd',
0,
G_OPTION_ARG_NONE, &describe,
"Describe the interactive unit test", NULL,
},
{
"list-all", 'l',
0,
G_OPTION_ARG_NONE, &list_all,
"List all available units", NULL,
},
{
G_OPTION_REMAINING, 0,
0,
G_OPTION_ARG_STRING_ARRAY, &unit_names,
"The interactive unit test", "UNIT_NAME"
},
{ NULL }
};
int
main (int argc, char **argv)
{
int ret, i, n_unit_names;
GOptionContext *context;
context = g_option_context_new (" - Interactive test suite");
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_help_enabled (context, TRUE);
g_option_context_set_ignore_unknown_options (context, TRUE);
if (!g_option_context_parse (context, &argc, &argv, NULL))
{
g_print ("Usage: test-interactive <unit_test>\n");
return EXIT_FAILURE;
}
g_option_context_free (context);
module = g_module_open (NULL, 0);
if (!module)
g_error ("*** Failed to open self for symbol lookup");
ret = EXIT_SUCCESS;
if (list_all)
{
g_print ("* Available unit tests:\n");
for (i = 0; i < G_N_ELEMENTS (test_unit_names); i++)
{
char *str;
gsize len;
len = MAX_DESC_SIZE - strlen (test_unit_names[i]);
str = get_unit_name_description (test_unit_names[i], len - 2);
g_print (" - %s:%*s%s\n",
test_unit_names[i],
(int) (len - strlen (str)), " ",
str);
g_free (str);
}
ret = EXIT_SUCCESS;
goto out;
}
if (unit_names != NULL)
n_unit_names = g_strv_length (unit_names);
else
{
g_print ("Usage: test-interactive <unit_test>\n");
ret = EXIT_FAILURE;
goto out;
}
for (i = 0; i < n_unit_names; i++)
{
const char *unit_name = unit_names[i];
char *unit_test = NULL;
gboolean found;
int j;
unit_test = g_path_get_basename (unit_name);
found = FALSE;
for (j = 0; j < G_N_ELEMENTS (test_unit_names); j++)
{
if (strcmp (test_unit_names[j], unit_test) == 0)
{
found = TRUE;
break;
}
}
if (!found)
g_error ("*** Unit '%s' does not exist", unit_test);
if (describe)
{
char *str;
str = get_unit_name_description (unit_test, -1);
g_print ("* %s:\n%s\n\n", unit_test, str);
g_free (str);
ret = EXIT_SUCCESS;
}
else
{
int (* unit_test_main) (int argc, char **argv);
gpointer func;
func = get_unit_name_main (unit_test);
if (func == NULL)
g_error ("*** Unable to find the main entry point for '%s'", unit_test);
unit_test_main = func;
ret = unit_test_main (n_unit_names, unit_names);
g_free (unit_test);
break;
}
g_free (unit_test);
}
out:
g_module_close (module);
return ret;
}

View File

@ -0,0 +1,376 @@
#include <gmodule.h>
#include <clutter/clutter.h>
#if defined (_MSC_VER) && !defined (_USE_MATH_DEFINES)
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#include <glib.h>
#ifdef CLUTTER_WINDOWING_X11
#include "clutter/x11/clutter-x11.h"
#endif
#define NHANDS 6
typedef struct SuperOH
{
ClutterActor **hand, *bgtex;
ClutterActor *real_hand;
ClutterActor *group;
ClutterActor *stage;
gint stage_width;
gint stage_height;
gfloat radius;
ClutterBehaviour *scaler_1;
ClutterBehaviour *scaler_2;
ClutterTimeline *timeline;
guint frame_id;
gboolean *paint_guards;
} SuperOH;
static gint n_hands = NHANDS;
static gint use_alpha = 255;
static GOptionEntry super_oh_entries[] = {
{
"num-hands", 'n',
0,
G_OPTION_ARG_INT, &n_hands,
"Number of hands", "HANDS"
},
{
"use-alpha", 'a',
0,
G_OPTION_ARG_INT, &use_alpha,
"Stage opacity", "VALUE"
},
{ NULL }
};
int
test_paint_wrapper_main (int argc, char *argv[]);
const char *
test_paint_wrapper_describe (void);
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 ***\n",
clutter_event_get_button (event),
x, y);
clutter_actor_hide (actor);
return TRUE;
}
static gboolean
input_cb (ClutterActor *stage,
ClutterEvent *event,
gpointer data)
{
SuperOH *oh = data;
if (event->type == 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_main_quit ();
return TRUE;
}
else if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_r)
{
gint i;
for (i = 0; i < n_hands; i++)
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 = clutter_timeline_get_progress (timeline) * 360.0f;
/* Rotate everything clockwise about stage center*/
clutter_actor_set_rotation (oh->group,
CLUTTER_Z_AXIS,
rotation,
oh->stage_width / 2,
oh->stage_height / 2,
0);
for (i = 0; i < n_hands; i++)
{
/* Rotate each hand around there centers - to get this we need
* to take into account any scaling.
*/
clutter_actor_set_rotation (oh->hand[i],
CLUTTER_Z_AXIS,
-6.0 * rotation,
0, 0, 0);
}
}
static gdouble
my_sine_wave (ClutterAlpha *alpha,
gpointer dummy G_GNUC_UNUSED)
{
ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
gdouble progress = clutter_timeline_get_progress (timeline);
return sin (progress * G_PI);
}
static void
hand_pre_paint (ClutterActor *actor,
gpointer user_data)
{
SuperOH *oh = user_data;
gfloat w, h;
int actor_num;
for (actor_num = 0; oh->hand[actor_num] != actor; actor_num++)
;
g_assert (oh->paint_guards[actor_num] == FALSE);
clutter_actor_get_size (actor, &w, &h);
cogl_set_source_color4ub (255, 0, 0, 128);
cogl_rectangle (0, 0, w / 2, h / 2);
oh->paint_guards[actor_num] = TRUE;
}
static void
hand_post_paint (ClutterActor *actor,
gpointer user_data)
{
SuperOH *oh = user_data;
gfloat w, h;
int actor_num;
for (actor_num = 0; oh->hand[actor_num] != actor; actor_num++)
;
g_assert (oh->paint_guards[actor_num] == TRUE);
clutter_actor_get_size (actor, &w, &h);
cogl_set_source_color4ub (0, 255, 0, 128);
cogl_rectangle (w / 2, h / 2, w, h);
oh->paint_guards[actor_num] = FALSE;
}
static void
stop_and_quit (ClutterActor *actor,
SuperOH *oh)
{
g_signal_handler_disconnect (oh->timeline, oh->frame_id);
clutter_timeline_stop (oh->timeline);
clutter_main_quit ();
}
G_MODULE_EXPORT int
test_paint_wrapper_main (int argc, char *argv[])
{
ClutterAlpha *alpha;
ClutterActor *stage;
ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff };
SuperOH *oh;
gint i;
GError *error;
ClutterActor *real_hand;
error = NULL;
#ifdef CLUTTER_WINDOWING_X11
clutter_x11_set_use_argb_visual (TRUE);
#endif
if (clutter_init_with_args (&argc, &argv,
NULL,
super_oh_entries,
NULL,
&error) != CLUTTER_INIT_SUCCESS)
{
g_warning ("Unable to initialise Clutter:\n%s",
error->message);
g_error_free (error);
return EXIT_FAILURE;
}
oh = g_new(SuperOH, 1);
stage = clutter_stage_new ();
clutter_actor_set_size (stage, 800, 600);
if (use_alpha != 255)
{
clutter_stage_set_use_alpha (CLUTTER_STAGE (stage), TRUE);
clutter_actor_set_opacity (stage, use_alpha);
}
clutter_stage_set_title (CLUTTER_STAGE (stage), "Paint Test");
clutter_actor_set_background_color (stage, &stage_color);
g_signal_connect (stage, "destroy", G_CALLBACK (stop_and_quit), oh);
oh->stage = stage;
/* Create a timeline to manage animation */
oh->timeline = clutter_timeline_new (6000);
clutter_timeline_set_repeat_count (oh->timeline, -1);
/* fire a callback for frame change */
oh->frame_id =
g_signal_connect (oh->timeline, "new-frame", G_CALLBACK (frame_cb), oh);
/* Set up some behaviours to handle scaling */
alpha = clutter_alpha_new_with_func (oh->timeline, my_sine_wave, NULL, NULL);
oh->scaler_1 = clutter_behaviour_scale_new (alpha, 0.5, 0.5, 1.0, 1.0);
oh->scaler_2 = clutter_behaviour_scale_new (alpha, 1.0, 1.0, 0.5, 0.5);
real_hand = clutter_texture_new_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",
&error);
if (real_hand == NULL)
{
g_error ("image load failed: %s", error->message);
return EXIT_FAILURE;
}
/* create a new group to hold multiple actors in a group */
oh->group = clutter_group_new();
oh->hand = g_new (ClutterActor*, n_hands);
oh->stage_width = clutter_actor_get_width (stage);
oh->stage_height = clutter_actor_get_height (stage);
oh->radius = (oh->stage_width + oh->stage_height)
/ n_hands;
for (i = 0; i < n_hands; i++)
{
gint x, y, w, h;
if (i == 0)
oh->hand[i] = real_hand;
else
oh->hand[i] = clutter_clone_new (real_hand);
clutter_actor_set_reactive (oh->hand[i], TRUE);
clutter_actor_set_size (oh->hand[i], 200, 213);
/* Place around a circle */
w = clutter_actor_get_width (oh->hand[i]);
h = clutter_actor_get_height (oh->hand[i]);
x = oh->stage_width / 2
+ oh->radius
* cos (i * G_PI / (n_hands / 2))
- w / 2;
y = oh->stage_height / 2
+ oh->radius
* sin (i * G_PI / (n_hands / 2))
- h / 2;
clutter_actor_set_position (oh->hand[i], x, y);
clutter_actor_move_anchor_point_from_gravity (oh->hand[i],
CLUTTER_GRAVITY_CENTER);
g_signal_connect (oh->hand[i], "button-press-event",
G_CALLBACK (on_button_press_event),
oh);
/* paint something before each hand */
g_signal_connect (oh->hand[i],
"paint", G_CALLBACK (hand_pre_paint),
oh);
/* paint something after each hand */
g_signal_connect_after (oh->hand[i],
"paint", G_CALLBACK (hand_post_paint),
oh);
/* Add to our group group */
clutter_container_add_actor (CLUTTER_CONTAINER (oh->group), oh->hand[i]);
if (i % 2)
clutter_behaviour_apply (oh->scaler_1, oh->hand[i]);
else
clutter_behaviour_apply (oh->scaler_2, oh->hand[i]);
}
oh->paint_guards = g_malloc0 (sizeof (gboolean) * n_hands);
/* Add the group to the stage */
clutter_container_add_actor (CLUTTER_CONTAINER (stage),
CLUTTER_ACTOR (oh->group));
/* Show everying ( and map window ) */
clutter_actor_show (stage);
g_signal_connect (stage, "key-release-event",
G_CALLBACK (input_cb),
oh);
/* and start it */
clutter_timeline_start (oh->timeline);
clutter_main ();
g_object_unref (oh->scaler_1);
g_object_unref (oh->scaler_2);
g_object_unref (oh->timeline);
g_free (oh->paint_guards);
g_free (oh->hand);
g_free (oh);
return 0;
}
G_MODULE_EXPORT const char *
test_paint_wrapper_describe (void)
{
return "Wrap an actor's paint cycle for pre and post processing.";
}

View File

@ -0,0 +1,137 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#define PATH_DESCRIPTION \
"M 0, 0 " \
"L 0, 300 " \
"L 300, 300 " \
"L 300, 0 " \
"L 0, 0"
static gboolean toggled = FALSE;
int
test_path_constraint_main (int argc,
char *argv[]);
static gboolean
on_button_press (ClutterActor *actor,
const ClutterEvent *event,
gpointer dummy G_GNUC_UNUSED)
{
if (!toggled)
clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 500,
"@constraints.path.offset", 1.0,
NULL);
else
clutter_actor_animate (actor, CLUTTER_EASE_OUT_CUBIC, 500,
"@constraints.path.offset", 0.0,
NULL);
toggled = !toggled;
return TRUE;
}
static gchar *
node_to_string (const ClutterPathNode *node)
{
GString *buffer = g_string_sized_new (256);
gsize len = 0, i;
switch (node->type)
{
case CLUTTER_PATH_MOVE_TO:
g_string_append (buffer, "move-to ");
len = 1;
break;
case CLUTTER_PATH_LINE_TO:
g_string_append (buffer, "line-to ");
len = 1;
break;
case CLUTTER_PATH_CURVE_TO:
g_string_append (buffer, "curve-to ");
len = 3;
break;
case CLUTTER_PATH_CLOSE:
g_string_append (buffer, "close");
len = 0;
break;
default:
break;
}
for (i = 0; i < len; i++)
{
if (i == 0)
g_string_append (buffer, "[ ");
g_string_append_printf (buffer, "[ %d, %d ]",
node->points[i].x,
node->points[i].y);
if (i == len - 1)
g_string_append (buffer, " ]");
}
return g_string_free (buffer, FALSE);
}
static void
on_node_reached (ClutterPathConstraint *constraint,
ClutterActor *actor,
guint index_)
{
ClutterPath *path = clutter_path_constraint_get_path (constraint);
ClutterPathNode node;
gchar *str;
clutter_path_get_node (path, index_, &node);
str = node_to_string (&node);
g_print ("Node %d reached: %s\n", index_, str);
g_free (str);
}
G_MODULE_EXPORT int
test_path_constraint_main (int argc,
char *argv[])
{
ClutterActor *stage, *rect;
ClutterPath *path;
ClutterColor rect_color = { 0xcc, 0x00, 0x00, 0xff };
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Path Constraint");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
path = clutter_path_new ();
clutter_path_set_description (path, PATH_DESCRIPTION);
rect = clutter_rectangle_new ();
clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color);
clutter_actor_set_size (rect, 128, 128);
clutter_actor_set_reactive (rect, TRUE);
clutter_actor_add_constraint_with_name (rect, "path", clutter_path_constraint_new (path, 0.0));
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
g_signal_connect (rect, "button-press-event", G_CALLBACK (on_button_press), NULL);
g_signal_connect (clutter_actor_get_constraint (rect, "path"),
"node-reached",
G_CALLBACK (on_node_reached),
NULL);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,99 @@
/*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#include <stdlib.h>
#include <math.h>
#include <cairo.h>
#include <glib.h>
#include <clutter/clutter.h>
#include <gdk-pixbuf/gdk-pixbuf.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 */
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
/* create a resizable stage */
stage = clutter_stage_new ();
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
clutter_stage_set_title (CLUTTER_STAGE (stage), "Rotate and Zoom actions");
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_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

@ -0,0 +1,125 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
static const ClutterGravity gravities[] = {
CLUTTER_GRAVITY_NORTH_EAST,
CLUTTER_GRAVITY_NORTH,
CLUTTER_GRAVITY_NORTH_WEST,
CLUTTER_GRAVITY_WEST,
CLUTTER_GRAVITY_SOUTH_WEST,
CLUTTER_GRAVITY_SOUTH,
CLUTTER_GRAVITY_SOUTH_EAST,
CLUTTER_GRAVITY_EAST,
CLUTTER_GRAVITY_CENTER,
CLUTTER_GRAVITY_NONE
};
static gint gindex = 0;
static ClutterActor *label;
int
test_scale_main (int argc, char *argv[]);
const char *
test_scale_describe (void);
static void
set_next_gravity (ClutterActor *actor)
{
ClutterGravity gravity = gravities[gindex];
GEnumClass *eclass;
GEnumValue *evalue;
clutter_actor_move_anchor_point_from_gravity (actor, gravities[gindex]);
eclass = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
evalue = g_enum_get_value (eclass, gravity);
clutter_text_set_text (CLUTTER_TEXT (label), evalue->value_nick);
g_type_class_unref (eclass);
if (++gindex >= G_N_ELEMENTS (gravities))
gindex = 0;
}
static gdouble
my_ramp_func (ClutterAlpha *alpha,
gpointer unused)
{
ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
return clutter_timeline_get_progress (timeline);
}
G_MODULE_EXPORT int
test_scale_main (int argc, char *argv[])
{
ClutterActor *stage, *rect;
ClutterColor rect_color = { 0xff, 0xff, 0xff, 0x99 };
ClutterTimeline *timeline;
ClutterAlpha *alpha;
ClutterBehaviour *behave;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Scaling");
clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black);
clutter_actor_set_size (stage, 300, 300);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
rect = clutter_rectangle_new_with_color (&rect_color);
clutter_actor_set_size (rect, 100, 100);
clutter_actor_set_position (rect, 100, 100);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
label = clutter_text_new_with_text ("Sans 20px", "");
clutter_text_set_color (CLUTTER_TEXT (label), CLUTTER_COLOR_White);
clutter_actor_set_position (label,
clutter_actor_get_x (rect),
clutter_actor_get_y (rect)
+ clutter_actor_get_height (rect));
clutter_container_add_actor (CLUTTER_CONTAINER (stage), label);
rect_color.alpha = 0xff;
rect = clutter_rectangle_new_with_color (&rect_color);
clutter_actor_set_position (rect, 100, 100);
clutter_actor_set_size (rect, 100, 100);
set_next_gravity (rect);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
timeline = clutter_timeline_new (750);
alpha = clutter_alpha_new_with_func (timeline,
my_ramp_func,
NULL, NULL);
behave = clutter_behaviour_scale_new (alpha,
0.0, 0.0, /* scale start */
1.0, 1.0); /* scale end */
clutter_behaviour_apply (behave, rect);
clutter_timeline_set_repeat_count (timeline, -1);
g_signal_connect_swapped (timeline, "completed",
G_CALLBACK (set_next_gravity), rect);
clutter_timeline_start (timeline);
clutter_actor_show_all (stage);
clutter_main();
g_object_unref (timeline);
g_object_unref (behave);
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_scale_describe (void)
{
return "Scaling animation and scaling center changes";
}

View File

@ -0,0 +1,68 @@
[
{
"id" : "button",
"type" : "ClutterRectangle",
"width" : "16 em",
"height" : "6 em",
"color" : "rgb(255, 0, 0)",
"opacity" : 128,
"scale-gravity" : "center",
"reactive" : true,
"signals" : [
{
"name" : "button-press-event",
"handler" : "on_button_press"
},
{ "name" : "enter-event", "states" : "button-states", "target-state" : "hover" },
{ "name" : "leave-event", "states" : "button-states", "target-state" : "base" },
{ "name" : "button-press-event", "states" : "button-states", "target-state" : "active" },
{ "name" : "button-release-event", "states" : "button-states", "target-state" : "hover" }
]
},
{
"id" : "button-states",
"type" : "ClutterState",
"duration" : 250,
"transitions" : [
{
"source" : null,
"target" : "base",
"keys" : [
[ "button", "opacity", "linear", 128 ],
[ "button", "scale-x", "ease-in-cubic", 1.0 ],
[ "button", "scale-y", "ease-in-cubic", 1.0 ],
[ "button", "color", "linear", "rgb(255, 0, 0)" ]
]
},
{
"source" : null,
"target" : "hover",
"keys" : [
[ "button", "opacity", "linear", 255 ],
[ "button", "scale-x", "ease-out-bounce", 1.4 ],
[ "button", "scale-y", "ease-out-bounce", 1.4 ],
[ "button", "color", "linear", "rgb(0, 255, 0)" ]
]
},
{
"source" : null,
"target" : "active",
"keys" : [
[ "button", "opacity", "linear", 255 ],
[ "button", "color", "linear", "rgb(0, 0, 255)" ]
]
}
]
}
]

View File

@ -0,0 +1,188 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <glib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
static ClutterScript *script = NULL;
static guint merge_id = 0;
int
test_script_main (int argc, char *argv[]);
static const gchar *test_unmerge =
"["
" {"
" \"id\" : \"main-stage\","
" \"type\" : \"ClutterStage\","
" \"children\" : [ \"blue-button\" ]"
" },"
" {"
" \"id\" : \"blue-button\","
" \"type\" : \"ClutterRectangle\","
" \"color\" : \"#0000ffff\","
" \"x\" : 350,"
" \"y\" : 50,"
" \"width\" : 100,"
" \"height\" : 100,"
" \"visible\" : true,"
" \"reactive\" : true"
" }"
"]";
static const gchar *test_behaviour =
"["
" {"
" \"id\" : \"main-timeline\","
" \"type\" : \"ClutterTimeline\","
" \"duration\" : 5000,"
" \"loop\" : true"
" },"
" {"
" \"id\" : \"sine-alpha\","
" \"type\" : \"ClutterAlpha\","
" \"function\" : \"sine_alpha\","
" \"timeline\" : \"main-timeline\""
" },"
" {"
" \"id\" : \"path-behaviour\","
" \"type\" : \"ClutterBehaviourPath\","
" \"path\" : \"M 50 50 L 100 100\","
" \"alpha\" : {"
" \"timeline\" : \"main-timeline\","
" \"function\" : \"double_ramp_alpha\""
" }"
" },"
" {"
" \"id\" : \"rotate-behaviour\","
" \"type\" : \"ClutterBehaviourRotate\","
" \"angle-start\" : 0.0,"
" \"angle-end\" : 360.0,"
" \"axis\" : \"y-axis\","
" \"alpha\" : \"sine-alpha\""
" },"
" {"
" \"id\" : \"fade-behaviour\","
" \"type\" : \"ClutterBehaviourOpacity\","
" \"opacity-start\" : 255,"
" \"opacity-end\" : 0,"
" \"alpha\" : {"
" \"id\" : \"fade-alpha\","
" \"type\" : \"ClutterAlpha\","
" \"timeline\" : \"main-timeline\","
" \"mode\" : \"linear\""
" }"
" }"
"]";
static gboolean
blue_button_press (ClutterActor *actor,
ClutterButtonEvent *event,
gpointer data)
{
g_print ("[*] Pressed '%s'\n", clutter_get_script_id (G_OBJECT (actor)));
g_print ("[*] Unmerging objects with merge id: %d\n", merge_id);
clutter_script_unmerge_objects (script, merge_id);
return TRUE;
}
static gboolean
red_button_press (ClutterActor *actor,
ClutterButtonEvent *event,
gpointer data)
{
GObject *timeline;
g_print ("[*] Pressed '%s'\n", clutter_get_script_id (G_OBJECT (actor)));
timeline = clutter_script_get_object (script, "main-timeline");
g_assert (CLUTTER_IS_TIMELINE (timeline));
if (!clutter_timeline_is_playing (CLUTTER_TIMELINE (timeline)))
clutter_timeline_start (CLUTTER_TIMELINE (timeline));
else
clutter_timeline_pause (CLUTTER_TIMELINE (timeline));
return TRUE;
}
G_MODULE_EXPORT int
test_script_main (int argc, char *argv[])
{
GObject *stage, *blue_button, *red_button;
GError *error = NULL;
gchar *file;
gint res;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
script = clutter_script_new ();
g_assert (CLUTTER_IS_SCRIPT (script));
clutter_script_load_from_data (script, test_behaviour, -1, &error);
if (error)
{
g_print ("*** Error:\n"
"*** %s\n", error->message);
g_error_free (error);
g_object_unref (script);
return EXIT_FAILURE;
}
file = g_build_filename (TESTS_DATADIR, "test-script.json", NULL);
clutter_script_load_from_file (script, file, &error);
if (error)
{
g_print ("*** Error:\n"
"*** %s\n", error->message);
g_error_free (error);
g_object_unref (script);
g_free (file);
return EXIT_FAILURE;
}
g_free (file);
merge_id = clutter_script_load_from_data (script, test_unmerge, -1, &error);
if (error)
{
g_print ("*** Error:\n"
"*** %s\n", error->message);
g_error_free (error);
g_object_unref (script);
return EXIT_FAILURE;
}
clutter_script_connect_signals (script, NULL);
res = clutter_script_get_objects (script,
"main-stage", &stage,
"red-button", &red_button,
"blue-button", &blue_button,
NULL);
g_assert (res == 3);
clutter_actor_show (CLUTTER_ACTOR (stage));
g_signal_connect (red_button,
"button-press-event",
G_CALLBACK (red_button_press),
NULL);
g_signal_connect (blue_button,
"button-press-event",
G_CALLBACK (blue_button_press),
NULL);
clutter_main ();
g_object_unref (script);
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,74 @@
{
"My Scene" : {
"id" : "main-stage",
"type" : "ClutterStage",
"title" : { "translatable" : true, "string" : "ClutterScript test" },
"color" : "white",
"signals" : [
{ "name" : "key-press-event", "handler" : "clutter_main_quit" },
{ "name" : "destroy", "handler" : "clutter_main_quit" }
],
"children" : [
{
"id" : "red-button",
"type" : "ClutterRectangle",
"color" : "#ff0000ff",
"x" : 50, "y" : 50, "width" : 100, "height" : 100,
"reactive" : true,
"rotation" : [
{ "z-axis" : [ 45.0, [ 75, 75 ] ] }
],
"behaviours" : [ "fade-behaviour", "path-behaviour" ]
},
{
"id" : "green-button",
"type" : "ClutterRectangle",
"color" : "#00ff00ff",
"border-width" : 5,
"border-color" : "#00cc00ff",
"position" : [ 200.0, 50.0 ],
"size" : { "width" : 100.0, "height" : 100.0 },
"depth" : -200.0,
"reactive" : true,
"signals" : [
{ "name" : "button-press-event", "handler" : "clutter_main_quit" }
]
},
{
"id" : "red-hand",
"type" : "ClutterTexture",
"filename" : "redhand.png",
"position" : { "x" : 100.0, "y" : 100.0 },
"width" : "20 mm",
"keep-aspect-ratio" : true,
"anchor-x" : "5 em",
"anchor-y" : "5 pt",
"opacity" : 100,
"behaviours" : [ "rotate-behaviour", "fade-behaviour" ]
},
{
"id" : "red-hand-clone",
"type" : "ClutterClone",
"source" : "red-hand",
"position" : [ 250.0, 150.0 ],
"opacity" : 100
},
{
"id" : "label",
"type" : "ClutterText",
"x" : 50,
"y" : 200,
"text" : { "translatable" : true, "string" : "Clutter Script" },
"font-name" : "Sans 24px",
"color" : "black",
"line-alignment" : "center",
"line-wrap" : false,
"ellipsize" : "none",
"rotation" : [
{ "y-axis" : [ 60.0, [ 275, 100 ] ] },
{ "z-axis" : [ 45.0, [ 75, 75 ] ] }
]
}
]
}
}

View File

@ -0,0 +1,137 @@
#include <stdlib.h>
#include <math.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#define RECT_WIDTH 400
#define RECT_HEIGHT 300
#define N_RECTS 7
static const gchar *rect_color[N_RECTS] = {
"#edd400",
"#f57900",
"#c17d11",
"#73d216",
"#3465a4",
"#75507b",
"#cc0000"
};
static ClutterActor *rectangle[N_RECTS];
static ClutterActor *viewport = NULL;
int
test_scrolling_main (int argc, char *argv[]);
static void
on_drag_end (ClutterDragAction *action,
ClutterActor *actor,
gfloat event_x,
gfloat event_y,
ClutterModifierType modifiers)
{
gfloat viewport_x = clutter_actor_get_x (viewport);
gfloat offset_x;
gint child_visible;
/* check if we're at the viewport edges */
if (viewport_x > 0)
{
clutter_actor_save_easing_state (viewport);
clutter_actor_set_easing_mode (viewport, CLUTTER_EASE_OUT_BOUNCE);
clutter_actor_set_x (viewport, 0);
clutter_actor_restore_easing_state (viewport);
return;
}
if (viewport_x < (-1.0f * (RECT_WIDTH * (N_RECTS - 1))))
{
clutter_actor_save_easing_state (viewport);
clutter_actor_set_easing_mode (viewport, CLUTTER_EASE_OUT_BOUNCE);
clutter_actor_set_x (viewport, -1.0f * (RECT_WIDTH * (N_RECTS - 1)));
clutter_actor_restore_easing_state (viewport);
return;
}
/* animate the viewport to fully show the child once we pass
* a certain threshold with the dragging action
*/
offset_x = fabsf (viewport_x) / RECT_WIDTH + 0.5f;
if (offset_x > (RECT_WIDTH * 0.33))
child_visible = (int) offset_x + 1;
else
child_visible = (int) offset_x;
/* sanity check on the children number */
child_visible = CLAMP (child_visible, 0, N_RECTS);
clutter_actor_save_easing_state (viewport);
clutter_actor_set_x (viewport, -1.0f * RECT_WIDTH * child_visible);
clutter_actor_restore_easing_state (viewport);
}
G_MODULE_EXPORT int
test_scrolling_main (int argc, char *argv[])
{
ClutterActor *stage;
ClutterActor *scroll;
ClutterAction *action;
gint i;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Scrolling");
clutter_actor_set_size (stage, 800, 600);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* scroll: the group that contains the scrolling viewport; we set its
* size to be the same as one rectangle, position it in the middle of
* the stage and set it to clip its contents to the allocated size
*/
scroll = clutter_actor_new ();
clutter_actor_add_child (stage, scroll);
clutter_actor_set_size (scroll, RECT_WIDTH, RECT_HEIGHT);
clutter_actor_add_constraint (scroll, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5));
clutter_actor_set_clip_to_allocation (scroll, TRUE);
/* viewport: the actual container for the children; we scroll it using
* the Drag action constrained to the horizontal axis, and every time
* the dragging ends we check whether we're dragging past the end of
* the viewport
*/
viewport = clutter_actor_new ();
clutter_actor_set_layout_manager (viewport, clutter_box_layout_new ());
clutter_actor_add_child (scroll, viewport);
/* add dragging capabilities to the viewport; the heavy lifting is
* all done by the DragAction itself, plus the ::drag-end signal
* handler in our code
*/
action = clutter_drag_action_new ();
clutter_actor_add_action (viewport, action);
clutter_drag_action_set_drag_axis (CLUTTER_DRAG_ACTION (action),
CLUTTER_DRAG_X_AXIS);
g_signal_connect (action, "drag-end", G_CALLBACK (on_drag_end), NULL);
clutter_actor_set_reactive (viewport, TRUE);
/* children of the viewport */
for (i = 0; i < N_RECTS; i++)
{
ClutterColor color;
clutter_color_from_string (&color, rect_color[i]);
rectangle[i] = clutter_actor_new ();
clutter_actor_set_background_color (rectangle[i], &color);
clutter_actor_add_child (viewport, rectangle[i]);
clutter_actor_set_size (rectangle[i], RECT_WIDTH, RECT_HEIGHT);
}
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,86 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <gmodule.h>
#include <clutter/clutter.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;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
/* Make a timeline */
timeline = clutter_timeline_new (7692);
clutter_timeline_set_repeat_count (timeline, -1);
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Rotations");
clutter_actor_set_background_color (stage, CLUTTER_COLOR_Aluminium3);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* Make a hand */
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
hand = clutter_texture_new_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_rectangle_new_with_color (CLUTTER_COLOR_DarkOrange);
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_container_add (CLUTTER_CONTAINER (stage), rect, hand, label, NULL);
/* start the timeline and thus the animations */
clutter_timeline_start (timeline);
clutter_actor_show_all (stage);
clutter_main();
g_object_unref (timeline);
return 0;
}

View File

@ -0,0 +1,174 @@
#include <gmodule.h>
#include <clutter/clutter.h>
#include <string.h>
#define DOT_SIZE 2
#define TEX_SIZE 64
typedef struct _CallbackData CallbackData;
struct _CallbackData
{
ClutterActor *stage;
ClutterActor *tex;
ClutterActor *box;
ClutterMotionEvent event;
guint idle_source;
};
int
test_stage_read_pixels_main (int argc, char **argv);
const char *
test_stage_read_pixels_describe (void);
static ClutterActor *
make_label (void)
{
ClutterActor *label;
gchar *text;
const char *argv[] = { "ls", "--help", NULL };
label = clutter_text_new ();
clutter_text_set_font_name (CLUTTER_TEXT (label), "Sans 10");
if (g_spawn_sync (NULL, (char **) argv, NULL,
G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH,
NULL, NULL, &text, NULL, NULL, NULL))
{
clutter_text_set_text (CLUTTER_TEXT (label), text);
g_free (text);
}
return label;
}
static ClutterActor *
make_tex (void)
{
ClutterActor *tex = clutter_texture_new ();
clutter_actor_set_size (tex, TEX_SIZE * 2, TEX_SIZE * 2);
return tex;
}
static ClutterActor *
make_box (void)
{
ClutterActor *box;
static const ClutterColor blue = { 0x00, 0x00, 0xff, 0xff };
box = clutter_rectangle_new_with_color (&blue);
clutter_actor_set_size (box, DOT_SIZE + 2, DOT_SIZE + 2);
clutter_actor_hide (box);
return box;
}
static gboolean
on_motion_idle (gpointer user_data)
{
CallbackData *data = (CallbackData *) user_data;
guchar *pixels, *p;
gfloat stage_width, stage_height;
gint x, y;
data->idle_source = 0;
clutter_actor_get_size (data->stage, &stage_width, &stage_height);
x = CLAMP (data->event.x - TEX_SIZE / 2, 0, stage_width - TEX_SIZE);
y = CLAMP (data->event.y - TEX_SIZE / 2, 0, stage_height - TEX_SIZE);
clutter_actor_set_position (data->box,
x + TEX_SIZE / 2 - 1,
y + TEX_SIZE / 2 - 1);
clutter_actor_show (data->box);
/* Redraw so that the layouting will be done and the box will be
drawn in the right position */
clutter_stage_ensure_redraw (CLUTTER_STAGE (data->stage));
pixels = clutter_stage_read_pixels (CLUTTER_STAGE (data->stage),
x, y,
TEX_SIZE, TEX_SIZE);
/* Make a red dot in the center */
p = pixels + (TEX_SIZE / 2 - DOT_SIZE / 2) * TEX_SIZE * 4
+ (TEX_SIZE / 2 - DOT_SIZE / 2) * 4;
for (y = 0; y < DOT_SIZE; y++)
{
for (x = 0; x < DOT_SIZE; x++)
{
*(p++) = 255;
memset (p, 0, 3);
p += 3;
}
p += TEX_SIZE * 4 - DOT_SIZE * 4;
}
/* Set all of the alpa values to full */
for (p = pixels + TEX_SIZE * TEX_SIZE * 4; p > pixels; p -= 4)
*(p - 1) = 255;
clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (data->tex),
pixels, TRUE,
TEX_SIZE, TEX_SIZE,
TEX_SIZE * 4, 4, 0, NULL);
g_free (pixels);
return FALSE;
}
static gboolean
on_motion (ClutterActor *stage, ClutterMotionEvent *event, CallbackData *data)
{
/* Handle the motion event in an idle handler so that multiple
events will be combined into one */
if (data->idle_source == 0)
data->idle_source = clutter_threads_add_idle (on_motion_idle, data);
data->event = *event;
return FALSE;
}
G_MODULE_EXPORT int
test_stage_read_pixels_main (int argc, char **argv)
{
CallbackData data;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
data.idle_source = 0;
data.stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (data.stage), "Read Pixels");
g_signal_connect (data.stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
data.tex = make_tex ();
data.box = make_box ();
clutter_actor_set_position (data.tex,
clutter_actor_get_width (data.stage)
- clutter_actor_get_width (data.tex),
clutter_actor_get_height (data.stage)
- clutter_actor_get_height (data.tex));
clutter_container_add (CLUTTER_CONTAINER (data.stage),
make_label (), data.tex, data.box, NULL);
g_signal_connect (data.stage, "motion-event", G_CALLBACK (on_motion), &data);
clutter_actor_show (data.stage);
clutter_main ();
return 0;
}
G_MODULE_EXPORT const char *
test_stage_read_pixels_describe (void)
{
return "Read back pixels from a Stage.";
}

View File

@ -0,0 +1,88 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
int
test_stage_sizing_main (int argc, char *argv[]);
const char *
test_stage_sizing_describe (void);
static gboolean
shrink_clicked_cb (ClutterActor *stage)
{
gfloat width, height;
clutter_actor_get_size (stage, &width, &height);
clutter_actor_set_size (stage, MAX (0, width - 10.f), MAX (0, height - 10.f));
return CLUTTER_EVENT_STOP;
}
static gboolean
expand_clicked_cb (ClutterActor *stage)
{
gfloat width, height;
clutter_actor_get_size (stage, &width, &height);
clutter_actor_set_size (stage, width + 10.f, height + 10.f);
return CLUTTER_EVENT_STOP;
}
G_MODULE_EXPORT int
test_stage_sizing_main (int argc, char *argv[])
{
ClutterActor *stage, *rect, *label, *box;
ClutterMargin margin = { 12.f, 12.f, 6.f, 6.f };
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Stage Sizing");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
box = clutter_actor_new ();
clutter_actor_set_layout_manager (box, clutter_box_layout_new ());
clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5));
clutter_actor_add_child (stage, box);
rect = clutter_actor_new ();
clutter_actor_set_layout_manager (rect,
clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER));
clutter_actor_set_background_color (rect, CLUTTER_COLOR_SkyBlue);
clutter_actor_set_reactive (rect, TRUE);
g_signal_connect_swapped (rect, "button-press-event",
G_CALLBACK (shrink_clicked_cb), stage);
label = clutter_text_new_with_text ("Sans 16", "Shrink");
clutter_actor_set_margin (label, &margin);
clutter_actor_add_child (rect, label);
clutter_actor_add_child (box, rect);
rect = clutter_actor_new ();
clutter_actor_set_layout_manager (rect,
clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER));
clutter_actor_set_background_color (rect, CLUTTER_COLOR_Butter);
clutter_actor_set_reactive (rect, TRUE);
g_signal_connect_swapped (rect, "button-press-event",
G_CALLBACK (expand_clicked_cb), stage);
label = clutter_text_new_with_text ("Sans 16", "Expand");
clutter_actor_set_margin (label, &margin);
clutter_actor_add_child (rect, label);
clutter_actor_add_child (box, rect);
clutter_stage_set_minimum_size (CLUTTER_STAGE (stage),
clutter_actor_get_width (box),
clutter_actor_get_height (box));
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_stage_sizing_describe (void)
{
return "Check stage sizing policies.";
}

View File

@ -0,0 +1,45 @@
#include <stdlib.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#define TEST_STATE_SCRIPT_FILE "test-script-signals.json"
int
test_state_script_main (int argc, char *argv[]);
G_MODULE_EXPORT int
test_state_script_main (int argc, char *argv[])
{
ClutterActor *stage, *button;
ClutterScript *script;
GError *error = NULL;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
script = clutter_script_new ();
clutter_script_load_from_file (script, TEST_STATE_SCRIPT_FILE, &error);
if (error != NULL)
g_error ("Unable to load '%s': %s\n",
TEST_STATE_SCRIPT_FILE,
error->message);
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "State Script");
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
clutter_actor_show (stage);
button = CLUTTER_ACTOR (clutter_script_get_object (script, "button"));
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
clutter_actor_add_constraint (button, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5));
clutter_script_connect_signals (script, NULL);
clutter_main ();
g_object_unref (script);
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,212 @@
#include <stdlib.h>
#include <math.h>
#include <gmodule.h>
#include <clutter/clutter.h>
#define STAGE_WIDTH 1024
#define STAGE_HEIGHT 768
#define ACTOR_WIDTH 128
#define ACTOR_HEIGHT 128
#define COLS (STAGE_WIDTH/ACTOR_WIDTH)
#define ROWS (STAGE_HEIGHT/ACTOR_HEIGHT)
#define TOTAL (ROWS*COLS)
gint
test_state_main (gint argc,
gchar **argv);
const char *
test_state_describe (void);
static gboolean press_event (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
ClutterState *state = CLUTTER_STATE (user_data);
clutter_state_set_state (state, "right");
return TRUE;
}
static gboolean release_event (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
ClutterState *state = CLUTTER_STATE (user_data);
clutter_state_set_state (state, "active");
return TRUE;
}
static gboolean enter_event (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
ClutterState *state = CLUTTER_STATE (user_data);
clutter_state_set_state (state, "hover");
return TRUE;
}
static gboolean leave_event (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
ClutterState *state = CLUTTER_STATE (user_data);
clutter_state_set_state (state, "normal");
return TRUE;
}
static void completed (ClutterState *state,
gpointer data)
{
g_print ("Completed transitioning to state: %s\n",
clutter_state_get_state (state));
if (g_str_equal (clutter_state_get_state (state), "right"))
{
/* skip straight to left state when reaching right */
clutter_state_warp_to_state (state, "left");
}
}
static ClutterActor *new_rect (gint r,
gint g,
gint b,
gint a)
{
GError *error = NULL;
ClutterColor *color = clutter_color_new (r, g, b, a);
ClutterActor *group = clutter_actor_new ();
ClutterActor *rectangle = clutter_actor_new ();
ClutterActor *hand = NULL;
gchar *file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
hand = clutter_texture_new_from_file (file, &error);
if (rectangle == NULL)
g_error ("image load failed: %s", error->message);
g_free (file);
clutter_actor_set_size (hand, ACTOR_WIDTH,ACTOR_HEIGHT);
clutter_actor_set_background_color (rectangle, color);
clutter_actor_set_size (rectangle, ACTOR_WIDTH,ACTOR_HEIGHT);
clutter_color_free (color);
clutter_actor_add_child (group, rectangle);
clutter_actor_add_child (group, hand);
return group;
}
G_MODULE_EXPORT gint
test_state_main (gint argc,
gchar **argv)
{
ClutterActor *stage;
ClutterState *layout_state;
gint i;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
layout_state = clutter_state_new ();
stage = clutter_stage_new ();
clutter_actor_set_background_color (stage, CLUTTER_COLOR_Black);
clutter_stage_set_title (CLUTTER_STAGE (stage), "State Machine");
clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
g_signal_connect (stage, "button-press-event",
G_CALLBACK (press_event), layout_state);
g_signal_connect (stage, "button-release-event",
G_CALLBACK (release_event), layout_state);
for (i = 0; i < TOTAL; i++)
{
ClutterActor *actor;
ClutterState *a_state;
int row = i/COLS;
int col = i%COLS;
actor = new_rect (255 * (1.0 * col / COLS), 50,
255 * (1.0 * row / ROWS), 255);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
clutter_actor_set_position (actor, 320.0, 240.0);
clutter_actor_set_reactive (actor, TRUE);
clutter_actor_add_effect_with_name (actor, "fade",
clutter_desaturate_effect_new (0.0));
clutter_state_set (layout_state, NULL, "active",
actor, "delayed::x", CLUTTER_LINEAR,
ACTOR_WIDTH * 1.0 * ((TOTAL-1-i) % COLS),
((row*1.0/ROWS))/2, (1.0-(row*1.0/ROWS))/2,
actor, "delayed::y", CLUTTER_LINEAR,
ACTOR_HEIGHT * 1.0 * ((TOTAL-1-i) / COLS),
((row*1.0/ROWS))/2, 0.0,
actor, "rotation-angle-x", CLUTTER_LINEAR, 0.0,
actor, "rotation-angle-y", CLUTTER_LINEAR, 0.0,
NULL);
clutter_state_set (layout_state, NULL, "right",
actor, "delayed::x", CLUTTER_LINEAR, STAGE_WIDTH * 1.0,
((row*1.0/ROWS))/2,
(1.0-(row*1.0/ROWS))/2,
actor, "delayed::y", CLUTTER_LINEAR, STAGE_HEIGHT * 1.0,
((row*1.0/ROWS))/2,
0.0,
NULL);
clutter_state_set (layout_state, NULL, "left",
actor, "rotation-angle-x", CLUTTER_LINEAR, 45.0,
actor, "rotation-angle-y", CLUTTER_LINEAR, 5.0,
actor, "x", CLUTTER_LINEAR, 0-64.0,
actor, "y", CLUTTER_LINEAR, 0-64.0,
NULL);
a_state = clutter_state_new ();
g_object_set_data_full (G_OBJECT (actor), "hover-state-machine",
a_state, g_object_unref);
g_signal_connect (actor, "enter-event",
G_CALLBACK (enter_event), a_state);
g_signal_connect (actor, "leave-event",
G_CALLBACK (leave_event), a_state);
clutter_state_set (a_state, NULL, "normal",
actor, "opacity", CLUTTER_LINEAR, 0x77,
actor, "rotation-angle-z", CLUTTER_LINEAR, 0.0,
actor, "@effects.fade.factor", CLUTTER_LINEAR, 0.0,
NULL);
clutter_state_set (a_state, NULL, "hover",
actor, "opacity", CLUTTER_LINEAR, 0xff,
actor, "rotation-angle-z", CLUTTER_LINEAR, 10.0,
actor, "@effects.fade.factor", CLUTTER_LINEAR, 1.0,
NULL);
clutter_actor_set_opacity (actor, 0x77);
clutter_state_set_duration (a_state, NULL, NULL, 500);
}
clutter_state_set_duration (layout_state, NULL, NULL, 1000);
clutter_state_set_duration (layout_state, "active", "left", 1400);
g_signal_connect (layout_state, "completed", G_CALLBACK (completed), NULL);
clutter_actor_show (stage);
clutter_state_warp_to_state (layout_state, "left");
clutter_state_set_state (layout_state, "active");
clutter_main ();
g_object_unref (layout_state);
return EXIT_SUCCESS;
}
G_MODULE_EXPORT const char *
test_state_describe (void)
{
return "Animating using the State class.";
}

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