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