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 }