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 		void delegate(FrameClock) dlg;
286 		gulong handlerId;
287 		
288 		this(void delegate(FrameClock) dlg)
289 		{
290 			this.dlg = dlg;
291 			onAfterPaintListeners ~= this;
292 		}
293 		
294 		void remove(OnAfterPaintDelegateWrapper source)
295 		{
296 			foreach(index, wrapper; onAfterPaintListeners)
297 			{
298 				if (wrapper.handlerId == source.handlerId)
299 				{
300 					onAfterPaintListeners[index] = null;
301 					onAfterPaintListeners = std.algorithm.remove(onAfterPaintListeners, index);
302 					break;
303 				}
304 			}
305 		}
306 	}
307 	OnAfterPaintDelegateWrapper[] onAfterPaintListeners;
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 		void delegate(FrameClock) dlg;
339 		gulong handlerId;
340 		
341 		this(void delegate(FrameClock) dlg)
342 		{
343 			this.dlg = dlg;
344 			onBeforePaintListeners ~= this;
345 		}
346 		
347 		void remove(OnBeforePaintDelegateWrapper source)
348 		{
349 			foreach(index, wrapper; onBeforePaintListeners)
350 			{
351 				if (wrapper.handlerId == source.handlerId)
352 				{
353 					onBeforePaintListeners[index] = null;
354 					onBeforePaintListeners = std.algorithm.remove(onBeforePaintListeners, index);
355 					break;
356 				}
357 			}
358 		}
359 	}
360 	OnBeforePaintDelegateWrapper[] onBeforePaintListeners;
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 		void delegate(FrameClock) dlg;
392 		gulong handlerId;
393 		
394 		this(void delegate(FrameClock) dlg)
395 		{
396 			this.dlg = dlg;
397 			onFlushEventsListeners ~= this;
398 		}
399 		
400 		void remove(OnFlushEventsDelegateWrapper source)
401 		{
402 			foreach(index, wrapper; onFlushEventsListeners)
403 			{
404 				if (wrapper.handlerId == source.handlerId)
405 				{
406 					onFlushEventsListeners[index] = null;
407 					onFlushEventsListeners = std.algorithm.remove(onFlushEventsListeners, index);
408 					break;
409 				}
410 			}
411 		}
412 	}
413 	OnFlushEventsDelegateWrapper[] onFlushEventsListeners;
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 		void delegate(FrameClock) dlg;
446 		gulong handlerId;
447 		
448 		this(void delegate(FrameClock) dlg)
449 		{
450 			this.dlg = dlg;
451 			onLayoutListeners ~= this;
452 		}
453 		
454 		void remove(OnLayoutDelegateWrapper source)
455 		{
456 			foreach(index, wrapper; onLayoutListeners)
457 			{
458 				if (wrapper.handlerId == source.handlerId)
459 				{
460 					onLayoutListeners[index] = null;
461 					onLayoutListeners = std.algorithm.remove(onLayoutListeners, index);
462 					break;
463 				}
464 			}
465 		}
466 	}
467 	OnLayoutDelegateWrapper[] onLayoutListeners;
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 		void delegate(FrameClock) dlg;
501 		gulong handlerId;
502 		
503 		this(void delegate(FrameClock) dlg)
504 		{
505 			this.dlg = dlg;
506 			onPaintListeners ~= this;
507 		}
508 		
509 		void remove(OnPaintDelegateWrapper source)
510 		{
511 			foreach(index, wrapper; onPaintListeners)
512 			{
513 				if (wrapper.handlerId == source.handlerId)
514 				{
515 					onPaintListeners[index] = null;
516 					onPaintListeners = std.algorithm.remove(onPaintListeners, index);
517 					break;
518 				}
519 			}
520 		}
521 	}
522 	OnPaintDelegateWrapper[] onPaintListeners;
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 		void delegate(FrameClock) dlg;
557 		gulong handlerId;
558 		
559 		this(void delegate(FrameClock) dlg)
560 		{
561 			this.dlg = dlg;
562 			onResumeEventsListeners ~= this;
563 		}
564 		
565 		void remove(OnResumeEventsDelegateWrapper source)
566 		{
567 			foreach(index, wrapper; onResumeEventsListeners)
568 			{
569 				if (wrapper.handlerId == source.handlerId)
570 				{
571 					onResumeEventsListeners[index] = null;
572 					onResumeEventsListeners = std.algorithm.remove(onResumeEventsListeners, index);
573 					break;
574 				}
575 			}
576 		}
577 	}
578 	OnResumeEventsDelegateWrapper[] onResumeEventsListeners;
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 		void delegate(FrameClock) dlg;
611 		gulong handlerId;
612 		
613 		this(void delegate(FrameClock) dlg)
614 		{
615 			this.dlg = dlg;
616 			onUpdateListeners ~= this;
617 		}
618 		
619 		void remove(OnUpdateDelegateWrapper source)
620 		{
621 			foreach(index, wrapper; onUpdateListeners)
622 			{
623 				if (wrapper.handlerId == source.handlerId)
624 				{
625 					onUpdateListeners[index] = null;
626 					onUpdateListeners = std.algorithm.remove(onUpdateListeners, index);
627 					break;
628 				}
629 			}
630 		}
631 	}
632 	OnUpdateDelegateWrapper[] onUpdateListeners;
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 }