]> Pileus Git - ~andy/gtk/blob - gdk/gdkframeclock.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gdk / gdkframeclock.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2010.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include "config.h"
28
29 #include "gdkframeclockprivate.h"
30 #include "gdkinternals.h"
31
32 /**
33  * SECTION:gdkframeclock
34  * @Short_description: Frame clock syncs painting to a window or display
35  * @Title: Frame clock
36  *
37  * A #GdkFrameClock tells the application when to update and repaint a
38  * window. This may be synced to the vertical refresh rate of the
39  * monitor, for example. Even when the frame clock uses a simple timer
40  * rather than a hardware-based vertical sync, the frame clock helps
41  * because it ensures everything paints at the same time (reducing the
42  * total number of frames). The frame clock can also automatically
43  * stop painting when it knows the frames will not be visible, or
44  * scale back animation framerates.
45  *
46  * #GdkFrameClock is designed to be compatible with an OpenGL-based
47  * implementation or with mozRequestAnimationFrame in Firefox,
48  * for example.
49  *
50  * A frame clock is idle until someone requests a frame with
51  * gdk_frame_clock_request_phase(). At some later point that makes
52  * sense for the synchronization being implemented, the clock will
53  * process a frame and emit signals for each phase that has been
54  * requested. (See the signals of the #GdkFrameClock class for
55  * documentation of the phases. %GDK_FRAME_CLOCK_PHASE_UPDATE and the
56  * #GdkFrameClock::update signal are most interesting for application
57  * writers, and are used to update the animations, using the frame time
58  * given by gdk_frame_clock_get_frame_time().
59  *
60  * The frame time is reported in microseconds and generally in the same
61  * timescale as g_get_monotonic_time(), however, it is not the same
62  * as g_get_monotonic_time(). The frame time does not advance during
63  * the time a frame is being painted, and outside of a frame, an attempt
64  * is made so that all calls to gdk_frame_clock_get_frame_time() that
65  * are called at a "similar" time get the same value. This means that
66  * if different animations are timed by looking at the difference in
67  * time between an initial value from gdk_frame_clock_get_frame_time()
68  * and the value inside the #GdkFrameClock::update signal of the clock,
69  * they will stay exactly synchronized.
70  */
71
72 G_DEFINE_ABSTRACT_TYPE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
73
74 enum {
75   FLUSH_EVENTS,
76   BEFORE_PAINT,
77   UPDATE,
78   LAYOUT,
79   PAINT,
80   AFTER_PAINT,
81   RESUME_EVENTS,
82   LAST_SIGNAL
83 };
84
85 static guint signals[LAST_SIGNAL];
86
87 #define FRAME_HISTORY_MAX_LENGTH 16
88
89 struct _GdkFrameClockPrivate
90 {
91   gint64 frame_counter;
92   gint n_timings;
93   gint current;
94   GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
95 };
96
97 static void
98 gdk_frame_clock_finalize (GObject *object)
99 {
100   GdkFrameClockPrivate *priv = GDK_FRAME_CLOCK (object)->priv;
101   int i;
102
103   for (i = 0; i < FRAME_HISTORY_MAX_LENGTH; i++)
104     if (priv->timings[i] != 0)
105       gdk_frame_timings_unref (priv->timings[i]);
106
107   G_OBJECT_CLASS (gdk_frame_clock_parent_class)->finalize (object);
108 }
109
110 static void
111 gdk_frame_clock_class_init (GdkFrameClockClass *klass)
112 {
113   GObjectClass *gobject_class = (GObjectClass*) klass;
114
115   gobject_class->finalize     = gdk_frame_clock_finalize;
116
117   /**
118    * GdkFrameClock::flush-events:
119    * @clock: the frame clock emitting the signal
120    *
121    * This signal is used to flush pending motion events that
122    * are being batched up and compressed together. Applications
123    * should not handle this signal.
124    */
125   signals[FLUSH_EVENTS] =
126     g_signal_new (g_intern_static_string ("flush-events"),
127                   GDK_TYPE_FRAME_CLOCK,
128                   G_SIGNAL_RUN_LAST,
129                   0,
130                   NULL, NULL,
131                   g_cclosure_marshal_VOID__VOID,
132                   G_TYPE_NONE, 0);
133
134   /**
135    * GdkFrameClock::before-paint:
136    * @clock: the frame clock emitting the signal
137    *
138    * This signal begins processing of the frame. Applications
139    * should generally not handle this signal.
140    */
141   signals[BEFORE_PAINT] =
142     g_signal_new (g_intern_static_string ("before-paint"),
143                   GDK_TYPE_FRAME_CLOCK,
144                   G_SIGNAL_RUN_LAST,
145                   0,
146                   NULL, NULL,
147                   g_cclosure_marshal_VOID__VOID,
148                   G_TYPE_NONE, 0);
149
150   /**
151    * GdkFrameClock::update:
152    * @clock: the frame clock emitting the signal
153    *
154    * This signal is emitted as the first step of toolkit and
155    * application processing of the frame. Animations should
156    * be updated using gdk_frame_clock_get_frame_time().
157    * Applications can connect directly to this signal, or
158    * use gtk_widget_add_tick_callback() as a more convenient
159    * interface.
160    */
161   signals[UPDATE] =
162     g_signal_new (g_intern_static_string ("update"),
163                   GDK_TYPE_FRAME_CLOCK,
164                   G_SIGNAL_RUN_LAST,
165                   0,
166                   NULL, NULL,
167                   g_cclosure_marshal_VOID__VOID,
168                   G_TYPE_NONE, 0);
169
170   /**
171    * GdkFrameClock::layout:
172    * @clock: the frame clock emitting the signal
173    *
174    * This signal is emitted as the second step of toolkit and
175    * application processing of the frame. Any work to update
176    * sizes and positions of application elements should be
177    * performed. GTK+ normally handles this internally.
178    */
179   signals[LAYOUT] =
180     g_signal_new (g_intern_static_string ("layout"),
181                   GDK_TYPE_FRAME_CLOCK,
182                   G_SIGNAL_RUN_LAST,
183                   0,
184                   NULL, NULL,
185                   g_cclosure_marshal_VOID__VOID,
186                   G_TYPE_NONE, 0);
187
188   /**
189    * GdkFrameClock::paint:
190    * @clock: the frame clock emitting the signal
191    *
192    * This signal is emitted as the third step of toolkit and
193    * application processing of the frame. The frame is
194    * repainted. GDK normally handles this internally and
195    * produces expose events, which are turned into GTK+
196    * #GtkWidget::draw signals.
197    */
198   signals[PAINT] =
199     g_signal_new (g_intern_static_string ("paint"),
200                   GDK_TYPE_FRAME_CLOCK,
201                   G_SIGNAL_RUN_LAST,
202                   0,
203                   NULL, NULL,
204                   g_cclosure_marshal_VOID__VOID,
205                   G_TYPE_NONE, 0);
206
207   /**
208    * GdkFrameClock::after-paint:
209    * @clock: the frame clock emitting the signal
210    *
211    * This signal ends processing of the frame. Applications
212    * should generally not handle this signal.
213    */
214   signals[AFTER_PAINT] =
215     g_signal_new (g_intern_static_string ("after-paint"),
216                   GDK_TYPE_FRAME_CLOCK,
217                   G_SIGNAL_RUN_LAST,
218                   0,
219                   NULL, NULL,
220                   g_cclosure_marshal_VOID__VOID,
221                   G_TYPE_NONE, 0);
222
223   /**
224    * GdkFrameClock::resume-events:
225    * @clock: the frame clock emitting the signal
226    *
227    * This signal is emitted after processing of the frame is
228    * finished, and is handled internally by GTK+ to resume normal
229    * event processing. Applications should not handle this signal.
230    */
231   signals[RESUME_EVENTS] =
232     g_signal_new (g_intern_static_string ("resume-events"),
233                   GDK_TYPE_FRAME_CLOCK,
234                   G_SIGNAL_RUN_LAST,
235                   0,
236                   NULL, NULL,
237                   g_cclosure_marshal_VOID__VOID,
238                   G_TYPE_NONE, 0);
239
240   g_type_class_add_private (klass, sizeof (GdkFrameClockPrivate));
241 }
242
243 static void
244 gdk_frame_clock_init (GdkFrameClock *clock)
245 {
246   GdkFrameClockPrivate *priv;
247
248   clock->priv = G_TYPE_INSTANCE_GET_PRIVATE (clock,
249                                              GDK_TYPE_FRAME_CLOCK,
250                                              GdkFrameClockPrivate);
251   priv = clock->priv;
252
253   priv->frame_counter = -1;
254   priv->current = FRAME_HISTORY_MAX_LENGTH - 1;
255 }
256
257 /**
258  * gdk_frame_clock_get_frame_time:
259  * @frame_clock: a #GdkFrameClock
260  *
261  * Gets the time that should currently be used for animations.  Inside
262  * the processing of a frame, it's the time used to compute the
263  * animation position of everything in a frame. Outside of a frame, it's
264  * the time of the conceptual "previous frame," which may be either
265  * the actual previous frame time, or if that's too old, an updated
266  * time.
267  *
268  * Since: 3.8
269  * Return value: a timestamp in microseconds, in the timescale of
270  *  of g_get_monotonic_time().
271  */
272 gint64
273 gdk_frame_clock_get_frame_time (GdkFrameClock *frame_clock)
274 {
275   g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), 0);
276
277   return GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->get_frame_time (frame_clock);
278 }
279
280 /**
281  * gdk_frame_clock_request_phase:
282  * @frame_clock: a #GdkFrameClock
283  * @phase: the phase that is requested
284  *
285  * Asks the frame clock to run a particular phase. The signal
286  * corresponding the requested phase will be emitted the next
287  * time the frame clock processes. Multiple calls to
288  * gdk_frame_clock_request_phase() will be combined together
289  * and only one frame processed. If you are displaying animated
290  * content and want to continually request the
291  * %GDK_FRAME_CLOCK_PHASE_UPDATE phase for a period of time,
292  * you should use gdk_frame_clock_begin_updating() instead, since
293  * this allows GTK+ to adjust system parameters to get maximally
294  * smooth animations.
295  *
296  * Since: 3.8
297  */
298 void
299 gdk_frame_clock_request_phase (GdkFrameClock      *frame_clock,
300                                GdkFrameClockPhase  phase)
301 {
302   g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
303
304   GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->request_phase (frame_clock, phase);
305 }
306
307 /**
308  * gdk_frame_clock_begin_updating:
309  * @frame_clock: a #GdkFrameClock
310  *
311  * Starts updates for an animation. Until a matching call to
312  * gdk_frame_clock_end_updating() is made, the frame clock will continually
313  * request a new frame with the %GDK_FRAME_CLOCK_PHASE_UPDATE phase.
314  * This function may be called multiple times and frames will be
315  * requested until gdk_frame_clock_end_updating() is called the same
316  * number of times.
317  *
318  * Since: 3.8
319  */
320 void
321 gdk_frame_clock_begin_updating (GdkFrameClock *frame_clock)
322 {
323   g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
324
325   GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->begin_updating (frame_clock);
326 }
327
328 /**
329  * gdk_frame_clock_end_updating:
330  * @frame_clock: a #GdkFrameClock
331  *
332  * Stops updates for an animation. See the documentation for
333  * gdk_frame_clock_begin_updating().
334  *
335  * Since: 3.8
336  */
337 void
338 gdk_frame_clock_end_updating (GdkFrameClock *frame_clock)
339 {
340   g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
341
342   GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->end_updating (frame_clock);
343 }
344
345 void
346 _gdk_frame_clock_freeze (GdkFrameClock *clock)
347 {
348   g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
349
350   GDK_FRAME_CLOCK_GET_CLASS (clock)->freeze (clock);
351 }
352
353
354 void
355 _gdk_frame_clock_thaw (GdkFrameClock *clock)
356 {
357   g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
358
359   GDK_FRAME_CLOCK_GET_CLASS (clock)->thaw (clock);
360 }
361
362 /**
363  * gdk_frame_clock_get_frame_counter:
364  * @frame_clock: a #GdkFrameClock
365  *
366  * A #GdkFrameClock maintains a 64-bit counter that increments for
367  * each frame drawn.
368  *
369  * Returns: inside frame processing, the value of the frame counter
370  *  for the current frame. Outside of frame processing, the frame
371  *   counter for the last frame.
372  * Since: 3.8
373  */
374 gint64
375 gdk_frame_clock_get_frame_counter (GdkFrameClock *frame_clock)
376 {
377   GdkFrameClockPrivate *priv;
378
379   g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), 0);
380
381   priv = frame_clock->priv;
382
383   return priv->frame_counter;
384 }
385
386 /**
387  * gdk_frame_clock_get_history_start:
388  * @frame_clock: a #GdkFrameClock
389  *
390  * #GdkFrameClock internally keeps a history of #GdkFrameTiming
391  * objects for recent frames that can be retrieved with
392  * gdk_frame_clock_get_timings(). The set of stored frames
393  * is the set from the counter values given by
394  * gdk_frame_clock_get_history_start() and
395  * gdk_frame_clock_get_frame_counter(), inclusive.
396  *
397  * Return value: the frame counter value for the oldest frame
398  *  that is available in the internal frame history of the
399  *  #GdkFrameClock.
400  * Since: 3.8
401  */
402 gint64
403 gdk_frame_clock_get_history_start (GdkFrameClock *frame_clock)
404 {
405   GdkFrameClockPrivate *priv;
406
407   g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), 0);
408
409   priv = frame_clock->priv;
410
411   return priv->frame_counter + 1 - priv->n_timings;
412 }
413
414 void
415 _gdk_frame_clock_begin_frame (GdkFrameClock *frame_clock)
416 {
417   GdkFrameClockPrivate *priv;
418
419   g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
420
421   priv = frame_clock->priv;
422
423   priv->frame_counter++;
424   priv->current = (priv->current + 1) % FRAME_HISTORY_MAX_LENGTH;
425
426   if (priv->n_timings < FRAME_HISTORY_MAX_LENGTH)
427     priv->n_timings++;
428   else
429     {
430       gdk_frame_timings_unref(priv->timings[priv->current]);
431     }
432
433   priv->timings[priv->current] = _gdk_frame_timings_new (priv->frame_counter);
434 }
435
436 /**
437  * gdk_frame_clock_get_timings:
438  * @frame_clock: a #GdkFrameClock
439  * @frame_counter: the frame counter value identifying the frame to
440  *  be received.
441  *
442  * Retrieves a #GdkFrameTimings object holding timing information
443  * for the current frame or a recent frame. The #GdkFrameTimings
444  * object may not yet be complete: see gdk_frame_timings_get_complete().
445  *
446  * Return value: the #GdkFrameTimings object for the specified
447  *  frame, or %NULL if it is not available. See
448  *  gdk_frame_clock_get_history_start().
449  * Since: 3.8
450  */
451 GdkFrameTimings *
452 gdk_frame_clock_get_timings (GdkFrameClock *frame_clock,
453                              gint64         frame_counter)
454 {
455   GdkFrameClockPrivate *priv;
456   gint pos;
457
458   g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), NULL);
459
460   priv = frame_clock->priv;
461
462   if (frame_counter > priv->frame_counter)
463     return NULL;
464
465   if (frame_counter <= priv->frame_counter - priv->n_timings)
466     return NULL;
467
468   pos = (priv->current - (priv->frame_counter - frame_counter) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
469
470   return priv->timings[pos];
471 }
472
473 /**
474  * gdk_frame_clock_get_current_timings:
475  * @frame_clock: a #GdkFrameClock
476  *
477  * Gets the frame timings for the current frame.
478  *
479  * Returns: the #GdkFrameTimings for the frame currently being
480  *  processed, or even no frame is being processed, for the
481  *  previous frame. Before any frames have been procesed,
482  *  returns %NULL.
483  * Since: 3.8
484  */
485 GdkFrameTimings *
486 gdk_frame_clock_get_current_timings (GdkFrameClock *frame_clock)
487 {
488   GdkFrameClockPrivate *priv;
489
490   g_return_val_if_fail (GDK_IS_FRAME_CLOCK (frame_clock), 0);
491
492   priv = frame_clock->priv;
493
494   return gdk_frame_clock_get_timings (frame_clock, priv->frame_counter);
495 }
496
497
498 #ifdef G_ENABLE_DEBUG
499 void
500 _gdk_frame_clock_debug_print_timings (GdkFrameClock   *clock,
501                                       GdkFrameTimings *timings)
502 {
503   gint64 previous_frame_time = 0;
504   GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (clock,
505                                                                    timings->frame_counter - 1);
506
507   if (previous_timings != NULL)
508     previous_frame_time = previous_timings->frame_time;
509
510   g_print ("%5" G_GINT64_FORMAT ":", timings->frame_counter);
511   if (previous_frame_time != 0)
512     {
513       g_print (" interval=%-4.1f", (timings->frame_time - previous_frame_time) / 1000.);
514       g_print (timings->slept_before ?  " (sleep)" : "        ");
515     }
516   if (timings->layout_start_time != 0)
517     g_print (" layout_start=%-4.1f", (timings->layout_start_time - timings->frame_time) / 1000.);
518   if (timings->paint_start_time != 0)
519     g_print (" paint_start=%-4.1f", (timings->paint_start_time - timings->frame_time) / 1000.);
520   if (timings->frame_end_time != 0)
521     g_print (" frame_end=%-4.1f", (timings->frame_end_time - timings->frame_time) / 1000.);
522   if (timings->presentation_time != 0)
523     g_print (" present=%-4.1f", (timings->presentation_time - timings->frame_time) / 1000.);
524   if (timings->predicted_presentation_time != 0)
525     g_print (" predicted=%-4.1f", (timings->predicted_presentation_time - timings->frame_time) / 1000.);
526   if (timings->refresh_interval != 0)
527     g_print (" refresh_interval=%-4.1f", timings->refresh_interval / 1000.);
528   g_print ("\n");
529 }
530 #endif /* G_ENABLE_DEBUG */
531
532 #define DEFAULT_REFRESH_INTERVAL 16667 /* 16.7ms (1/60th second) */
533 #define MAX_HISTORY_AGE 150000         /* 150ms */
534
535 /**
536  * gdk_frame_clock_get_refresh_info:
537  * @frame_clock: a #GdkFrameClock
538  * @base_time: base time for determining a presentaton time
539  * @refresh_interval_return: a location to store the determined refresh
540  *  interval, or %NULL. A default refresh interval of 1/60th of
541  *  a second will be stored if no history is present.
542  * @presentation_time_return: a location to store the next
543  *  candidate presentation time after the given base time.
544  *  0 will be will be stored if no history is present.
545  *
546  * Using the frame history stored in the frame clock, finds the last
547  * known presentation time and refresh interval, and assuming that
548  * presentation times are separated by the refresh interval,
549  * predicts a presentation time that is a multiple of the refresh
550  * interval after the last presentation time, and later than @base_time.
551  *
552  * Since: 3.8
553  */
554 void
555 gdk_frame_clock_get_refresh_info (GdkFrameClock *frame_clock,
556                                   gint64         base_time,
557                                   gint64        *refresh_interval_return,
558                                   gint64        *presentation_time_return)
559 {
560   gint64 frame_counter;
561
562   g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock));
563
564   frame_counter = gdk_frame_clock_get_frame_counter (frame_clock);
565
566   if (presentation_time_return)
567     *presentation_time_return = 0;
568   if (refresh_interval_return)
569     *refresh_interval_return = DEFAULT_REFRESH_INTERVAL;
570
571   while (TRUE)
572     {
573       GdkFrameTimings *timings = gdk_frame_clock_get_timings (frame_clock, frame_counter);
574       gint64 presentation_time;
575       gint64 refresh_interval;
576
577       if (timings == NULL)
578         return;
579
580       refresh_interval = timings->refresh_interval;
581       presentation_time = timings->presentation_time;
582
583       if (presentation_time != 0)
584         {
585           if (presentation_time > base_time - MAX_HISTORY_AGE &&
586               presentation_time_return)
587             {
588               if (refresh_interval == 0)
589                 refresh_interval = DEFAULT_REFRESH_INTERVAL;
590
591               if (refresh_interval_return)
592                 *refresh_interval_return = refresh_interval;
593
594               while (presentation_time < base_time)
595                 presentation_time += refresh_interval;
596
597               if (presentation_time_return)
598                 *presentation_time_return = presentation_time;
599             }
600
601           return;
602         }
603
604       frame_counter--;
605     }
606 }