This file is indexed.

/usr/share/gtk-doc/html/clutter-cookbook/animations-looping.html is in libclutter-1.0-doc 1.20.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>8. Looping an animation</title><link rel="stylesheet" type="text/css" href="style.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="The Clutter Cookbook"><link rel="up" href="animations.html" title="Chapter 5. Animations"><link rel="prev" href="animations-moving.html" title="7. Moving actors"><link rel="next" href="animations-scaling.html" title="9. Animated scaling"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8. Looping an animation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="animations-moving.html">Prev</a> </td><th width="60%" align="center">Chapter 5. Animations</th><td width="20%" align="right"> <a accesskey="n" href="animations-scaling.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="animations-looping"></a>8. Looping an animation</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idp75334176"></a>8.1. Problem</h3></div></div></div><p>You want to loop an animation so it plays multiple times.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idp75335408"></a>8.2. Solutions</h3></div></div></div><p>Each <a class="link" href="animations.html#animations-introduction-api" title="1.3. Clutter's animation API">animation
      approach</a> can be used to create a looping animation, as
      described in the following sections.</p><p>The animation implemented in each case is a simple repeated
      movement of a rectangle from the right (<code class="code">x = 150.0</code>)
      to the left (<code class="code">x = 50.0</code>) of the stage, and back again,
      looped; like this (just a few iterations):</p><p><video controls="controls" src="videos/animations-looping.ogv"><a href="videos/animations-looping.ogv"></a></video></p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="animations-looping-solutions-implicit"></a>8.2.1. Solution 1: looping an implicit animation</h4></div></div></div><p>Implicit animations, started using
        <code class="function">clutter_actor_animate()</code>, can be looped via
        their associated <span class="type">ClutterTimeline</span>.</p><p>Create a <span class="type">ClutterTimeline</span> which is
        set to loop:</p><div class="informalexample"><pre class="programlisting">ClutterTimeline *timeline = clutter_timeline_new (1000);
clutter_timeline_set_repeat_count (timeline, -1);</pre></div><p>Use this timeline when starting an implicit animation on an
        actor; in this case, to animate the actor's <code class="varname">x</code>
        coordinate from its initial value to <code class="code">50.0</code>:</p><div class="informalexample"><pre class="programlisting">/* assume <code class="varname">actor</code> is a <span class="type">ClutterActor</span> instance */

/* actor's initial x value is 150.0 */
clutter_actor_set_x (actor, 150.0);

/* animate the actor (starting the timeline is implicit) */
clutter_actor_animate_with_timeline (actor,
                                     CLUTTER_LINEAR,
                                     timeline,
                                     "x", 50.0,
                                     NULL);</pre></div><p>One further technique is to repeatedly reverse the timeline's
        direction to create a "closed loop" animation (one which returns
        to its origin at the end of each iteration). See
        <a class="link" href="animations-looping.html#animations-looping-discussion-closed-loop" title='8.3.2. Creating a "closed loop" with an implicit animation'>this
        section</a> for details.</p><p><a class="link" href="animations-looping.html#animations-looping-example-1" title="Example 5.11. Looping an implicit animation">The full
        code example</a> shows how to run an implicit animation on
        a loop.</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="idp75350544"></a>8.2.2. Solution 2: looping with <span class="type">ClutterAnimator</span></h4></div></div></div><p>A <span class="type">ClutterAnimator</span> animation can also be looped
        via its <span class="type">ClutterTimeline</span>. However, as
        <span class="type">ClutterAnimator</span> enables more complex animations,
        you don't have to manually invert the timeline at the
        end of each iteration. Instead, you can animate
        an actor's properties back to their initial values
        at the end of each iteration of the loop.</p><p>Creating the timeline and setting it to loop is the same
        as for implicit animations:</p><div class="informalexample"><pre class="programlisting">ClutterTimeline *timeline = clutter_timeline_new (2000);
