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