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