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 gstreamer.Bus; 26 27 private import glib.ConstructionException; 28 private import glib.Source; 29 private import gobject.ObjectG; 30 private import gobject.Signals; 31 private import gstreamer.Message; 32 private import gstreamer.ObjectGst; 33 private import gstreamerc.gstreamer; 34 public import gstreamerc.gstreamertypes; 35 public import gtkc.gdktypes; 36 private import std.algorithm; 37 38 39 /** 40 * The #GstBus is an object responsible for delivering #GstMessage packets in 41 * a first-in first-out way from the streaming threads (see #GstTask) to the 42 * application. 43 * 44 * Since the application typically only wants to deal with delivery of these 45 * messages from one thread, the GstBus will marshall the messages between 46 * different threads. This is important since the actual streaming of media 47 * is done in another thread than the application. 48 * 49 * The GstBus provides support for #GSource based notifications. This makes it 50 * possible to handle the delivery in the glib mainloop. 51 * 52 * The #GSource callback function gst_bus_async_signal_func() can be used to 53 * convert all bus messages into signal emissions. 54 * 55 * A message is posted on the bus with the gst_bus_post() method. With the 56 * gst_bus_peek() and gst_bus_pop() methods one can look at or retrieve a 57 * previously posted message. 58 * 59 * The bus can be polled with the gst_bus_poll() method. This methods blocks 60 * up to the specified timeout value until one of the specified messages types 61 * is posted on the bus. The application can then gst_bus_pop() the messages 62 * from the bus to handle them. 63 * Alternatively the application can register an asynchronous bus function 64 * using gst_bus_add_watch_full() or gst_bus_add_watch(). This function will 65 * install a #GSource in the default glib main loop and will deliver messages 66 * a short while after they have been posted. Note that the main loop should 67 * be running for the asynchronous callbacks. 68 * 69 * It is also possible to get messages from the bus without any thread 70 * marshalling with the gst_bus_set_sync_handler() method. This makes it 71 * possible to react to a message in the same thread that posted the 72 * message on the bus. This should only be used if the application is able 73 * to deal with messages from different threads. 74 * 75 * Every #GstPipeline has one bus. 76 * 77 * Note that a #GstPipeline will set its bus into flushing state when changing 78 * from READY to NULL state. 79 */ 80 public class Bus : ObjectGst 81 { 82 /** the main Gtk struct */ 83 protected GstBus* gstBus; 84 85 /** Get the main Gtk struct */ 86 public GstBus* getBusStruct() 87 { 88 return gstBus; 89 } 90 91 /** the main Gtk struct as a void* */ 92 protected override void* getStruct() 93 { 94 return cast(void*)gstBus; 95 } 96 97 protected override void setStruct(GObject* obj) 98 { 99 gstBus = cast(GstBus*)obj; 100 super.setStruct(obj); 101 } 102 103 /** 104 * Sets our main struct and passes it to the parent class. 105 */ 106 public this (GstBus* gstBus, bool ownedRef = false) 107 { 108 this.gstBus = gstBus; 109 super(cast(GstObject*)gstBus, ownedRef); 110 } 111 112 /** 113 * Adds a bus watch to the default main context with the default priority. 114 * This function is used to receive asynchronous messages in the main loop. 115 * The watch can be removed using g_source_remove() or by returning FALSE 116 * from func. 117 * MT safe. 118 * Params: 119 * dlg = A function to call when a message is received. 120 * Returns: 121 * The event source id. 122 */ 123 public uint addWatch( bool delegate(Message) dlg ) 124 { 125 onWatchListener = dlg; 126 return gst_bus_add_watch(gstBus, cast(GstBusFunc)&watchCallBack, cast(void*)this); 127 } 128 129 bool delegate(Message) onWatchListener; 130 131 extern(C) static int watchCallBack(GstBus* bus, GstMessage* msg, Bus bus_d )//gpointer data) 132 { 133 Message msg_d = new Message( msg ); 134 135 return bus_d.onWatchListener( msg_d ); 136 } 137 138 /** 139 * Use this for making an XOverlay. 140 * Sets the synchronous handler on the bus. The function will be called 141 * every time a new message is posted on the bus. Note that the function 142 * will be called in the same thread context as the posting object. This 143 * function is usually only called by the creator of the bus. Applications 144 * should handle messages asynchronously using the gst_bus watch and poll 145 * functions. 146 * You cannot replace an existing sync_handler. You can pass NULL to this 147 * function, which will clear the existing handler. 148 * Params: 149 * dlg = The handler function to install 150 */ 151 public void setSyncHandler( GstBusSyncReply delegate(Message) dlg ) 152 { 153 onSyncHandlerListener = dlg; 154 gst_bus_set_sync_handler(gstBus, cast(GstBusSyncHandler)&syncHandlerCallBack, cast(void*)this, null); 155 } 156 157 GstBusSyncReply delegate(Message) onSyncHandlerListener; 158 159 extern(C) static GstBusSyncReply syncHandlerCallBack(GstBus* bus, GstMessage* msg, Bus bus_d) 160 { 161 Message msg_d = new Message( msg ); 162 163 return bus_d.onSyncHandlerListener( msg_d ); 164 } 165 166 /** 167 */ 168 169 /** */ 170 public static GType getType() 171 { 172 return gst_bus_get_type(); 173 } 174 175 /** 176 * Creates a new #GstBus instance. 177 * 178 * Return: a new #GstBus instance 179 * 180 * Throws: ConstructionException GTK+ fails to create the object. 181 */ 182 public this() 183 { 184 auto p = gst_bus_new(); 185 186 if(p is null) 187 { 188 throw new ConstructionException("null returned by new"); 189 } 190 191 this(cast(GstBus*) p, true); 192 } 193 194 /** 195 * Adds a bus signal watch to the default main context with the default priority 196 * (%G_PRIORITY_DEFAULT). It is also possible to use a non-default 197 * main context set up using g_main_context_push_thread_default() (before 198 * one had to create a bus watch source and attach it to the desired main 199 * context 'manually'). 200 * 201 * After calling this statement, the bus will emit the "message" signal for each 202 * message posted on the bus. 203 * 204 * This function may be called multiple times. To clean up, the caller is 205 * responsible for calling gst_bus_remove_signal_watch() as many times as this 206 * function is called. 207 * 208 * MT safe. 209 */ 210 public void addSignalWatch() 211 { 212 gst_bus_add_signal_watch(gstBus); 213 } 214 215 /** 216 * Adds a bus signal watch to the default main context with the given @priority 217 * (e.g. %G_PRIORITY_DEFAULT). It is also possible to use a non-default main 218 * context set up using g_main_context_push_thread_default() 219 * (before one had to create a bus watch source and attach it to the desired 220 * main context 'manually'). 221 * 222 * After calling this statement, the bus will emit the "message" signal for each 223 * message posted on the bus when the main loop is running. 224 * 225 * This function may be called multiple times. To clean up, the caller is 226 * responsible for calling gst_bus_remove_signal_watch() as many times as this 227 * function is called. 228 * 229 * There can only be a single bus watch per bus, you must remove any signal 230 * watch before you can set another type of watch. 231 * 232 * MT safe. 233 * 234 * Params: 235 * priority = The priority of the watch. 236 */ 237 public void addSignalWatchFull(int priority) 238 { 239 gst_bus_add_signal_watch_full(gstBus, priority); 240 } 241 242 /** 243 * Adds a bus watch to the default main context with the given @priority (e.g. 244 * %G_PRIORITY_DEFAULT). It is also possible to use a non-default main 245 * context set up using g_main_context_push_thread_default() (before 246 * one had to create a bus watch source and attach it to the desired main 247 * context 'manually'). 248 * 249 * This function is used to receive asynchronous messages in the main loop. 250 * There can only be a single bus watch per bus, you must remove it before you 251 * can set a new one. 252 * 253 * The bus watch will only work if a GLib main loop is being run. 254 * 255 * When @func is called, the message belongs to the caller; if you want to 256 * keep a copy of it, call gst_message_ref() before leaving @func. 257 * 258 * The watch can be removed using gst_bus_remove_watch() or by returning %FALSE 259 * from @func. If the watch was added to the default main context it is also 260 * possible to remove the watch using g_source_remove(). 261 * 262 * MT safe. 263 * 264 * Params: 265 * priority = The priority of the watch. 266 * func = A function to call when a message is received. 267 * userData = user data passed to @func. 268 * notify = the function to call when the source is removed. 269 * 270 * Return: The event source id or 0 if @bus already got an event source. 271 */ 272 public uint addWatchFull(int priority, GstBusFunc func, void* userData, GDestroyNotify notify) 273 { 274 return gst_bus_add_watch_full(gstBus, priority, func, userData, notify); 275 } 276 277 /** 278 * A helper #GstBusFunc that can be used to convert all asynchronous messages 279 * into signals. 280 * 281 * Params: 282 * message = the #GstMessage received 283 * data = user data 284 * 285 * Return: %TRUE 286 */ 287 public bool asyncSignalFunc(Message message, void* data) 288 { 289 return gst_bus_async_signal_func(gstBus, (message is null) ? null : message.getMessageStruct(), data) != 0; 290 } 291 292 /** 293 * Create watch for this bus. The GSource will be dispatched whenever 294 * a message is on the bus. After the GSource is dispatched, the 295 * message is popped off the bus and unreffed. 296 * 297 * Return: a #GSource that can be added to a mainloop. 298 */ 299 public Source createWatch() 300 { 301 auto p = gst_bus_create_watch(gstBus); 302 303 if(p is null) 304 { 305 return null; 306 } 307 308 return new Source(cast(GSource*) p, true); 309 } 310 311 /** 312 * Instructs GStreamer to stop emitting the "sync-message" signal for this bus. 313 * See gst_bus_enable_sync_message_emission() for more information. 314 * 315 * In the event that multiple pieces of code have called 316 * gst_bus_enable_sync_message_emission(), the sync-message emissions will only 317 * be stopped after all calls to gst_bus_enable_sync_message_emission() were 318 * "cancelled" by calling this function. In this way the semantics are exactly 319 * the same as gst_object_ref() that which calls enable should also call 320 * disable. 321 * 322 * MT safe. 323 */ 324 public void disableSyncMessageEmission() 325 { 326 gst_bus_disable_sync_message_emission(gstBus); 327 } 328 329 /** 330 * Instructs GStreamer to emit the "sync-message" signal after running the bus's 331 * sync handler. This function is here so that code can ensure that they can 332 * synchronously receive messages without having to affect what the bin's sync 333 * handler is. 334 * 335 * This function may be called multiple times. To clean up, the caller is 336 * responsible for calling gst_bus_disable_sync_message_emission() as many times 337 * as this function is called. 338 * 339 * While this function looks similar to gst_bus_add_signal_watch(), it is not 340 * exactly the same -- this function enables <emphasis>synchronous</emphasis> emission of 341 * signals when messages arrive; gst_bus_add_signal_watch() adds an idle callback 342 * to pop messages off the bus <emphasis>asynchronously</emphasis>. The sync-message signal 343 * comes from the thread of whatever object posted the message; the "message" 344 * signal is marshalled to the main thread via the main loop. 345 * 346 * MT safe. 347 */ 348 public void enableSyncMessageEmission() 349 { 350 gst_bus_enable_sync_message_emission(gstBus); 351 } 352 353 /** 354 * Check if there are pending messages on the bus that 355 * should be handled. 356 * 357 * Return: %TRUE if there are messages on the bus to be handled, %FALSE 358 * otherwise. 359 * 360 * MT safe. 361 */ 362 public bool havePending() 363 { 364 return gst_bus_have_pending(gstBus) != 0; 365 } 366 367 /** 368 * Peek the message on the top of the bus' queue. The message will remain 369 * on the bus' message queue. A reference is returned, and needs to be unreffed 370 * by the caller. 371 * 372 * Return: the #GstMessage that is on the 373 * bus, or %NULL if the bus is empty. 374 * 375 * MT safe. 376 */ 377 public Message peek() 378 { 379 auto p = gst_bus_peek(gstBus); 380 381 if(p is null) 382 { 383 return null; 384 } 385 386 return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true); 387 } 388 389 /** 390 * Poll the bus for messages. Will block while waiting for messages to come. 391 * You can specify a maximum time to poll with the @timeout parameter. If 392 * @timeout is negative, this function will block indefinitely. 393 * 394 * All messages not in @events will be popped off the bus and will be ignored. 395 * It is not possible to use message enums beyond #GST_MESSAGE_EXTENDED in the 396 * @events mask 397 * 398 * Because poll is implemented using the "message" signal enabled by 399 * gst_bus_add_signal_watch(), calling gst_bus_poll() will cause the "message" 400 * signal to be emitted for every message that poll sees. Thus a "message" 401 * signal handler will see the same messages that this function sees -- neither 402 * will steal messages from the other. 403 * 404 * This function will run a main loop from the default main context when 405 * polling. 406 * 407 * You should never use this function, since it is pure evil. This is 408 * especially true for GUI applications based on Gtk+ or Qt, but also for any 409 * other non-trivial application that uses the GLib main loop. As this function 410 * runs a GLib main loop, any callback attached to the default GLib main 411 * context may be invoked. This could be timeouts, GUI events, I/O events etc.; 412 * even if gst_bus_poll() is called with a 0 timeout. Any of these callbacks 413 * may do things you do not expect, e.g. destroy the main application window or 414 * some other resource; change other application state; display a dialog and 415 * run another main loop until the user clicks it away. In short, using this 416 * function may add a lot of complexity to your code through unexpected 417 * re-entrancy and unexpected changes to your application's state. 418 * 419 * For 0 timeouts use gst_bus_pop_filtered() instead of this function; for 420 * other short timeouts use gst_bus_timed_pop_filtered(); everything else is 421 * better handled by setting up an asynchronous bus watch and doing things 422 * from there. 423 * 424 * Params: 425 * events = a mask of #GstMessageType, representing the set of message types to 426 * poll for (note special handling of extended message types below) 427 * timeout = the poll timeout, as a #GstClockTime, or #GST_CLOCK_TIME_NONE to poll 428 * indefinitely. 429 * 430 * Return: the message that was received, 431 * or %NULL if the poll timed out. The message is taken from the 432 * bus and needs to be unreffed with gst_message_unref() after 433 * usage. 434 */ 435 public Message poll(GstMessageType events, GstClockTime timeout) 436 { 437 auto p = gst_bus_poll(gstBus, events, timeout); 438 439 if(p is null) 440 { 441 return null; 442 } 443 444 return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true); 445 } 446 447 /** 448 * Get a message from the bus. 449 * 450 * Return: the #GstMessage that is on the 451 * bus, or %NULL if the bus is empty. The message is taken from 452 * the bus and needs to be unreffed with gst_message_unref() after 453 * usage. 454 * 455 * MT safe. 456 */ 457 public Message pop() 458 { 459 auto p = gst_bus_pop(gstBus); 460 461 if(p is null) 462 { 463 return null; 464 } 465 466 return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true); 467 } 468 469 /** 470 * Get a message matching @type from the bus. Will discard all messages on 471 * the bus that do not match @type and that have been posted before the first 472 * message that does match @type. If there is no message matching @type on 473 * the bus, all messages will be discarded. It is not possible to use message 474 * enums beyond #GST_MESSAGE_EXTENDED in the @events mask. 475 * 476 * Params: 477 * types = message types to take into account 478 * 479 * Return: the next #GstMessage matching 480 * @type that is on the bus, or %NULL if the bus is empty or there 481 * is no message matching @type. The message is taken from the bus 482 * and needs to be unreffed with gst_message_unref() after usage. 483 * 484 * MT safe. 485 */ 486 public Message popFiltered(GstMessageType types) 487 { 488 auto p = gst_bus_pop_filtered(gstBus, types); 489 490 if(p is null) 491 { 492 return null; 493 } 494 495 return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true); 496 } 497 498 /** 499 * Post a message on the given bus. Ownership of the message 500 * is taken by the bus. 501 * 502 * Params: 503 * message = the #GstMessage to post 504 * 505 * Return: %TRUE if the message could be posted, %FALSE if the bus is flushing. 506 * 507 * MT safe. 508 */ 509 public bool post(Message message) 510 { 511 return gst_bus_post(gstBus, (message is null) ? null : message.getMessageStruct()) != 0; 512 } 513 514 /** 515 * Removes a signal watch previously added with gst_bus_add_signal_watch(). 516 * 517 * MT safe. 518 */ 519 public void removeSignalWatch() 520 { 521 gst_bus_remove_signal_watch(gstBus); 522 } 523 524 /** 525 * Removes an installed bus watch from @bus. 526 * 527 * Return: %TRUE on success or %FALSE if @bus has no event source. 528 * 529 * Since: 1.6 530 */ 531 public bool removeWatch() 532 { 533 return gst_bus_remove_watch(gstBus) != 0; 534 } 535 536 /** 537 * If @flushing, flush out and unref any messages queued in the bus. Releases 538 * references to the message origin objects. Will flush future messages until 539 * gst_bus_set_flushing() sets @flushing to %FALSE. 540 * 541 * MT safe. 542 * 543 * Params: 544 * flushing = whether or not to flush the bus 545 */ 546 public void setFlushing(bool flushing) 547 { 548 gst_bus_set_flushing(gstBus, flushing); 549 } 550 551 /** 552 * A helper GstBusSyncHandler that can be used to convert all synchronous 553 * messages into signals. 554 * 555 * Params: 556 * message = the #GstMessage received 557 * data = user data 558 * 559 * Return: GST_BUS_PASS 560 */ 561 public GstBusSyncReply syncSignalHandler(Message message, void* data) 562 { 563 return gst_bus_sync_signal_handler(gstBus, (message is null) ? null : message.getMessageStruct(), data); 564 } 565 566 /** 567 * Get a message from the bus, waiting up to the specified timeout. 568 * 569 * If @timeout is 0, this function behaves like gst_bus_pop(). If @timeout is 570 * #GST_CLOCK_TIME_NONE, this function will block forever until a message was 571 * posted on the bus. 572 * 573 * Params: 574 * timeout = a timeout 575 * 576 * Return: the #GstMessage that is on the 577 * bus after the specified timeout or %NULL if the bus is empty 578 * after the timeout expired. The message is taken from the bus 579 * and needs to be unreffed with gst_message_unref() after usage. 580 * 581 * MT safe. 582 */ 583 public Message timedPop(GstClockTime timeout) 584 { 585 auto p = gst_bus_timed_pop(gstBus, timeout); 586 587 if(p is null) 588 { 589 return null; 590 } 591 592 return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true); 593 } 594 595 /** 596 * Get a message from the bus whose type matches the message type mask @types, 597 * waiting up to the specified timeout (and discarding any messages that do not 598 * match the mask provided). 599 * 600 * If @timeout is 0, this function behaves like gst_bus_pop_filtered(). If 601 * @timeout is #GST_CLOCK_TIME_NONE, this function will block forever until a 602 * matching message was posted on the bus. 603 * 604 * Params: 605 * timeout = a timeout in nanoseconds, or GST_CLOCK_TIME_NONE to wait forever 606 * types = message types to take into account, GST_MESSAGE_ANY for any type 607 * 608 * Return: a #GstMessage matching the 609 * filter in @types, or %NULL if no matching message was found on 610 * the bus until the timeout expired. The message is taken from 611 * the bus and needs to be unreffed with gst_message_unref() after 612 * usage. 613 * 614 * MT safe. 615 */ 616 public Message timedPopFiltered(GstClockTime timeout, GstMessageType types) 617 { 618 auto p = gst_bus_timed_pop_filtered(gstBus, timeout, types); 619 620 if(p is null) 621 { 622 return null; 623 } 624 625 return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true); 626 } 627 628 protected class OnMessageDelegateWrapper 629 { 630 void delegate(Message, Bus) dlg; 631 gulong handlerId; 632 ConnectFlags flags; 633 this(void delegate(Message, Bus) dlg, gulong handlerId, ConnectFlags flags) 634 { 635 this.dlg = dlg; 636 this.handlerId = handlerId; 637 this.flags = flags; 638 } 639 } 640 protected OnMessageDelegateWrapper[] onMessageListeners; 641 642 /** 643 * A message has been posted on the bus. This signal is emitted from a 644 * GSource added to the mainloop. this signal will only be emitted when 645 * there is a mainloop running. 646 * 647 * Params: 648 * message = the message that has been posted asynchronously 649 */ 650 gulong addOnMessage(void delegate(Message, Bus) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 651 { 652 onMessageListeners ~= new OnMessageDelegateWrapper(dlg, 0, connectFlags); 653 onMessageListeners[onMessageListeners.length - 1].handlerId = Signals.connectData( 654 this, 655 "message", 656 cast(GCallback)&callBackMessage, 657 cast(void*)onMessageListeners[onMessageListeners.length - 1], 658 cast(GClosureNotify)&callBackMessageDestroy, 659 connectFlags); 660 return onMessageListeners[onMessageListeners.length - 1].handlerId; 661 } 662 663 extern(C) static void callBackMessage(GstBus* busStruct, GstMessage* message,OnMessageDelegateWrapper wrapper) 664 { 665 wrapper.dlg(ObjectG.getDObject!(Message)(message), wrapper.outer); 666 } 667 668 extern(C) static void callBackMessageDestroy(OnMessageDelegateWrapper wrapper, GClosure* closure) 669 { 670 wrapper.outer.internalRemoveOnMessage(wrapper); 671 } 672 673 protected void internalRemoveOnMessage(OnMessageDelegateWrapper source) 674 { 675 foreach(index, wrapper; onMessageListeners) 676 { 677 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 678 { 679 onMessageListeners[index] = null; 680 onMessageListeners = std.algorithm.remove(onMessageListeners, index); 681 break; 682 } 683 } 684 } 685 686 687 protected class OnSyncMessageDelegateWrapper 688 { 689 void delegate(Message, Bus) dlg; 690 gulong handlerId; 691 ConnectFlags flags; 692 this(void delegate(Message, Bus) dlg, gulong handlerId, ConnectFlags flags) 693 { 694 this.dlg = dlg; 695 this.handlerId = handlerId; 696 this.flags = flags; 697 } 698 } 699 protected OnSyncMessageDelegateWrapper[] onSyncMessageListeners; 700 701 /** 702 * A message has been posted on the bus. This signal is emitted from the 703 * thread that posted the message so one has to be careful with locking. 704 * 705 * This signal will not be emitted by default, you have to call 706 * gst_bus_enable_sync_message_emission() before. 707 * 708 * Params: 709 * message = the message that has been posted synchronously 710 */ 711 gulong addOnSyncMessage(void delegate(Message, Bus) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 712 { 713 onSyncMessageListeners ~= new OnSyncMessageDelegateWrapper(dlg, 0, connectFlags); 714 onSyncMessageListeners[onSyncMessageListeners.length - 1].handlerId = Signals.connectData( 715 this, 716 "sync-message", 717 cast(GCallback)&callBackSyncMessage, 718 cast(void*)onSyncMessageListeners[onSyncMessageListeners.length - 1], 719 cast(GClosureNotify)&callBackSyncMessageDestroy, 720 connectFlags); 721 return onSyncMessageListeners[onSyncMessageListeners.length - 1].handlerId; 722 } 723 724 extern(C) static void callBackSyncMessage(GstBus* busStruct, GstMessage* message,OnSyncMessageDelegateWrapper wrapper) 725 { 726 wrapper.dlg(ObjectG.getDObject!(Message)(message), wrapper.outer); 727 } 728 729 extern(C) static void callBackSyncMessageDestroy(OnSyncMessageDelegateWrapper wrapper, GClosure* closure) 730 { 731 wrapper.outer.internalRemoveOnSyncMessage(wrapper); 732 } 733 734 protected void internalRemoveOnSyncMessage(OnSyncMessageDelegateWrapper source) 735 { 736 foreach(index, wrapper; onSyncMessageListeners) 737 { 738 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 739 { 740 onSyncMessageListeners[index] = null; 741 onSyncMessageListeners = std.algorithm.remove(onSyncMessageListeners, index); 742 break; 743 } 744 } 745 } 746 747 }