clutter_timeline_set_repeat_count (timeline, -1);</pre></div><p>Note that the timeline is twice the length of the one for
        the implicit animation: this is because, unlike the implicit
        animation, the movement from right to left and back again
        is a <span class="emphasis"><em>single</em></span> animation. By contrast, in the
        implicit animation, the timeline runs forward, for the right to
        left movement; and then backwards, for the left to right
        movement. So rather than a 1000ms timeline running twice (once
        forward,  once backward for the implicit animation),
        we have a 2000ms timeline running once (for
        <span class="type">ClutterAnimator</span>).</p><p>Next, create a <span class="type">ClutterAnimator</span> which animates
        the actor from right to left, then left to right:</p><div class="informalexample"><pre class="programlisting">/* assume <code class="varname">actor</code> is a <span class="type">ClutterActor</span> instance */
ClutterAnimator *animator = clutter_animator_new ();

/* use the looping timeline as the timeline for the animator */
clutter_animator_set_timeline (animator, timeline);

/* set positions for the actor at various points through the animation:
 * at progress 0.0, x = 150.0 (right of the stage)
 * at progress 0.5, x = 50.0 (left of the stage)
 * at progress 1.0, x = 150.0 again (back to the right)
 */
clutter_animator_set (animator,
                      actor, "x", CLUTTER_LINEAR, 0.0, 150.0,
                      actor, "x", CLUTTER_LINEAR, 0.5, 50.0,
                      actor, "x", CLUTTER_LINEAR, 1.0, 150.0,
                      NULL);</pre></div><p>Finally, start the animation:</p><div class="informalexample"><pre class="programlisting">clutter_animator_start (animator);</pre></div><p>See <a class="link" href="animations-looping.html#animations-looping-example-2" title="Example 5.12. Looping with ClutterAnimator">the full
        example</a> for more details.</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="idp75362496"></a>8.2.3. Solution 3: looping with <span class="type">ClutterState</span></h4></div></div></div><p>You can loop <span class="type">ClutterState</span> animations by
        creating a cycle of states which
        <a class="ulink" href="http://en.wikipedia.org/wiki/Ouroboros" target="_top">"swallows
        its own tail"</a>: i.e. goes from a start state, through
        intermediate state(s), back to the start state, then again
        through the intermediate states(s), back to the start state,
        etc., ad infinitum.</p><p>For the animation we're implementing, there are two states
        the actor transitions between:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>The actor's <code class="varname">x</code> value
            is <code class="code">150.0</code> (the start/end state, on the right
            of the stage).</p></li><li class="listitem"><p>The actor's <code class="varname">x</code> value is
            <code class="code">50.0</code> (the intermediate state, on the left
            of the stage).</p></li></ol></div><p>Here is how to add those states to a
        <span class="type">ClutterState</span> instance:</p><div class="informalexample"><pre class="programlisting">ClutterState *transitions = clutter_state_new ();

/* the duration for a transition from any state to any other is 1 second */
clutter_state_set_duration (transitions, NULL, NULL, 1000);

clutter_state_set (transitions, NULL, "right",
                   actor, "x", CLUTTER_LINEAR, 150.0,
                   NULL);

clutter_state_set (transitions, NULL, "left",
                   actor, "x", CLUTTER_LINEAR, 50.0,
                   NULL);</pre></div><p>You also need a handler to move the <span class="type">ClutterState</span>
        to its next state, called each time a state transition
        is completed:</p><div class="informalexample"><pre class="programlisting">/* handler to move the <span class="type">ClutterState</span> to its next state */
static void
next_state (ClutterState *transitions,
            gpointer      user_data)
{
  const gchar *state = clutter_state_get_state (transitions);

  if (g_strcmp0 (state, "right") == 0)
    clutter_state_set_state (transitions, "left");
  else
    clutter_state_set_state (transitions, "right");
}</pre></div><p>Then connect the <span class="type">ClutterState's</span>
        <code class="code">completed</code> signal to the handler, so that each time
        a state is reached, the transition to the next state begins:</p><div class="informalexample"><pre class="programlisting">/* connect the <span class="type">ClutterState</span> <code class="code">completed</code> signal to the handler */
