1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gdk.FrameClock;
26 
27 private import gdk.FrameTimings;
28 private import gdk.c.functions;
29 public  import gdk.c.types;
30 private import gobject.ObjectG;
31 private import gobject.Signals;
32 public  import gtkc.gdktypes;
33 private import std.algorithm;
34 
35 
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 public class FrameClock : ObjectG
72 {
73 	/** the main Gtk struct */
74 	protected GdkFrameClock* gdkFrameClock;
75 
76 	/** Get the main Gtk struct */
77 	public GdkFrameClock* getFrameClockStruct(bool transferOwnership = false)
78 	{
79 		if (transferOwnership)
80 			ownedRef = false;
81 		return gdkFrameClock;
82 	}
83 
84 	/** the main Gtk struct as a void* */
85 	protected override void* getStruct()
86 	{
87 		return cast(void*)gdkFrameClock;
88 	}
89 
90 	/**
91 	 * Sets our main struct and passes it to the parent class.
92 	 */
93 	public this (GdkFrameClock* gdkFrameClock, bool ownedRef = false)
94 	{
95 		this.gdkFrameClock = gdkFrameClock;
96 		super(cast(GObject*)gdkFrameClock, ownedRef);
97 	}
98 
99 
100 	/** */
101 	public static GType getType()
102 	{
103 		return gdk_frame_clock_get_type();
104 	}
105 
106 	/**
107 	 * Starts updates for an animation. Until a matching call to
108 	 * gdk_frame_clock_end_updating() is made, the frame clock will continually
109 	 * request a new frame with the %GDK_FRAME_CLOCK_PHASE_UPDATE phase.
110 	 * This function may be called multiple times and frames will be
111 	 * requested until gdk_frame_clock_end_updating() is called the same
112 	 * number of times.
113 	 *
114 	 * Since: 3.8
115 	 */
116 	public void beginUpdating()
117 	{
118 		gdk_frame_clock_begin_updating(gdkFrameClock);
119 	}
120 
121 	/**
122 	 * Stops updates for an animation. See the documentation for
123 	 * gdk_frame_clock_begin_updating().
124 	 *
125 	 * Since: 3.8
126 	 */
127 	public void endUpdating()
128 	{
129 		gdk_frame_clock_end_updating(gdkFrameClock);
130 	}
131 
132 	/**
133 	 * Gets the frame timings for the current frame.
134 	 *
135 	 * Returns: the #GdkFrameTimings for the frame currently
136 	 *     being processed, or even no frame is being processed, for the
137 	 *     previous frame. Before any frames have been procesed, returns
138 	 *     %NULL.
139 	 *
140 	 * Since: 3.8
141 	 */
142 	public FrameTimings getCurrentTimings()
143 	{
144 		auto p = gdk_frame_clock_get_current_timings(gdkFrameClock);
145 
146 		if(p is null)
147 		{
148 			return null;
149 		}
150 
151 		return ObjectG.getDObject!(FrameTimings)(cast(GdkFrameTimings*) p, true);
152 	}
153 
154 	/**
155 	 * A #GdkFrameClock maintains a 64-bit counter that increments for
156 	 * each frame drawn.
157 	 *
158 	 * Returns: inside frame processing, the value of the frame counter
159 	 *     for the current frame. Outside of frame processing, the frame
160 	 *     counter for the last frame.
161 	 *
162 	 * Since: 3.8
163 	 */
164 	public long getFrameCounter()
165 	{
166 		return gdk_frame_clock_get_frame_counter(gdkFrameClock);
167 	}
168 
169 	/**
170 	 * Gets the time that should currently be used for animations.  Inside
171 	 * the processing of a frame, it’s the time used to compute the
172 	 * animation position of everything in a frame. Outside of a frame, it's
173 	 * the time of the conceptual “previous frame,” which may be either
174 	 * the actual previous frame time, or if that’s too old, an updated
175 	 * time.
176 	 *
177 	 * Returns: a timestamp in microseconds, in the timescale of
178 	 *     of g_get_monotonic_time().
179 	 *
180 	 * Since: 3.8
181 	 */
182 	public long getFrameTime()
183 	{
184 		return gdk_frame_clock_get_frame_time(gdkFrameClock);
185 	}
186 
187 	/**
188 	 * #GdkFrameClock internally keeps a history of #GdkFrameTimings
189 	 * objects for recent frames that can be retrieved with
190 	 * gdk_frame_clock_get_timings(). The set of stored frames
191 	 * is the set from the counter values given by
192 	 * gdk_frame_clock_get_history_start() and
193 	 * gdk_frame_clock_get_frame_counter(), inclusive.
194 	 *
195 	 * Returns: the frame counter value for the oldest frame
196 	 *     that is available in the internal frame history of the
197 	 *     #GdkFrameClock.
198 	 *
199 	 * Since: 3.8
200 	 */
201 	public long getHistoryStart()
202 	{
203 		return gdk_frame_clock_get_history_start(gdkFrameClock);
204 	}
205 
206 	/**
207 	 * Using the frame history stored in the frame clock, finds the last
208 	 * known presentation time and refresh interval, and assuming that
209 	 * presentation times are separated by the refresh interval,
210 	 * predicts a presentation time that is a multiple of the refresh
211 	 * interval after the last presentation time, and later than @base_time.
212 	 *
213 	 * Params:
214 	 *     baseTime = base time for determining a presentaton time
215 	 *     refreshIntervalReturn = a location to store the determined refresh
216 	 *         interval, or %NULL. A default refresh interval of 1/60th of
217 	 *         a second will be stored if no history is present.
218 	 *     presentationTimeReturn = a location to store the next
219 	 *         candidate presentation time after the given base time.
220 	 *         0 will be will be stored if no history is present.
221 	 *
222 	 * Since: 3.8
223 	 */
224 	public void getRefreshInfo(long baseTime, long* refreshIntervalReturn, long* presentationTimeReturn)
225 	{
226 		gdk_frame_clock_get_refresh_info(gdkFrameClock, baseTime, refreshIntervalReturn, presentationTimeReturn);
227 	}
228 
229 	/**
230 	 * Retrieves a #GdkFrameTimings object holding timing information
231 	 * for the current frame or a recent frame. The #GdkFrameTimings
232 	 * object may not yet be complete: see gdk_frame_timings_get_complete().
233 	 *
234 	 * Params:
235 	 *     frameCounter = the frame counter value identifying the frame to
236 	 *         be received.
237 	 *
238 	 * Returns: the #GdkFrameTimings object for the specified
239 	 *     frame, or %NULL if it is not available. See
240 	 *     gdk_frame_clock_get_history_start().
241 	 *
242 	 * Since: 3.8
243 	 */
244 	public FrameTimings getTimings(long frameCounter)
245 	{
246 		auto p = gdk_frame_clock_get_timings(gdkFrameClock, frameCounter);
247 
248 		if(p is null)
249 		{
250 			return null;
251 		}
252 
253 		return ObjectG.getDObject!(FrameTimings)(cast(GdkFrameTimings*) p, true);
254 	}
255 
256 	/**
257 	 * Asks the frame clock to run a particular phase. The signal
258 	 * corresponding the requested phase will be emitted the next
259 	 * time the frame clock processes. Multiple calls to
260 	 * gdk_frame_clock_request_phase() will be combined together
261 	 * and only one frame processed. If you are displaying animated
262 	 * content and want to continually request the
263 	 * %GDK_FRAME_CLOCK_PHASE_UPDATE phase for a period of time,
264 	 * you should use gdk_frame_clock_begin_updating() instead, since
265 	 * this allows GTK+ to adjust system parameters to get maximally
266 	 * smooth animations.
267 	 *
268 	 * Params:
269 	 *     phase = the phase that is requested
270 	 *
271 	 * Since: 3.8
272 	 */
273 	public void requestPhase(GdkFrameClockPhase phase)
274 	{
275 		gdk_frame_clock_request_phase(gdkFrameClock, phase);
276 	}
277 
278 	protected class OnAfterPaintDelegateWrapper
279 	{
280 		void delegate(FrameClock) dlg;
281 		gulong handlerId;
282 
283 		this(void delegate(FrameClock) dlg)
284 		{
285 			this.dlg = dlg;
286 			onAfterPaintListeners ~= this;
287 		}
288 
289 		void remove(OnAfterPaintDelegateWrapper source)
290 		{
291 			foreach(index, wrapper; onAfterPaintListeners)
292 			{
293 				if (wrapper.handlerId == source.handlerId)
294 				{
295 					onAfterPaintListeners[index] = null;
296 					onAfterPaintListeners = std.algorithm.remove(onAfterPaintListeners, index);
297 					break;
298 				}
299 			}
300 		}
301 	}
302 	OnAfterPaintDelegateWrapper[] onAfterPaintListeners;
303 
304 	/**
305 	 * This signal ends processing of the frame. Applications
306 	 * should generally not handle this signal.
307 	 */
308 	gulong addOnAfterPaint(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
309 	{
310 		auto wrapper = new OnAfterPaintDelegateWrapper(dlg);
311 		wrapper.handlerId = Signals.connectData(
312 			this,
313 			"after-paint",
314 			cast(GCallback)&callBackAfterPaint,
315 			cast(void*)wrapper,
316 			cast(GClosureNotify)&callBackAfterPaintDestroy,
317 			connectFlags);
318 		return wrapper.handlerId;
319 	}
320 
321 	extern(C) static void callBackAfterPaint(GdkFrameClock* frameclockStruct, OnAfterPaintDelegateWrapper wrapper)
322 	{
323 		wrapper.dlg(wrapper.outer);
324 	}
325 
326 	extern(C) static void callBackAfterPaintDestroy(OnAfterPaintDelegateWrapper wrapper, GClosure* closure)
327 	{
328 		wrapper.remove(wrapper);
329 	}
330 
331 	protected class OnBeforePaintDelegateWrapper
332 	{
333 		void delegate(FrameClock) dlg;
334 		gulong handlerId;
335 
336 		this(void delegate(FrameClock) dlg)
337 		{
338 			this.dlg = dlg;
339 			onBeforePaintListeners ~= this;
340 		}
341 
342 		void remove(OnBeforePaintDelegateWrapper source)
343 		{
344 			foreach(index, wrapper; onBeforePaintListeners)
345 			{
346 				if (wrapper.handlerId == source.handlerId)
347 				{
348 					onBeforePaintListeners[index] = null;
349 					onBeforePaintListeners = std.algorithm.remove(onBeforePaintListeners, index);
350 					break;
351 				}
352 			}
353 		}
354 	}
355 	OnBeforePaintDelegateWrapper[] onBeforePaintListeners;
356 
357 	/**
358 	 * This signal begins processing of the frame. Applications
359 	 * should generally not handle this signal.
360 	 */
361 	gulong addOnBeforePaint(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
362 	{
363 		auto wrapper = new OnBeforePaintDelegateWrapper(dlg);
364 		wrapper.handlerId = Signals.connectData(
365 			this,
366 			"before-paint",
367 			cast(GCallback)&callBackBeforePaint,
368 			cast(void*)wrapper,
369 			cast(GClosureNotify)&callBackBeforePaintDestroy,
370 			connectFlags);
371 		return wrapper.handlerId;
372 	}
373 
374 	extern(C) static void callBackBeforePaint(GdkFrameClock* frameclockStruct, OnBeforePaintDelegateWrapper wrapper)
375 	{
376 		wrapper.dlg(wrapper.outer);
377 	}
378 
379 	extern(C) static void callBackBeforePaintDestroy(OnBeforePaintDelegateWrapper wrapper, GClosure* closure)
380 	{
381 		wrapper.remove(wrapper);
382 	}
383 
384 	protected class OnFlushEventsDelegateWrapper
385 	{
386 		void delegate(FrameClock) dlg;
387 		gulong handlerId;
388 
389 		this(void delegate(FrameClock) dlg)
390 		{
391 			this.dlg = dlg;
392 			onFlushEventsListeners ~= this;
393 		}
394 
395 		void remove(OnFlushEventsDelegateWrapper source)
396 		{
397 			foreach(index, wrapper; onFlushEventsListeners)
398 			{
399 				if (wrapper.handlerId == source.handlerId)
400 				{
401 					onFlushEventsListeners[index] = null;
402 					onFlushEventsListeners = std.algorithm.remove(onFlushEventsListeners, index);
403 					break;
404 				}
405 			}
406 		}
407 	}
408 	OnFlushEventsDelegateWrapper[] onFlushEventsListeners;
409 
410 	/**
411 	 * This signal is used to flush pending motion events that
412 	 * are being batched up and compressed together. Applications
413 	 * should not handle this signal.
414 	 */
415 	gulong addOnFlushEvents(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
416 	{
417 		auto wrapper = new OnFlushEventsDelegateWrapper(dlg);
418 		wrapper.handlerId = Signals.connectData(
419 			this,
420 			"flush-events",
421 			cast(GCallback)&callBackFlushEvents,
422 			cast(void*)wrapper,
423 			cast(GClosureNotify)&callBackFlushEventsDestroy,
424 			connectFlags);
425 		return wrapper.handlerId;
426 	}
427 
428 	extern(C) static void callBackFlushEvents(GdkFrameClock* frameclockStruct, OnFlushEventsDelegateWrapper wrapper)
429 	{
430 		wrapper.dlg(wrapper.outer);
431 	}
432 
433 	extern(C) static void callBackFlushEventsDestroy(OnFlushEventsDelegateWrapper wrapper, GClosure* closure)
434 	{
435 		wrapper.remove(wrapper);
436 	}
437 
438 	protected class OnLayoutDelegateWrapper
439 	{
440 		void delegate(FrameClock) dlg;
441 		gulong handlerId;
442 
443 		this(void delegate(FrameClock) dlg)
444 		{
445 			this.dlg = dlg;
446 			onLayoutListeners ~= this;
447 		}
448 
449 		void remove(OnLayoutDelegateWrapper source)
450 		{
451 			foreach(index, wrapper; onLayoutListeners)
452 			{
453 				if (wrapper.handlerId == source.handlerId)
454 				{
455 					onLayoutListeners[index] = null;
456 					onLayoutListeners = std.algorithm.remove(onLayoutListeners, index);
457 					break;
458 				}
459 			}
460 		}
461 	}
462 	OnLayoutDelegateWrapper[] onLayoutListeners;
463 
464 	/**
465 	 * This signal is emitted as the second step of toolkit and
466 	 * application processing of the frame. Any work to update
467 	 * sizes and positions of application elements should be
468 	 * performed. GTK+ normally handles this internally.
469 	 */
470 	gulong addOnLayout(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
471 	{
472 		auto wrapper = new OnLayoutDelegateWrapper(dlg);
473 		wrapper.handlerId = Signals.connectData(
474 			this,
475 			"layout",
476 			cast(GCallback)&callBackLayout,
477 			cast(void*)wrapper,
478 			cast(GClosureNotify)&callBackLayoutDestroy,
479 			connectFlags);
480 		return wrapper.handlerId;
481 	}
482 
483 	extern(C) static void callBackLayout(GdkFrameClock* frameclockStruct, OnLayoutDelegateWrapper wrapper)
484 	{
485 		wrapper.dlg(wrapper.outer);
486 	}
487 
488 	extern(C) static void callBackLayoutDestroy(OnLayoutDelegateWrapper wrapper, GClosure* closure)
489 	{
490 		wrapper.remove(wrapper);
491 	}
492 
493 	protected class OnPaintDelegateWrapper
494 	{
495 		void delegate(FrameClock) dlg;
496 		gulong handlerId;
497 
498 		this(void delegate(FrameClock) dlg)
499 		{
500 			this.dlg = dlg;
501 			onPaintListeners ~= this;
502 		}
503 
504 		void remove(OnPaintDelegateWrapper source)
505 		{
506 			foreach(index, wrapper; onPaintListeners)
507 			{
508 				if (wrapper.handlerId == source.handlerId)
509 				{
510 					onPaintListeners[index] = null;
511 					onPaintListeners = std.algorithm.remove(onPaintListeners, index);
512 					break;
513 				}
514 			}
515 		}
516 	}
517 	OnPaintDelegateWrapper[] onPaintListeners;
518 
519 	/**
520 	 * This signal is emitted as the third step of toolkit and
521 	 * application processing of the frame. The frame is
522 	 * repainted. GDK normally handles this internally and
523 	 * produces expose events, which are turned into GTK+
524 	 * #GtkWidget::draw signals.
525 	 */
526 	gulong addOnPaint(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
527 	{
528 		auto wrapper = new OnPaintDelegateWrapper(dlg);
529 		wrapper.handlerId = Signals.connectData(
530 			this,
531 			"paint",
532 			cast(GCallback)&callBackPaint,
533 			cast(void*)wrapper,
534 			cast(GClosureNotify)&callBackPaintDestroy,
535 			connectFlags);
536 		return wrapper.handlerId;
537 	}
538 
539 	extern(C) static void callBackPaint(GdkFrameClock* frameclockStruct, OnPaintDelegateWrapper wrapper)
540 	{
541 		wrapper.dlg(wrapper.outer);
542 	}
543 
544 	extern(C) static void callBackPaintDestroy(OnPaintDelegateWrapper wrapper, GClosure* closure)
545 	{
546 		wrapper.remove(wrapper);
547 	}
548 
549 	protected class OnResumeEventsDelegateWrapper
550 	{
551 		void delegate(FrameClock) dlg;
552 		gulong handlerId;
553 
554 		this(void delegate(FrameClock) dlg)
555 		{
556 			this.dlg = dlg;
557 			onResumeEventsListeners ~= this;
558 		}
559 
560 		void remove(OnResumeEventsDelegateWrapper source)
561 		{
562 			foreach(index, wrapper; onResumeEventsListeners)
563 			{
564 				if (wrapper.handlerId == source.handlerId)
565 				{
566 					onResumeEventsListeners[index] = null;
567 					onResumeEventsListeners = std.algorithm.remove(onResumeEventsListeners, index);
568 					break;
569 				}
570 			}
571 		}
572 	}
573 	OnResumeEventsDelegateWrapper[] onResumeEventsListeners;
574 
575 	/**
576 	 * This signal is emitted after processing of the frame is
577 	 * finished, and is handled internally by GTK+ to resume normal
578 	 * event processing. Applications should not handle this signal.
579 	 */
580 	gulong addOnResumeEvents(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
581 	{
582 		auto wrapper = new OnResumeEventsDelegateWrapper(dlg);
583 		wrapper.handlerId = Signals.connectData(
584 			this,
585 			"resume-events",
586 			cast(GCallback)&callBackResumeEvents,
587 			cast(void*)wrapper,
588 			cast(GClosureNotify)&callBackResumeEventsDestroy,
589 			connectFlags);
590 		return wrapper.handlerId;
591 	}
592 
593 	extern(C) static void callBackResumeEvents(GdkFrameClock* frameclockStruct, OnResumeEventsDelegateWrapper wrapper)
594 	{
595 		wrapper.dlg(wrapper.outer);
596 	}
597 
598 	extern(C) static void callBackResumeEventsDestroy(OnResumeEventsDelegateWrapper wrapper, GClosure* closure)
599 	{
600 		wrapper.remove(wrapper);
601 	}
602 
603 	protected class OnUpdateDelegateWrapper
604 	{
605 		void delegate(FrameClock) dlg;
606 		gulong handlerId;
607 
608 		this(void delegate(FrameClock) dlg)
609 		{
610 			this.dlg = dlg;
611 			onUpdateListeners ~= this;
612 		}
613 
614 		void remove(OnUpdateDelegateWrapper source)
615 		{
616 			foreach(index, wrapper; onUpdateListeners)
617 			{
618 				if (wrapper.handlerId == source.handlerId)
619 				{
620 					onUpdateListeners[index] = null;
621 					onUpdateListeners = std.algorithm.remove(onUpdateListeners, index);
622 					break;
623 				}
624 			}
625 		}
626 	}
627 	OnUpdateDelegateWrapper[] onUpdateListeners;
628 
629 	/**
630 	 * This signal is emitted as the first step of toolkit and
631 	 * application processing of the frame. Animations should
632 	 * be updated using gdk_frame_clock_get_frame_time().
633 	 * Applications can connect directly to this signal, or
634 	 * use gtk_widget_add_tick_callback() as a more convenient
635 	 * interface.
636 	 */
637 	gulong addOnUpdate(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
638 	{
639 		auto wrapper = new OnUpdateDelegateWrapper(dlg);
640 		wrapper.handlerId = Signals.connectData(
641 			this,
642 			"update",
643 			cast(GCallback)&callBackUpdate,
644 			cast(void*)wrapper,
645 			cast(GClosureNotify)&callBackUpdateDestroy,
646 			connectFlags);
647 		return wrapper.handlerId;
648 	}
649 
650 	extern(C) static void callBackUpdate(GdkFrameClock* frameclockStruct, OnUpdateDelegateWrapper wrapper)
651 	{
652 		wrapper.dlg(wrapper.outer);
653 	}
654 
655 	extern(C) static void callBackUpdateDestroy(OnUpdateDelegateWrapper wrapper, GClosure* closure)
656 	{
657 		wrapper.remove(wrapper);
658 	}
659 }