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 }