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