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 * Returns: 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 * Returns: 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 * Returns: 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 * Returns: 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 * Returns: 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 static OnAfterPaintDelegateWrapper[] listeners; 284 void delegate(FrameClock) dlg; 285 gulong handlerId; 286 287 this(void delegate(FrameClock) dlg) 288 { 289 this.dlg = dlg; 290 this.listeners ~= this; 291 } 292 293 void remove(OnAfterPaintDelegateWrapper source) 294 { 295 foreach(index, wrapper; listeners) 296 { 297 if (wrapper.handlerId == source.handlerId) 298 { 299 listeners[index] = null; 300 listeners = std.algorithm.remove(listeners, index); 301 break; 302 } 303 } 304 } 305 } 306 307 /** 308 * This signal ends processing of the frame. Applications 309 * should generally not handle this signal. 310 */ 311 gulong addOnAfterPaint(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 312 { 313 auto wrapper = new OnAfterPaintDelegateWrapper(dlg); 314 wrapper.handlerId = Signals.connectData( 315 this, 316 "after-paint", 317 cast(GCallback)&callBackAfterPaint, 318 cast(void*)wrapper, 319 cast(GClosureNotify)&callBackAfterPaintDestroy, 320 connectFlags); 321 return wrapper.handlerId; 322 } 323 324 extern(C) static void callBackAfterPaint(GdkFrameClock* frameclockStruct, OnAfterPaintDelegateWrapper wrapper) 325 { 326 wrapper.dlg(wrapper.outer); 327 } 328 329 extern(C) static void callBackAfterPaintDestroy(OnAfterPaintDelegateWrapper wrapper, GClosure* closure) 330 { 331 wrapper.remove(wrapper); 332 } 333 334 protected class OnBeforePaintDelegateWrapper 335 { 336 static OnBeforePaintDelegateWrapper[] listeners; 337 void delegate(FrameClock) dlg; 338 gulong handlerId; 339 340 this(void delegate(FrameClock) dlg) 341 { 342 this.dlg = dlg; 343 this.listeners ~= this; 344 } 345 346 void remove(OnBeforePaintDelegateWrapper source) 347 { 348 foreach(index, wrapper; listeners) 349 { 350 if (wrapper.handlerId == source.handlerId) 351 { 352 listeners[index] = null; 353 listeners = std.algorithm.remove(listeners, index); 354 break; 355 } 356 } 357 } 358 } 359 360 /** 361 * This signal begins processing of the frame. Applications 362 * should generally not handle this signal. 363 */ 364 gulong addOnBeforePaint(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 365 { 366 auto wrapper = new OnBeforePaintDelegateWrapper(dlg); 367 wrapper.handlerId = Signals.connectData( 368 this, 369 "before-paint", 370 cast(GCallback)&callBackBeforePaint, 371 cast(void*)wrapper, 372 cast(GClosureNotify)&callBackBeforePaintDestroy, 373 connectFlags); 374 return wrapper.handlerId; 375 } 376 377 extern(C) static void callBackBeforePaint(GdkFrameClock* frameclockStruct, OnBeforePaintDelegateWrapper wrapper) 378 { 379 wrapper.dlg(wrapper.outer); 380 } 381 382 extern(C) static void callBackBeforePaintDestroy(OnBeforePaintDelegateWrapper wrapper, GClosure* closure) 383 { 384 wrapper.remove(wrapper); 385 } 386 387 protected class OnFlushEventsDelegateWrapper 388 { 389 static OnFlushEventsDelegateWrapper[] listeners; 390 void delegate(FrameClock) dlg; 391 gulong handlerId; 392 393 this(void delegate(FrameClock) dlg) 394 { 395 this.dlg = dlg; 396 this.listeners ~= this; 397 } 398 399 void remove(OnFlushEventsDelegateWrapper source) 400 { 401 foreach(index, wrapper; listeners) 402 { 403 if (wrapper.handlerId == source.handlerId) 404 { 405 listeners[index] = null; 406 listeners = std.algorithm.remove(listeners, index); 407 break; 408 } 409 } 410 } 411 } 412 413 /** 414 * This signal is used to flush pending motion events that 415 * are being batched up and compressed together. Applications 416 * should not handle this signal. 417 */ 418 gulong addOnFlushEvents(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 419 { 420 auto wrapper = new OnFlushEventsDelegateWrapper(dlg); 421 wrapper.handlerId = Signals.connectData( 422 this, 423 "flush-events", 424 cast(GCallback)&callBackFlushEvents, 425 cast(void*)wrapper, 426 cast(GClosureNotify)&callBackFlushEventsDestroy, 427 connectFlags); 428 return wrapper.handlerId; 429 } 430 431 extern(C) static void callBackFlushEvents(GdkFrameClock* frameclockStruct, OnFlushEventsDelegateWrapper wrapper) 432 { 433 wrapper.dlg(wrapper.outer); 434 } 435 436 extern(C) static void callBackFlushEventsDestroy(OnFlushEventsDelegateWrapper wrapper, GClosure* closure) 437 { 438 wrapper.remove(wrapper); 439 } 440 441 protected class OnLayoutDelegateWrapper 442 { 443 static OnLayoutDelegateWrapper[] listeners; 444 void delegate(FrameClock) dlg; 445 gulong handlerId; 446 447 this(void delegate(FrameClock) dlg) 448 { 449 this.dlg = dlg; 450 this.listeners ~= this; 451 } 452 453 void remove(OnLayoutDelegateWrapper source) 454 { 455 foreach(index, wrapper; listeners) 456 { 457 if (wrapper.handlerId == source.handlerId) 458 { 459 listeners[index] = null; 460 listeners = std.algorithm.remove(listeners, index); 461 break; 462 } 463 } 464 } 465 } 466 467 /** 468 * This signal is emitted as the second step of toolkit and 469 * application processing of the frame. Any work to update 470 * sizes and positions of application elements should be 471 * performed. GTK+ normally handles this internally. 472 */ 473 gulong addOnLayout(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 474 { 475 auto wrapper = new OnLayoutDelegateWrapper(dlg); 476 wrapper.handlerId = Signals.connectData( 477 this, 478 "layout", 479 cast(GCallback)&callBackLayout, 480 cast(void*)wrapper, 481 cast(GClosureNotify)&callBackLayoutDestroy, 482 connectFlags); 483 return wrapper.handlerId; 484 } 485 486 extern(C) static void callBackLayout(GdkFrameClock* frameclockStruct, OnLayoutDelegateWrapper wrapper) 487 { 488 wrapper.dlg(wrapper.outer); 489 } 490 491 extern(C) static void callBackLayoutDestroy(OnLayoutDelegateWrapper wrapper, GClosure* closure) 492 { 493 wrapper.remove(wrapper); 494 } 495 496 protected class OnPaintDelegateWrapper 497 { 498 static OnPaintDelegateWrapper[] listeners; 499 void delegate(FrameClock) dlg; 500 gulong handlerId; 501 502 this(void delegate(FrameClock) dlg) 503 { 504 this.dlg = dlg; 505 this.listeners ~= this; 506 } 507 508 void remove(OnPaintDelegateWrapper source) 509 { 510 foreach(index, wrapper; listeners) 511 { 512 if (wrapper.handlerId == source.handlerId) 513 { 514 listeners[index] = null; 515 listeners = std.algorithm.remove(listeners, index); 516 break; 517 } 518 } 519 } 520 } 521 522 /** 523 * This signal is emitted as the third step of toolkit and 524 * application processing of the frame. The frame is 525 * repainted. GDK normally handles this internally and 526 * produces expose events, which are turned into GTK+ 527 * #GtkWidget::draw signals. 528 */ 529 gulong addOnPaint(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 530 { 531 auto wrapper = new OnPaintDelegateWrapper(dlg); 532 wrapper.handlerId = Signals.connectData( 533 this, 534 "paint", 535 cast(GCallback)&callBackPaint, 536 cast(void*)wrapper, 537 cast(GClosureNotify)&callBackPaintDestroy, 538 connectFlags); 539 return wrapper.handlerId; 540 } 541 542 extern(C) static void callBackPaint(GdkFrameClock* frameclockStruct, OnPaintDelegateWrapper wrapper) 543 { 544 wrapper.dlg(wrapper.outer); 545 } 546 547 extern(C) static void callBackPaintDestroy(OnPaintDelegateWrapper wrapper, GClosure* closure) 548 { 549 wrapper.remove(wrapper); 550 } 551 552 protected class OnResumeEventsDelegateWrapper 553 { 554 static OnResumeEventsDelegateWrapper[] listeners; 555 void delegate(FrameClock) dlg; 556 gulong handlerId; 557 558 this(void delegate(FrameClock) dlg) 559 { 560 this.dlg = dlg; 561 this.listeners ~= this; 562 } 563 564 void remove(OnResumeEventsDelegateWrapper source) 565 { 566 foreach(index, wrapper; listeners) 567 { 568 if (wrapper.handlerId == source.handlerId) 569 { 570 listeners[index] = null; 571 listeners = std.algorithm.remove(listeners, index); 572 break; 573 } 574 } 575 } 576 } 577 578 /** 579 * This signal is emitted after processing of the frame is 580 * finished, and is handled internally by GTK+ to resume normal 581 * event processing. Applications should not handle this signal. 582 */ 583 gulong addOnResumeEvents(void delegate(FrameClock) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 584 { 585 auto wrapper = new OnResumeEventsDelegateWrapper(dlg); 586 wrapper.handlerId = Signals.connectData( 587 this, 588 "resume-events", 589 cast(GCallback)&callBackResumeEvents, 590 cast(void*)wrapper, 591 cast(GClosureNotify)&callBackResumeEventsDestroy, 592 connectFlags); 593 return wrapper.handlerId; 594 } 595 596 extern(C) static void callBackResumeEvents(GdkFrameClock* frameclockStruct, OnResumeEventsDelegateWrapper wrapper) 597 { 598 wrapper.dlg(wrapper.outer); 599 } 600 601 extern(C) static void callBackResumeEventsDestroy(OnResumeEventsDelegateWrapper wrapper, GClosure* closure) 602 { 603 wrapper.remove(wrapper); 604 } 605 606 protected class OnUpdateDelegateWrapper 607 { 608 static OnUpdateDelegateWrapper[] listeners; 609 void delegate(FrameClock) dlg; 610 gulong handlerId; 611 612 this(void delegate(FrameClock) dlg) 613 { 614 this.dlg = dlg; 615 this.listeners ~= this; 616 } 617 618 void remove(OnUpdateDelegateWrapper source) 619 { 620 foreach(index, wrapper; listeners) 621 { 622 if (wrapper.handlerId == source.handlerId) 623 { 624 listeners[index] = null; 625 listeners = std.algorithm.remove(listeners, index); 626 break; 627 } 628 } 629 } 630 } 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 auto wrapper = new OnUpdateDelegateWrapper(dlg); 643 wrapper.handlerId = Signals.connectData( 644 this, 645 "update", 646 cast(GCallback)&callBackUpdate, 647 cast(void*)wrapper, 648 cast(GClosureNotify)&callBackUpdateDestroy, 649 connectFlags); 650 return wrapper.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.remove(wrapper); 661 } 662 }