g_signal_connect (transitions,
                  "completed",
                  G_CALLBACK (next_state),
                  NULL);</pre></div><p>Finally, put the <span class="type">ClutterState</span> into the start
        state to begin the animation:</p><div class="informalexample"><pre class="programlisting">clutter_state_warp_to_state (transitions, "right");</pre></div><p>See <a class="link" href="animations-looping.html#animations-looping-example-3" title="Example 5.13. Looping with ClutterState">the full
        example</a> for more details.</p></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="idp75380880"></a>8.3. Discussion</h3></div></div></div><p>We use two different approaches to looping in the solutions:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>Setting the <span class="type">ClutterTimeline</span> to loop
          (via <code class="function">clutter_timeline_set_repeat_count()</code>). This
          is the best approach where the timeline is explicit (for
          <span class="type">ClutterAnimator</span> and implicit animations).</p></li><li class="listitem"><p>Cycling through states in a <span class="type">ClutterState</span>. In
          this case, the timeline is implicit and we don't need to
          manually control it: the loop is a consequence of cycling
          repeatedly through a series of states.</p></li></ol></div><p>The following sections cover some other aspects of looping
      animations.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="idp75386944"></a>8.3.1. Looping a fixed number of times</h4></div></div></div><p><span class="type">ClutterTimeline</span> doesn't have any built-in
        functionality to support looping a certain number of times. But
        it is reasonably easy to count the number of iterations completed and
        stop the animation when some limit is reached.</p><p>For example, you could use a static counter to keep track
        of the iteration count:</p><div class="informalexample"><pre class="programlisting">static guint counter = 0;</pre></div><p>Implement the looping behaviour as in the above solutions,
        but use a callback function to set/reset the counter each time
        the timeline completes. For example, for the
        <span class="type">ClutterAnimator</span> solution, you would connect the
        <code class="code">completed</code> signal of the timeline
        to a callback function:</p><div class="informalexample"><pre class="programlisting">g_signal_connect (timeline,
                  "completed",
                  G_CALLBACK (timeline_completed_cb),
                  NULL);</pre></div><p>And implement a callback function which resets the counter and
        stops the timeline if more than two iterations have been counted:</p><div class="informalexample"><pre class="programlisting">static void
timeline_completed_cb (ClutterTimeline *timeline,
                       gpointer         user_data)
{
  counter++;

  if (counter &gt; 2)
    {
      counter = 0;
      clutter_timeline_stop (timeline);
    }
}</pre></div><p>Note that it's simple to count iterations and
        control the timeline using <span class="type">ClutterAnimator</span> or
        <span class="type">ClutterState</span>, as the whole animation (right to left
        and back) is a discrete unit. Doing the same with implicit
        animations is possible (one forward + one backward run along the
        timeline is one iteration). But you will be really stretching the
        implicit animation API beyond its intended use cases.</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="animations-looping-discussion-closed-loop"></a>8.3.2. Creating a "closed loop" with an implicit animation</h4></div></div></div><p>When using implicit animations, at the end of the timeline
        (before the next iteration of the loop), an actor's properties
        "jump" back to their initial values (as they were when the timeline
        started). For example, in the
        <a class="link" href="animations-looping.html#animations-looping-solutions-implicit" title="8.2.1. Solution 1: looping an implicit animation">earlier
        solution</a>, the actor's initial <code class="varname">x</code> value was
        <code class="code">150.0</code>; so the default behaviour on each iteration
        of the loop would be to animate the actor to <code class="code">x = 50.0</code>
        then jump it immediately back to <code class="code">x = 150.0</code>, before
        continuing the loop.</p><p>To prevent this happening, you can create a "closed" loop:
        animate the actor's properties away from their initial values, then
        back again.</p><p>This could be done manually, by creating two separate
        animations, one the inverse of the other, and chaining them together.</p><p>However, a simpler solution is to run forward through the timeline
        once, and have the timeline invert itself when its end is reached.
        The animation then continues, but in reverse. Once the backward iteration
        completes, the timeline sets itself to run forward again, etc.</p><p>To make a timeline reverse its direction each time it
        completes, use the <code class="function">clutter_timeline_set_auto_reverse()</code>
        function:</p><div class="informalexample"><pre class="programlisting">clutter_timeline_set_auto_reverse (timeline, TRUE);</pre></div><p>This is the approach used in
        <a class="link" href="animations-looping.html#animations-looping-example-1" title="Example 5.11. Looping an implicit animation">the example</a>,
        which results in a smooth, repeated right to left,
        left to right motion.</p><p>See <a class="link" href="animations-inversion.html" title="2. Inverting Animations">this
        recipe</a> for more details about inverting a timeline.</p></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="animations-looping-examples"></a>8.4. Full examples</h3></div></div></div><div class="example"><a name="animations-looping-example-1"></a><p class="title"><b>Example 5.11. Looping an implicit animation</b></p><div class="example-contents"><pre class="programlisting">#include &lt;stdlib.h&gt;
