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 }