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