#include &lt;clutter/clutter.h&gt;

static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
static const ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff };

typedef struct
{
  ClutterActor    *actor;
  ClutterTimeline *timeline;
} State;

static gboolean
key_pressed_cb (ClutterActor *actor,
                ClutterEvent *event,
                gpointer      user_data)
{
  State *state = (State *) user_data;

  /* only start animating if actor isn't animating already */
  if (clutter_actor_get_animation (state-&gt;actor) == NULL)
    clutter_actor_animate_with_timeline (state-&gt;actor,
                                         CLUTTER_LINEAR,
                                         state-&gt;timeline,
                                         "x", 50.0,
                                         NULL);

  return TRUE;
}

int
main (int   argc,
      char *argv[])
{
  State *state = g_new0 (State, 1);

  ClutterActor *stage;

  if (clutter_init (&amp;argc, &amp;argv) != CLUTTER_INIT_SUCCESS)
    return 1;

  stage = clutter_stage_new ();
  clutter_actor_set_size (stage, 300, 200);
  clutter_stage_set_color (CLUTTER_STAGE (stage), &amp;stage_color);
  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

  state-&gt;actor = clutter_rectangle_new_with_color (&amp;red_color);
  clutter_actor_set_size (state-&gt;actor, 100, 100);
  clutter_actor_set_position (state-&gt;actor, 150, 50);

  state-&gt;timeline = clutter_timeline_new (1000);
  clutter_timeline_set_repeat_count (state-&gt;timeline, -1);
  clutter_timeline_set_auto_reverse (state-&gt;timeline, TRUE);

  g_signal_connect (stage,
                    "key-press-event",
                    G_CALLBACK (key_pressed_cb),
                    state);

  clutter_container_add_actor (CLUTTER_CONTAINER (stage), state-&gt;actor);

  clutter_actor_show (stage);

  clutter_main ();

  g_object_unref (state-&gt;timeline);
  g_free (state);

  return EXIT_SUCCESS;
}
</pre></div></div><br class="example-break"><div class="example"><a name="animations-looping-example-2"></a><p class="title"><b>Example 5.12. Looping with <span class="type">ClutterAnimator</span></b></p><div class="example-contents"><pre class="programlisting">#include &lt;stdlib.h&gt;
#include &lt;clutter/clutter.h&gt;

static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
static const ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff };

static gboolean
key_pressed_cb (ClutterActor *actor,
                ClutterEvent *event,
                gpointer      user_data)
{
  ClutterTimeline *timeline = CLUTTER_TIMELINE (user_data);

  if (!clutter_timeline_is_playing (timeline))
    clutter_timeline_start (timeline);

  return TRUE;
}

