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 gtk.MenuShell; 26 27 private import gio.MenuModel; 28 private import glib.Str; 29 private import gobject.ObjectG; 30 private import gobject.Signals; 31 private import gtk.Container; 32 private import gtk.MenuItem; 33 private import gtk.Widget; 34 private import gtkc.gtk; 35 public import gtkc.gtktypes; 36 private import std.algorithm; 37 38 39 /** 40 * A #GtkMenuShell is the abstract base class used to derive the 41 * #GtkMenu and #GtkMenuBar subclasses. 42 * 43 * A #GtkMenuShell is a container of #GtkMenuItem objects arranged 44 * in a list which can be navigated, selected, and activated by the 45 * user to perform application functions. A #GtkMenuItem can have a 46 * submenu associated with it, allowing for nested hierarchical menus. 47 * 48 * # Terminology 49 * 50 * A menu item can be “selected”, this means that it is displayed 51 * in the prelight state, and if it has a submenu, that submenu 52 * will be popped up. 53 * 54 * A menu is “active” when it is visible onscreen and the user 55 * is selecting from it. A menubar is not active until the user 56 * clicks on one of its menuitems. When a menu is active, 57 * passing the mouse over a submenu will pop it up. 58 * 59 * There is also is a concept of the current menu and a current 60 * menu item. The current menu item is the selected menu item 61 * that is furthest down in the hierarchy. (Every active menu shell 62 * does not necessarily contain a selected menu item, but if 63 * it does, then the parent menu shell must also contain 64 * a selected menu item.) The current menu is the menu that 65 * contains the current menu item. It will always have a GTK 66 * grab and receive all key presses. 67 */ 68 public class MenuShell : Container 69 { 70 /** the main Gtk struct */ 71 protected GtkMenuShell* gtkMenuShell; 72 73 /** Get the main Gtk struct */ 74 public GtkMenuShell* getMenuShellStruct(bool transferOwnership = false) 75 { 76 if (transferOwnership) 77 ownedRef = false; 78 return gtkMenuShell; 79 } 80 81 /** the main Gtk struct as a void* */ 82 protected override void* getStruct() 83 { 84 return cast(void*)gtkMenuShell; 85 } 86 87 protected override void setStruct(GObject* obj) 88 { 89 gtkMenuShell = cast(GtkMenuShell*)obj; 90 super.setStruct(obj); 91 } 92 93 /** 94 * Sets our main struct and passes it to the parent class. 95 */ 96 public this (GtkMenuShell* gtkMenuShell, bool ownedRef = false) 97 { 98 this.gtkMenuShell = gtkMenuShell; 99 super(cast(GtkContainer*)gtkMenuShell, ownedRef); 100 } 101 102 103 /** */ 104 public static GType getType() 105 { 106 return gtk_menu_shell_get_type(); 107 } 108 109 /** 110 * Activates the menu item within the menu shell. 111 * 112 * Params: 113 * menuItem = the #GtkMenuItem to activate 114 * forceDeactivate = if %TRUE, force the deactivation of the 115 * menu shell after the menu item is activated 116 */ 117 public void activateItem(Widget menuItem, bool forceDeactivate) 118 { 119 gtk_menu_shell_activate_item(gtkMenuShell, (menuItem is null) ? null : menuItem.getWidgetStruct(), forceDeactivate); 120 } 121 122 /** 123 * Adds a new #GtkMenuItem to the end of the menu shell's 124 * item list. 125 * 126 * Params: 127 * child = The #GtkMenuItem to add 128 */ 129 public void append(MenuItem child) 130 { 131 gtk_menu_shell_append(gtkMenuShell, (child is null) ? null : cast(GtkWidget*)child.getMenuItemStruct()); 132 } 133 134 /** 135 * Establishes a binding between a #GtkMenuShell and a #GMenuModel. 136 * 137 * The contents of @shell are removed and then refilled with menu items 138 * according to @model. When @model changes, @shell is updated. 139 * Calling this function twice on @shell with different @model will 140 * cause the first binding to be replaced with a binding to the new 141 * model. If @model is %NULL then any previous binding is undone and 142 * all children are removed. 143 * 144 * @with_separators determines if toplevel items (eg: sections) have 145 * separators inserted between them. This is typically desired for 146 * menus but doesn’t make sense for menubars. 147 * 148 * If @action_namespace is non-%NULL then the effect is as if all 149 * actions mentioned in the @model have their names prefixed with the 150 * namespace, plus a dot. For example, if the action “quit” is 151 * mentioned and @action_namespace is “app” then the effective action 152 * name is “app.quit”. 153 * 154 * This function uses #GtkActionable to define the action name and 155 * target values on the created menu items. If you want to use an 156 * action group other than “app” and “win”, or if you want to use a 157 * #GtkMenuShell outside of a #GtkApplicationWindow, then you will need 158 * to attach your own action group to the widget hierarchy using 159 * gtk_widget_insert_action_group(). As an example, if you created a 160 * group with a “quit” action and inserted it with the name “mygroup” 161 * then you would use the action name “mygroup.quit” in your 162 * #GMenuModel. 163 * 164 * For most cases you are probably better off using 165 * gtk_menu_new_from_model() or gtk_menu_bar_new_from_model() or just 166 * directly passing the #GMenuModel to gtk_application_set_app_menu() or 167 * gtk_application_set_menubar(). 168 * 169 * Params: 170 * model = the #GMenuModel to bind to or %NULL to remove 171 * binding 172 * actionNamespace = the namespace for actions in @model 173 * withSeparators = %TRUE if toplevel items in @shell should have 174 * separators between them 175 * 176 * Since: 3.6 177 */ 178 public void bindModel(MenuModel model, string actionNamespace, bool withSeparators) 179 { 180 gtk_menu_shell_bind_model(gtkMenuShell, (model is null) ? null : model.getMenuModelStruct(), Str.toStringz(actionNamespace), withSeparators); 181 } 182 183 /** 184 * Cancels the selection within the menu shell. 185 * 186 * Since: 2.4 187 */ 188 public void cancel() 189 { 190 gtk_menu_shell_cancel(gtkMenuShell); 191 } 192 193 /** 194 * Deactivates the menu shell. 195 * 196 * Typically this results in the menu shell being erased 197 * from the screen. 198 */ 199 public void deactivate() 200 { 201 gtk_menu_shell_deactivate(gtkMenuShell); 202 } 203 204 /** 205 * Deselects the currently selected item from the menu shell, 206 * if any. 207 */ 208 public void deselect() 209 { 210 gtk_menu_shell_deselect(gtkMenuShell); 211 } 212 213 /** 214 * Gets the parent menu shell. 215 * 216 * The parent menu shell of a submenu is the #GtkMenu or #GtkMenuBar 217 * from which it was opened up. 218 * 219 * Returns: the parent #GtkMenuShell 220 * 221 * Since: 3.0 222 */ 223 public Widget getParentShell() 224 { 225 auto p = gtk_menu_shell_get_parent_shell(gtkMenuShell); 226 227 if(p is null) 228 { 229 return null; 230 } 231 232 return ObjectG.getDObject!(Widget)(cast(GtkWidget*) p); 233 } 234 235 /** 236 * Gets the currently selected item. 237 * 238 * Returns: the currently selected item 239 * 240 * Since: 3.0 241 */ 242 public Widget getSelectedItem() 243 { 244 auto p = gtk_menu_shell_get_selected_item(gtkMenuShell); 245 246 if(p is null) 247 { 248 return null; 249 } 250 251 return ObjectG.getDObject!(Widget)(cast(GtkWidget*) p); 252 } 253 254 /** 255 * Returns %TRUE if the menu shell will take the keyboard focus on popup. 256 * 257 * Returns: %TRUE if the menu shell will take the keyboard focus on popup. 258 * 259 * Since: 2.8 260 */ 261 public bool getTakeFocus() 262 { 263 return gtk_menu_shell_get_take_focus(gtkMenuShell) != 0; 264 } 265 266 /** 267 * Adds a new #GtkMenuItem to the menu shell’s item list 268 * at the position indicated by @position. 269 * 270 * Params: 271 * child = The #GtkMenuItem to add 272 * position = The position in the item list where @child 273 * is added. Positions are numbered from 0 to n-1 274 */ 275 public void insert(Widget child, int position) 276 { 277 gtk_menu_shell_insert(gtkMenuShell, (child is null) ? null : child.getWidgetStruct(), position); 278 } 279 280 /** 281 * Adds a new #GtkMenuItem to the beginning of the menu shell's 282 * item list. 283 * 284 * Params: 285 * child = The #GtkMenuItem to add 286 */ 287 public void prepend(Widget child) 288 { 289 gtk_menu_shell_prepend(gtkMenuShell, (child is null) ? null : child.getWidgetStruct()); 290 } 291 292 /** 293 * Select the first visible or selectable child of the menu shell; 294 * don’t select tearoff items unless the only item is a tearoff 295 * item. 296 * 297 * Params: 298 * searchSensitive = if %TRUE, search for the first selectable 299 * menu item, otherwise select nothing if 300 * the first item isn’t sensitive. This 301 * should be %FALSE if the menu is being 302 * popped up initially. 303 * 304 * Since: 2.2 305 */ 306 public void selectFirst(bool searchSensitive) 307 { 308 gtk_menu_shell_select_first(gtkMenuShell, searchSensitive); 309 } 310 311 /** 312 * Selects the menu item from the menu shell. 313 * 314 * Params: 315 * menuItem = The #GtkMenuItem to select 316 */ 317 public void selectItem(Widget menuItem) 318 { 319 gtk_menu_shell_select_item(gtkMenuShell, (menuItem is null) ? null : menuItem.getWidgetStruct()); 320 } 321 322 /** 323 * If @take_focus is %TRUE (the default) the menu shell will take 324 * the keyboard focus so that it will receive all keyboard events 325 * which is needed to enable keyboard navigation in menus. 326 * 327 * Setting @take_focus to %FALSE is useful only for special applications 328 * like virtual keyboard implementations which should not take keyboard 329 * focus. 330 * 331 * The @take_focus state of a menu or menu bar is automatically 332 * propagated to submenus whenever a submenu is popped up, so you 333 * don’t have to worry about recursively setting it for your entire 334 * menu hierarchy. Only when programmatically picking a submenu and 335 * popping it up manually, the @take_focus property of the submenu 336 * needs to be set explicitly. 337 * 338 * Note that setting it to %FALSE has side-effects: 339 * 340 * If the focus is in some other app, it keeps the focus and keynav in 341 * the menu doesn’t work. Consequently, keynav on the menu will only 342 * work if the focus is on some toplevel owned by the onscreen keyboard. 343 * 344 * To avoid confusing the user, menus with @take_focus set to %FALSE 345 * should not display mnemonics or accelerators, since it cannot be 346 * guaranteed that they will work. 347 * 348 * See also gdk_keyboard_grab() 349 * 350 * Params: 351 * takeFocus = %TRUE if the menu shell should take the keyboard 352 * focus on popup 353 * 354 * Since: 2.8 355 */ 356 public void setTakeFocus(bool takeFocus) 357 { 358 gtk_menu_shell_set_take_focus(gtkMenuShell, takeFocus); 359 } 360 361 protected class OnActivateCurrentDelegateWrapper 362 { 363 void delegate(bool, MenuShell) dlg; 364 gulong handlerId; 365 366 this(void delegate(bool, MenuShell) dlg) 367 { 368 this.dlg = dlg; 369 onActivateCurrentListeners ~= this; 370 } 371 372 void remove(OnActivateCurrentDelegateWrapper source) 373 { 374 foreach(index, wrapper; onActivateCurrentListeners) 375 { 376 if (wrapper.handlerId == source.handlerId) 377 { 378 onActivateCurrentListeners[index] = null; 379 onActivateCurrentListeners = std.algorithm.remove(onActivateCurrentListeners, index); 380 break; 381 } 382 } 383 } 384 } 385 OnActivateCurrentDelegateWrapper[] onActivateCurrentListeners; 386 387 /** 388 * An action signal that activates the current menu item within 389 * the menu shell. 390 * 391 * Params: 392 * forceHide = if %TRUE, hide the menu after activating the menu item 393 */ 394 gulong addOnActivateCurrent(void delegate(bool, MenuShell) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 395 { 396 auto wrapper = new OnActivateCurrentDelegateWrapper(dlg); 397 wrapper.handlerId = Signals.connectData( 398 this, 399 "activate-current", 400 cast(GCallback)&callBackActivateCurrent, 401 cast(void*)wrapper, 402 cast(GClosureNotify)&callBackActivateCurrentDestroy, 403 connectFlags); 404 return wrapper.handlerId; 405 } 406 407 extern(C) static void callBackActivateCurrent(GtkMenuShell* menushellStruct, bool forceHide, OnActivateCurrentDelegateWrapper wrapper) 408 { 409 wrapper.dlg(forceHide, wrapper.outer); 410 } 411 412 extern(C) static void callBackActivateCurrentDestroy(OnActivateCurrentDelegateWrapper wrapper, GClosure* closure) 413 { 414 wrapper.remove(wrapper); 415 } 416 417 protected class OnCancelDelegateWrapper 418 { 419 void delegate(MenuShell) dlg; 420 gulong handlerId; 421 422 this(void delegate(MenuShell) dlg) 423 { 424 this.dlg = dlg; 425 onCancelListeners ~= this; 426 } 427 428 void remove(OnCancelDelegateWrapper source) 429 { 430 foreach(index, wrapper; onCancelListeners) 431 { 432 if (wrapper.handlerId == source.handlerId) 433 { 434 onCancelListeners[index] = null; 435 onCancelListeners = std.algorithm.remove(onCancelListeners, index); 436 break; 437 } 438 } 439 } 440 } 441 OnCancelDelegateWrapper[] onCancelListeners; 442 443 /** 444 * An action signal which cancels the selection within the menu shell. 445 * Causes the #GtkMenuShell::selection-done signal to be emitted. 446 */ 447 gulong addOnCancel(void delegate(MenuShell) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 448 { 449 auto wrapper = new OnCancelDelegateWrapper(dlg); 450 wrapper.handlerId = Signals.connectData( 451 this, 452 "cancel", 453 cast(GCallback)&callBackCancel, 454 cast(void*)wrapper, 455 cast(GClosureNotify)&callBackCancelDestroy, 456 connectFlags); 457 return wrapper.handlerId; 458 } 459 460 extern(C) static void callBackCancel(GtkMenuShell* menushellStruct, OnCancelDelegateWrapper wrapper) 461 { 462 wrapper.dlg(wrapper.outer); 463 } 464 465 extern(C) static void callBackCancelDestroy(OnCancelDelegateWrapper wrapper, GClosure* closure) 466 { 467 wrapper.remove(wrapper); 468 } 469 470 protected class OnCycleFocusDelegateWrapper 471 { 472 void delegate(GtkDirectionType, MenuShell) dlg; 473 gulong handlerId; 474 475 this(void delegate(GtkDirectionType, MenuShell) dlg) 476 { 477 this.dlg = dlg; 478 onCycleFocusListeners ~= this; 479 } 480 481 void remove(OnCycleFocusDelegateWrapper source) 482 { 483 foreach(index, wrapper; onCycleFocusListeners) 484 { 485 if (wrapper.handlerId == source.handlerId) 486 { 487 onCycleFocusListeners[index] = null; 488 onCycleFocusListeners = std.algorithm.remove(onCycleFocusListeners, index); 489 break; 490 } 491 } 492 } 493 } 494 OnCycleFocusDelegateWrapper[] onCycleFocusListeners; 495 496 /** 497 * A keybinding signal which moves the focus in the 498 * given @direction. 499 * 500 * Params: 501 * direction = the direction to cycle in 502 */ 503 gulong addOnCycleFocus(void delegate(GtkDirectionType, MenuShell) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 504 { 505 auto wrapper = new OnCycleFocusDelegateWrapper(dlg); 506 wrapper.handlerId = Signals.connectData( 507 this, 508 "cycle-focus", 509 cast(GCallback)&callBackCycleFocus, 510 cast(void*)wrapper, 511 cast(GClosureNotify)&callBackCycleFocusDestroy, 512 connectFlags); 513 return wrapper.handlerId; 514 } 515 516 extern(C) static void callBackCycleFocus(GtkMenuShell* menushellStruct, GtkDirectionType direction, OnCycleFocusDelegateWrapper wrapper) 517 { 518 wrapper.dlg(direction, wrapper.outer); 519 } 520 521 extern(C) static void callBackCycleFocusDestroy(OnCycleFocusDelegateWrapper wrapper, GClosure* closure) 522 { 523 wrapper.remove(wrapper); 524 } 525 526 protected class OnDeactivateDelegateWrapper 527 { 528 void delegate(MenuShell) dlg; 529 gulong handlerId; 530 531 this(void delegate(MenuShell) dlg) 532 { 533 this.dlg = dlg; 534 onDeactivateListeners ~= this; 535 } 536 537 void remove(OnDeactivateDelegateWrapper source) 538 { 539 foreach(index, wrapper; onDeactivateListeners) 540 { 541 if (wrapper.handlerId == source.handlerId) 542 { 543 onDeactivateListeners[index] = null; 544 onDeactivateListeners = std.algorithm.remove(onDeactivateListeners, index); 545 break; 546 } 547 } 548 } 549 } 550 OnDeactivateDelegateWrapper[] onDeactivateListeners; 551 552 /** 553 * This signal is emitted when a menu shell is deactivated. 554 */ 555 gulong addOnDeactivate(void delegate(MenuShell) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 556 { 557 auto wrapper = new OnDeactivateDelegateWrapper(dlg); 558 wrapper.handlerId = Signals.connectData( 559 this, 560 "deactivate", 561 cast(GCallback)&callBackDeactivate, 562 cast(void*)wrapper, 563 cast(GClosureNotify)&callBackDeactivateDestroy, 564 connectFlags); 565 return wrapper.handlerId; 566 } 567 568 extern(C) static void callBackDeactivate(GtkMenuShell* menushellStruct, OnDeactivateDelegateWrapper wrapper) 569 { 570 wrapper.dlg(wrapper.outer); 571 } 572 573 extern(C) static void callBackDeactivateDestroy(OnDeactivateDelegateWrapper wrapper, GClosure* closure) 574 { 575 wrapper.remove(wrapper); 576 } 577 578 protected class OnInsertDelegateWrapper 579 { 580 void delegate(Widget, int, MenuShell) dlg; 581 gulong handlerId; 582 583 this(void delegate(Widget, int, MenuShell) dlg) 584 { 585 this.dlg = dlg; 586 onInsertListeners ~= this; 587 } 588 589 void remove(OnInsertDelegateWrapper source) 590 { 591 foreach(index, wrapper; onInsertListeners) 592 { 593 if (wrapper.handlerId == source.handlerId) 594 { 595 onInsertListeners[index] = null; 596 onInsertListeners = std.algorithm.remove(onInsertListeners, index); 597 break; 598 } 599 } 600 } 601 } 602 OnInsertDelegateWrapper[] onInsertListeners; 603 604 /** 605 * The ::insert signal is emitted when a new #GtkMenuItem is added to 606 * a #GtkMenuShell. A separate signal is used instead of 607 * GtkContainer::add because of the need for an additional position 608 * parameter. 609 * 610 * The inverse of this signal is the GtkContainer::removed signal. 611 * 612 * Params: 613 * child = the #GtkMenuItem that is being inserted 614 * position = the position at which the insert occurs 615 * 616 * Since: 3.2 617 */ 618 gulong addOnInsert(void delegate(Widget, int, MenuShell) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 619 { 620 auto wrapper = new OnInsertDelegateWrapper(dlg); 621 wrapper.handlerId = Signals.connectData( 622 this, 623 "insert", 624 cast(GCallback)&callBackInsert, 625 cast(void*)wrapper, 626 cast(GClosureNotify)&callBackInsertDestroy, 627 connectFlags); 628 return wrapper.handlerId; 629 } 630 631 extern(C) static void callBackInsert(GtkMenuShell* menushellStruct, GtkWidget* child, int position, OnInsertDelegateWrapper wrapper) 632 { 633 wrapper.dlg(ObjectG.getDObject!(Widget)(child), position, wrapper.outer); 634 } 635 636 extern(C) static void callBackInsertDestroy(OnInsertDelegateWrapper wrapper, GClosure* closure) 637 { 638 wrapper.remove(wrapper); 639 } 640 641 protected class OnMoveCurrentDelegateWrapper 642 { 643 void delegate(GtkMenuDirectionType, MenuShell) dlg; 644 gulong handlerId; 645 646 this(void delegate(GtkMenuDirectionType, MenuShell) dlg) 647 { 648 this.dlg = dlg; 649 onMoveCurrentListeners ~= this; 650 } 651 652 void remove(OnMoveCurrentDelegateWrapper source) 653 { 654 foreach(index, wrapper; onMoveCurrentListeners) 655 { 656 if (wrapper.handlerId == source.handlerId) 657 { 658 onMoveCurrentListeners[index] = null; 659 onMoveCurrentListeners = std.algorithm.remove(onMoveCurrentListeners, index); 660 break; 661 } 662 } 663 } 664 } 665 OnMoveCurrentDelegateWrapper[] onMoveCurrentListeners; 666 667 /** 668 * An keybinding signal which moves the current menu item 669 * in the direction specified by @direction. 670 * 671 * Params: 672 * direction = the direction to move 673 */ 674 gulong addOnMoveCurrent(void delegate(GtkMenuDirectionType, MenuShell) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 675 { 676 auto wrapper = new OnMoveCurrentDelegateWrapper(dlg); 677 wrapper.handlerId = Signals.connectData( 678 this, 679 "move-current", 680 cast(GCallback)&callBackMoveCurrent, 681 cast(void*)wrapper, 682 cast(GClosureNotify)&callBackMoveCurrentDestroy, 683 connectFlags); 684 return wrapper.handlerId; 685 } 686 687 extern(C) static void callBackMoveCurrent(GtkMenuShell* menushellStruct, GtkMenuDirectionType direction, OnMoveCurrentDelegateWrapper wrapper) 688 { 689 wrapper.dlg(direction, wrapper.outer); 690 } 691 692 extern(C) static void callBackMoveCurrentDestroy(OnMoveCurrentDelegateWrapper wrapper, GClosure* closure) 693 { 694 wrapper.remove(wrapper); 695 } 696 697 protected class OnMoveSelectedDelegateWrapper 698 { 699 bool delegate(int, MenuShell) dlg; 700 gulong handlerId; 701 702 this(bool delegate(int, MenuShell) dlg) 703 { 704 this.dlg = dlg; 705 onMoveSelectedListeners ~= this; 706 } 707 708 void remove(OnMoveSelectedDelegateWrapper source) 709 { 710 foreach(index, wrapper; onMoveSelectedListeners) 711 { 712 if (wrapper.handlerId == source.handlerId) 713 { 714 onMoveSelectedListeners[index] = null; 715 onMoveSelectedListeners = std.algorithm.remove(onMoveSelectedListeners, index); 716 break; 717 } 718 } 719 } 720 } 721 OnMoveSelectedDelegateWrapper[] onMoveSelectedListeners; 722 723 /** 724 * The ::move-selected signal is emitted to move the selection to 725 * another item. 726 * 727 * Params: 728 * distance = +1 to move to the next item, -1 to move to the previous 729 * 730 * Returns: %TRUE to stop the signal emission, %FALSE to continue 731 * 732 * Since: 2.12 733 */ 734 gulong addOnMoveSelected(bool delegate(int, MenuShell) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 735 { 736 auto wrapper = new OnMoveSelectedDelegateWrapper(dlg); 737 wrapper.handlerId = Signals.connectData( 738 this, 739 "move-selected", 740 cast(GCallback)&callBackMoveSelected, 741 cast(void*)wrapper, 742 cast(GClosureNotify)&callBackMoveSelectedDestroy, 743 connectFlags); 744 return wrapper.handlerId; 745 } 746 747 extern(C) static int callBackMoveSelected(GtkMenuShell* menushellStruct, int distance, OnMoveSelectedDelegateWrapper wrapper) 748 { 749 return wrapper.dlg(distance, wrapper.outer); 750 } 751 752 extern(C) static void callBackMoveSelectedDestroy(OnMoveSelectedDelegateWrapper wrapper, GClosure* closure) 753 { 754 wrapper.remove(wrapper); 755 } 756 757 protected class OnSelectionDoneDelegateWrapper 758 { 759 void delegate(MenuShell) dlg; 760 gulong handlerId; 761 762 this(void delegate(MenuShell) dlg) 763 { 764 this.dlg = dlg; 765 onSelectionDoneListeners ~= this; 766 } 767 768 void remove(OnSelectionDoneDelegateWrapper source) 769 { 770 foreach(index, wrapper; onSelectionDoneListeners) 771 { 772 if (wrapper.handlerId == source.handlerId) 773 { 774 onSelectionDoneListeners[index] = null; 775 onSelectionDoneListeners = std.algorithm.remove(onSelectionDoneListeners, index); 776 break; 777 } 778 } 779 } 780 } 781 OnSelectionDoneDelegateWrapper[] onSelectionDoneListeners; 782 783 /** 784 * This signal is emitted when a selection has been 785 * completed within a menu shell. 786 */ 787 gulong addOnSelectionDone(void delegate(MenuShell) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 788 { 789 auto wrapper = new OnSelectionDoneDelegateWrapper(dlg); 790 wrapper.handlerId = Signals.connectData( 791 this, 792 "selection-done", 793 cast(GCallback)&callBackSelectionDone, 794 cast(void*)wrapper, 795 cast(GClosureNotify)&callBackSelectionDoneDestroy, 796 connectFlags); 797 return wrapper.handlerId; 798 } 799 800 extern(C) static void callBackSelectionDone(GtkMenuShell* menushellStruct, OnSelectionDoneDelegateWrapper wrapper) 801 { 802 wrapper.dlg(wrapper.outer); 803 } 804 805 extern(C) static void callBackSelectionDoneDestroy(OnSelectionDoneDelegateWrapper wrapper, GClosure* closure) 806 { 807 wrapper.remove(wrapper); 808 } 809 }