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