int
main (int   argc,
      char *argv[])
{
  ClutterActor *stage;
  ClutterActor *actor;
  ClutterTimeline *timeline;
  ClutterAnimator *animator;

  if (clutter_init (&amp;argc, &amp;argv) != CLUTTER_INIT_SUCCESS)
    return 1;

  stage = clutter_stage_new ();
  clutter_actor_set_size (stage, 300, 200);
  clutter_stage_set_color (CLUTTER_STAGE (stage), &amp;stage_color);
  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

  actor = clutter_rectangle_new_with_color (&amp;red_color);
  clutter_actor_set_size (actor, 100, 100);
  clutter_actor_set_position (actor, 150, 50);

  timeline = clutter_timeline_new (2000);
  clutter_timeline_set_repeat_count (timeline, -1);

  animator = clutter_animator_new ();
  clutter_animator_set_timeline (animator, timeline);

  clutter_animator_set (animator,
                        actor, "x", CLUTTER_LINEAR, 0.0, 150.0,
                        actor, "x", CLUTTER_LINEAR, 0.5, 50.0,
                        actor, "x", CLUTTER_LINEAR, 1.0, 150.0,
                        NULL);

  clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);

  g_signal_connect (stage,
                    "key-press-event",
                    G_CALLBACK (key_pressed_cb),
                    timeline);

  clutter_actor_show (stage);

  clutter_main ();

  g_object_unref (animator);

  return EXIT_SUCCESS;
}
</pre></div></div><br class="example-break"><div class="example"><a name="animations-looping-example-3"></a><p class="title"><b>Example 5.13. Looping with <span class="type">ClutterState</span></b></p><div class="example-contents"><pre class="programlisting">#include &lt;stdlib.h&gt;
#include &lt;clutter/clutter.h&gt;

static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
static const ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff };

static void
next_state (ClutterState *transitions,
            gpointer      user_data)
{
  const gchar *state = clutter_state_get_state (transitions);

  if (g_strcmp0 (state, "right") == 0)
    clutter_state_set_state (transitions, "left");
  else
    clutter_state_set_state (transitions, "right");
}

static gboolean
key_pressed_cb (ClutterActor *actor,
                ClutterEvent *event,
                gpointer      user_data)
{
  ClutterState *transitions = CLUTTER_STATE (user_data);

  if (!clutter_timeline_is_playing (clutter_state_get_timeline (transitions)))
    next_state (transitions, NULL);

  return TRUE;
}

int
main (int   argc,
      char *argv[])
{
  ClutterActor *stage;
  ClutterActor *actor;
  ClutterState *transitions;

  if (clutter_init (&amp;argc, &amp;argv) != CLUTTER_INIT_SUCCESS)
    return 1;

  stage = clutter_stage_new ();
  clutter_actor_set_size (stage, 300, 200);
  clutter_stage_set_color (CLUTTER_STAGE (stage), &amp;stage_color);
  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

  actor = clutter_rectangle_new_with_color (&amp;red_color);
  clutter_actor_set_position (actor, 150, 50);
  clutter_actor_set_size (actor, 100, 100);

  transitions = clutter_state_new ();
  clutter_state_set_duration (transitions, NULL, NULL, 1000);

  clutter_state_set (transitions, NULL, "right",
                     actor, "x", CLUTTER_LINEAR, 150.0,
                     NULL);

  clutter_state_set (transitions, NULL, "left",
                     actor, "x", CLUTTER_LINEAR, 50.0,
                     NULL);

  clutter_state_warp_to_state (transitions, "right");

  g_signal_connect (stage,
                    "key-press-event",
                    G_CALLBACK (key_pressed_cb),
                    transitions);

  g_signal_connect (transitions,
                    "completed",
                    G_CALLBACK (next_state),
                    NULL);

  clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);

  clutter_actor_show (stage);

  clutter_main ();

  g_object_unref (transitions);

  return EXIT_SUCCESS;
}
</pre></div></div><br class="example-break"></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="animations-moving.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="animations.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="animations-scaling.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7. Moving actors </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9. Animated scaling</td></tr></table></div></body></html>