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