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