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 		static OnActivateCurrentDelegateWrapper[] listeners;
364 		void delegate(bool, MenuShell) dlg;
365 		gulong handlerId;
366 		
367 		this(void delegate(bool, MenuShell) dlg)
368 		{
369 			this.dlg = dlg;
370 			this.listeners ~= this;
371 		}
372 		
373 		void remove(OnActivateCurrentDelegateWrapper source)
374 		{
375 			foreach(index, wrapper; listeners)
376 			{
377 				if (wrapper.handlerId == source.handlerId)
378 				{
379 					listeners[index] = null;
380 					listeners = std.algorithm.remove(listeners, index);
381 					break;
382 				}
383 			}
384 		}
385 	}
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 		static OnCancelDelegateWrapper[] listeners;
420 		void delegate(MenuShell) dlg;
421 		gulong handlerId;
422 		
423 		this(void delegate(MenuShell) dlg)
424 		{
425 			this.dlg = dlg;
426 			this.listeners ~= this;
427 		}
428 		
429 		void remove(OnCancelDelegateWrapper source)
430 		{
431 			foreach(index, wrapper; listeners)
432 			{
433 				if (wrapper.handlerId == source.handlerId)
434 				{
435 					listeners[index] = null;
436 					listeners = std.algorithm.remove(listeners, index);
437 					break;
438 				}
439 			}
440 		}
441 	}
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 		static OnCycleFocusDelegateWrapper[] listeners;
473 		void delegate(GtkDirectionType, MenuShell) dlg;
474 		gulong handlerId;
475 		
476 		this(void delegate(GtkDirectionType, MenuShell) dlg)
477 		{
478 			this.dlg = dlg;
479 			this.listeners ~= this;
480 		}
481 		
482 		void remove(OnCycleFocusDelegateWrapper source)
483 		{
484 			foreach(index, wrapper; listeners)
485 			{
486 				if (wrapper.handlerId == source.handlerId)
487 				{
488 					listeners[index] = null;
489 					listeners = std.algorithm.remove(listeners, index);
490 					break;
491 				}
492 			}
493 		}
494 	}
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 		static OnDeactivateDelegateWrapper[] listeners;
529 		void delegate(MenuShell) dlg;
530 		gulong handlerId;
531 		
532 		this(void delegate(MenuShell) dlg)
533 		{
534 			this.dlg = dlg;
535 			this.listeners ~= this;
536 		}
537 		
538 		void remove(OnDeactivateDelegateWrapper source)
539 		{
540 			foreach(index, wrapper; listeners)
541 			{
542 				if (wrapper.handlerId == source.handlerId)
543 				{
544 					listeners[index] = null;
545 					listeners = std.algorithm.remove(listeners, index);
546 					break;
547 				}
548 			}
549 		}
550 	}
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 		static OnInsertDelegateWrapper[] listeners;
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 			this.listeners ~= this;
588 		}
589 		
590 		void remove(OnInsertDelegateWrapper source)
591 		{
592 			foreach(index, wrapper; listeners)
593 			{
594 				if (wrapper.handlerId == source.handlerId)
595 				{
596 					listeners[index] = null;
597 					listeners = std.algorithm.remove(listeners, index);
598 					break;
599 				}
600 			}
601 		}
602 	}
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 		static OnMoveCurrentDelegateWrapper[] listeners;
644 		void delegate(GtkMenuDirectionType, MenuShell) dlg;
645 		gulong handlerId;
646 		
647 		this(void delegate(GtkMenuDirectionType, MenuShell) dlg)
648 		{
649 			this.dlg = dlg;
650 			this.listeners ~= this;
651 		}
652 		
653 		void remove(OnMoveCurrentDelegateWrapper source)
654 		{
655 			foreach(index, wrapper; listeners)
656 			{
657 				if (wrapper.handlerId == source.handlerId)
658 				{
659 					listeners[index] = null;
660 					listeners = std.algorithm.remove(listeners, index);
661 					break;
662 				}
663 			}
664 		}
665 	}
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 		static OnMoveSelectedDelegateWrapper[] listeners;
700 		bool delegate(int, MenuShell) dlg;
701 		gulong handlerId;
702 		
703 		this(bool delegate(int, MenuShell) dlg)
704 		{
705 			this.dlg = dlg;
706 			this.listeners ~= this;
707 		}
708 		
709 		void remove(OnMoveSelectedDelegateWrapper source)
710 		{
711 			foreach(index, wrapper; listeners)
712 			{
713 				if (wrapper.handlerId == source.handlerId)
714 				{
715 					listeners[index] = null;
716 					listeners = std.algorithm.remove(listeners, index);
717 					break;
718 				}
719 			}
720 		}
721 	}
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 		static OnSelectionDoneDelegateWrapper[] listeners;
760 		void delegate(MenuShell) dlg;
761 		gulong handlerId;
762 		
763 		this(void delegate(MenuShell) dlg)
764 		{
765 			this.dlg = dlg;
766 			this.listeners ~= this;
767 		}
768 		
769 		void remove(OnSelectionDoneDelegateWrapper source)
770 		{
771 			foreach(index, wrapper; listeners)
772 			{
773 				if (wrapper.handlerId == source.handlerId)
774 				{
775 					listeners[index] = null;
776 					listeners = std.algorithm.remove(listeners, index);
777 					break;
778 				}
779 			}
780 		}
781 	}
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 }