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.IMContext;
26 
27 private import gdk.Window;
28 private import glib.Str;
29 private import gobject.ObjectG;
30 private import gobject.Signals;
31 private import gtkc.gtk;
32 public  import gtkc.gtktypes;
33 private import pango.PgAttributeList;
34 private import std.algorithm;
35 
36 
37 /**
38  * #GtkIMContext defines the interface for GTK+ input methods. An input method
39  * is used by GTK+ text input widgets like #GtkEntry to map from key events to
40  * Unicode character strings.
41  * 
42  * The default input method can be set programmatically via the
43  * #GtkSettings:gtk-im-module GtkSettings property. Alternatively, you may set
44  * the GTK_IM_MODULE environment variable as documented in
45  * [Running GTK+ Applications][gtk-running].
46  * 
47  * The #GtkEntry #GtkEntry:im-module and #GtkTextView #GtkTextView:im-module
48  * properties may also be used to set input methods for specific widget
49  * instances. For instance, a certain entry widget might be expected to contain
50  * certain characters which would be easier to input with a certain input
51  * method.
52  * 
53  * An input method may consume multiple key events in sequence and finally
54  * output the composed result. This is called preediting, and an input method
55  * may provide feedback about this process by displaying the intermediate
56  * composition states as preedit text. For instance, the default GTK+ input
57  * method implements the input of arbitrary Unicode code points by holding down
58  * the Control and Shift keys and then typing “U” followed by the hexadecimal
59  * digits of the code point.  When releasing the Control and Shift keys,
60  * preediting ends and the character is inserted as text. Ctrl+Shift+u20AC for
61  * example results in the € sign.
62  * 
63  * Additional input methods can be made available for use by GTK+ widgets as
64  * loadable modules. An input method module is a small shared library which
65  * implements a subclass of #GtkIMContext or #GtkIMContextSimple and exports
66  * these four functions:
67  * 
68  * |[<!-- language="C" -->
69  * void im_module_init(GTypeModule *module);
70  * ]|
71  * This function should register the #GType of the #GtkIMContext subclass which
72  * implements the input method by means of g_type_module_register_type(). Note
73  * that g_type_register_static() cannot be used as the type needs to be
74  * registered dynamically.
75  * 
76  * |[<!-- language="C" -->
77  * void im_module_exit(void);
78  * ]|
79  * Here goes any cleanup code your input method might require on module unload.
80  * 
81  * |[<!-- language="C" -->
82  * void im_module_list(const GtkIMContextInfo ***contexts, int *n_contexts)
83  * {
84  * *contexts = info_list;
85  * *n_contexts = G_N_ELEMENTS (info_list);
86  * }
87  * ]|
88  * This function returns the list of input methods provided by the module. The
89  * example implementation above shows a common solution and simply returns a
90  * pointer to statically defined array of #GtkIMContextInfo items for each
91  * provided input method.
92  * 
93  * |[<!-- language="C" -->
94  * GtkIMContext * im_module_create(const gchar *context_id);
95  * ]|
96  * This function should return a pointer to a newly created instance of the
97  * #GtkIMContext subclass identified by @context_id. The context ID is the same
98  * as specified in the #GtkIMContextInfo array returned by im_module_list().
99  * 
100  * After a new loadable input method module has been installed on the system,
101  * the configuration file `gtk.immodules` needs to be
102  * regenerated by [gtk-query-immodules-3.0][gtk-query-immodules-3.0],
103  * in order for the new input method to become available to GTK+ applications.
104  */
105 public class IMContext : ObjectG
106 {
107 	/** the main Gtk struct */
108 	protected GtkIMContext* gtkIMContext;
109 
110 	/** Get the main Gtk struct */
111 	public GtkIMContext* getIMContextStruct(bool transferOwnership = false)
112 	{
113 		if (transferOwnership)
114 			ownedRef = false;
115 		return gtkIMContext;
116 	}
117 
118 	/** the main Gtk struct as a void* */
119 	protected override void* getStruct()
120 	{
121 		return cast(void*)gtkIMContext;
122 	}
123 
124 	protected override void setStruct(GObject* obj)
125 	{
126 		gtkIMContext = cast(GtkIMContext*)obj;
127 		super.setStruct(obj);
128 	}
129 
130 	/**
131 	 * Sets our main struct and passes it to the parent class.
132 	 */
133 	public this (GtkIMContext* gtkIMContext, bool ownedRef = false)
134 	{
135 		this.gtkIMContext = gtkIMContext;
136 		super(cast(GObject*)gtkIMContext, ownedRef);
137 	}
138 
139 
140 	/** */
141 	public static GType getType()
142 	{
143 		return gtk_im_context_get_type();
144 	}
145 
146 	/**
147 	 * Asks the widget that the input context is attached to to delete
148 	 * characters around the cursor position by emitting the
149 	 * GtkIMContext::delete_surrounding signal. Note that @offset and @n_chars
150 	 * are in characters not in bytes which differs from the usage other
151 	 * places in #GtkIMContext.
152 	 *
153 	 * In order to use this function, you should first call
154 	 * gtk_im_context_get_surrounding() to get the current context, and
155 	 * call this function immediately afterwards to make sure that you
156 	 * know what you are deleting. You should also account for the fact
157 	 * that even if the signal was handled, the input context might not
158 	 * have deleted all the characters that were requested to be deleted.
159 	 *
160 	 * This function is used by an input method that wants to make
161 	 * subsitutions in the existing text in response to new input. It is
162 	 * not useful for applications.
163 	 *
164 	 * Params:
165 	 *     offset = offset from cursor position in chars;
166 	 *         a negative value means start before the cursor.
167 	 *     nChars = number of characters to delete.
168 	 *
169 	 * Returns: %TRUE if the signal was handled.
170 	 */
171 	public bool deleteSurrounding(int offset, int nChars)
172 	{
173 		return gtk_im_context_delete_surrounding(gtkIMContext, offset, nChars) != 0;
174 	}
175 
176 	/**
177 	 * Allow an input method to internally handle key press and release
178 	 * events. If this function returns %TRUE, then no further processing
179 	 * should be done for this key event.
180 	 *
181 	 * Params:
182 	 *     event = the key event
183 	 *
184 	 * Returns: %TRUE if the input method handled the key event.
185 	 */
186 	public bool filterKeypress(GdkEventKey* event)
187 	{
188 		return gtk_im_context_filter_keypress(gtkIMContext, event) != 0;
189 	}
190 
191 	/**
192 	 * Notify the input method that the widget to which this
193 	 * input context corresponds has gained focus. The input method
194 	 * may, for example, change the displayed feedback to reflect
195 	 * this change.
196 	 */
197 	public void focusIn()
198 	{
199 		gtk_im_context_focus_in(gtkIMContext);
200 	}
201 
202 	/**
203 	 * Notify the input method that the widget to which this
204 	 * input context corresponds has lost focus. The input method
205 	 * may, for example, change the displayed feedback or reset the contexts
206 	 * state to reflect this change.
207 	 */
208 	public void focusOut()
209 	{
210 		gtk_im_context_focus_out(gtkIMContext);
211 	}
212 
213 	/**
214 	 * Retrieve the current preedit string for the input context,
215 	 * and a list of attributes to apply to the string.
216 	 * This string should be displayed inserted at the insertion
217 	 * point.
218 	 *
219 	 * Params:
220 	 *     str = location to store the retrieved
221 	 *         string. The string retrieved must be freed with g_free().
222 	 *     attrs = location to store the retrieved
223 	 *         attribute list.  When you are done with this list, you
224 	 *         must unreference it with pango_attr_list_unref().
225 	 *     cursorPos = location to store position of cursor (in characters)
226 	 *         within the preedit string.
227 	 */
228 	public void getPreeditString(out string str, out PgAttributeList attrs, out int cursorPos)
229 	{
230 		char* outstr = null;
231 		PangoAttrList* outattrs = null;
232 		
233 		gtk_im_context_get_preedit_string(gtkIMContext, &outstr, &outattrs, &cursorPos);
234 		
235 		str = Str.toString(outstr);
236 		attrs = ObjectG.getDObject!(PgAttributeList)(outattrs);
237 	}
238 
239 	/**
240 	 * Retrieves context around the insertion point. Input methods
241 	 * typically want context in order to constrain input text based on
242 	 * existing text; this is important for languages such as Thai where
243 	 * only some sequences of characters are allowed.
244 	 *
245 	 * This function is implemented by emitting the
246 	 * GtkIMContext::retrieve_surrounding signal on the input method; in
247 	 * response to this signal, a widget should provide as much context as
248 	 * is available, up to an entire paragraph, by calling
249 	 * gtk_im_context_set_surrounding(). Note that there is no obligation
250 	 * for a widget to respond to the ::retrieve_surrounding signal, so input
251 	 * methods must be prepared to function without context.
252 	 *
253 	 * Params:
254 	 *     text = location to store a UTF-8 encoded
255 	 *         string of text holding context around the insertion point.
256 	 *         If the function returns %TRUE, then you must free the result
257 	 *         stored in this location with g_free().
258 	 *     cursorIndex = location to store byte index of the insertion
259 	 *         cursor within @text.
260 	 *
261 	 * Returns: %TRUE if surrounding text was provided; in this case
262 	 *     you must free the result stored in *text.
263 	 */
264 	public bool getSurrounding(out string text, out int cursorIndex)
265 	{
266 		char* outtext = null;
267 		
268 		auto p = gtk_im_context_get_surrounding(gtkIMContext, &outtext, &cursorIndex) != 0;
269 		
270 		text = Str.toString(outtext);
271 		
272 		return p;
273 	}
274 
275 	/**
276 	 * Notify the input method that a change such as a change in cursor
277 	 * position has been made. This will typically cause the input
278 	 * method to clear the preedit state.
279 	 */
280 	public void reset()
281 	{
282 		gtk_im_context_reset(gtkIMContext);
283 	}
284 
285 	/**
286 	 * Set the client window for the input context; this is the
287 	 * #GdkWindow in which the input appears. This window is
288 	 * used in order to correctly position status windows, and may
289 	 * also be used for purposes internal to the input method.
290 	 *
291 	 * Params:
292 	 *     window = the client window. This may be %NULL to indicate
293 	 *         that the previous client window no longer exists.
294 	 */
295 	public void setClientWindow(Window window)
296 	{
297 		gtk_im_context_set_client_window(gtkIMContext, (window is null) ? null : window.getWindowStruct());
298 	}
299 
300 	/**
301 	 * Notify the input method that a change in cursor
302 	 * position has been made. The location is relative to the client
303 	 * window.
304 	 *
305 	 * Params:
306 	 *     area = new location
307 	 */
308 	public void setCursorLocation(GdkRectangle* area)
309 	{
310 		gtk_im_context_set_cursor_location(gtkIMContext, area);
311 	}
312 
313 	/**
314 	 * Sets surrounding context around the insertion point and preedit
315 	 * string. This function is expected to be called in response to the
316 	 * GtkIMContext::retrieve_surrounding signal, and will likely have no
317 	 * effect if called at other times.
318 	 *
319 	 * Params:
320 	 *     text = text surrounding the insertion point, as UTF-8.
321 	 *         the preedit string should not be included within
322 	 *         @text.
323 	 *     len = the length of @text, or -1 if @text is nul-terminated
324 	 *     cursorIndex = the byte index of the insertion cursor within @text.
325 	 */
326 	public void setSurrounding(string text, int len, int cursorIndex)
327 	{
328 		gtk_im_context_set_surrounding(gtkIMContext, Str.toStringz(text), len, cursorIndex);
329 	}
330 
331 	/**
332 	 * Sets whether the IM context should use the preedit string
333 	 * to display feedback. If @use_preedit is FALSE (default
334 	 * is TRUE), then the IM context may use some other method to display
335 	 * feedback, such as displaying it in a child of the root window.
336 	 *
337 	 * Params:
338 	 *     usePreedit = whether the IM context should use the preedit string.
339 	 */
340 	public void setUsePreedit(bool usePreedit)
341 	{
342 		gtk_im_context_set_use_preedit(gtkIMContext, usePreedit);
343 	}
344 
345 	protected class OnCommitDelegateWrapper
346 	{
347 		static OnCommitDelegateWrapper[] listeners;
348 		void delegate(string, IMContext) dlg;
349 		gulong handlerId;
350 		
351 		this(void delegate(string, IMContext) dlg)
352 		{
353 			this.dlg = dlg;
354 			this.listeners ~= this;
355 		}
356 		
357 		void remove(OnCommitDelegateWrapper source)
358 		{
359 			foreach(index, wrapper; listeners)
360 			{
361 				if (wrapper.handlerId == source.handlerId)
362 				{
363 					listeners[index] = null;
364 					listeners = std.algorithm.remove(listeners, index);
365 					break;
366 				}
367 			}
368 		}
369 	}
370 
371 	/**
372 	 * The ::commit signal is emitted when a complete input sequence
373 	 * has been entered by the user. This can be a single character
374 	 * immediately after a key press or the final result of preediting.
375 	 *
376 	 * Params:
377 	 *     str = the completed character(s) entered by the user
378 	 */
379 	gulong addOnCommit(void delegate(string, IMContext) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
380 	{
381 		auto wrapper = new OnCommitDelegateWrapper(dlg);
382 		wrapper.handlerId = Signals.connectData(
383 			this,
384 			"commit",
385 			cast(GCallback)&callBackCommit,
386 			cast(void*)wrapper,
387 			cast(GClosureNotify)&callBackCommitDestroy,
388 			connectFlags);
389 		return wrapper.handlerId;
390 	}
391 	
392 	extern(C) static void callBackCommit(GtkIMContext* imcontextStruct, char* str, OnCommitDelegateWrapper wrapper)
393 	{
394 		wrapper.dlg(Str.toString(str), wrapper.outer);
395 	}
396 	
397 	extern(C) static void callBackCommitDestroy(OnCommitDelegateWrapper wrapper, GClosure* closure)
398 	{
399 		wrapper.remove(wrapper);
400 	}
401 
402 	protected class OnDeleteSurroundingDelegateWrapper
403 	{
404 		static OnDeleteSurroundingDelegateWrapper[] listeners;
405 		bool delegate(int, int, IMContext) dlg;
406 		gulong handlerId;
407 		
408 		this(bool delegate(int, int, IMContext) dlg)
409 		{
410 			this.dlg = dlg;
411 			this.listeners ~= this;
412 		}
413 		
414 		void remove(OnDeleteSurroundingDelegateWrapper source)
415 		{
416 			foreach(index, wrapper; listeners)
417 			{
418 				if (wrapper.handlerId == source.handlerId)
419 				{
420 					listeners[index] = null;
421 					listeners = std.algorithm.remove(listeners, index);
422 					break;
423 				}
424 			}
425 		}
426 	}
427 
428 	/**
429 	 * The ::delete-surrounding signal is emitted when the input method
430 	 * needs to delete all or part of the context surrounding the cursor.
431 	 *
432 	 * Params:
433 	 *     offset = the character offset from the cursor position of the text
434 	 *         to be deleted. A negative value indicates a position before
435 	 *         the cursor.
436 	 *     nChars = the number of characters to be deleted
437 	 *
438 	 * Returns: %TRUE if the signal was handled.
439 	 */
440 	gulong addOnDeleteSurrounding(bool delegate(int, int, IMContext) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
441 	{
442 		auto wrapper = new OnDeleteSurroundingDelegateWrapper(dlg);
443 		wrapper.handlerId = Signals.connectData(
444 			this,
445 			"delete-surrounding",
446 			cast(GCallback)&callBackDeleteSurrounding,
447 			cast(void*)wrapper,
448 			cast(GClosureNotify)&callBackDeleteSurroundingDestroy,
449 			connectFlags);
450 		return wrapper.handlerId;
451 	}
452 	
453 	extern(C) static int callBackDeleteSurrounding(GtkIMContext* imcontextStruct, int offset, int nChars, OnDeleteSurroundingDelegateWrapper wrapper)
454 	{
455 		return wrapper.dlg(offset, nChars, wrapper.outer);
456 	}
457 	
458 	extern(C) static void callBackDeleteSurroundingDestroy(OnDeleteSurroundingDelegateWrapper wrapper, GClosure* closure)
459 	{
460 		wrapper.remove(wrapper);
461 	}
462 
463 	protected class OnPreeditChangedDelegateWrapper
464 	{
465 		static OnPreeditChangedDelegateWrapper[] listeners;
466 		void delegate(IMContext) dlg;
467 		gulong handlerId;
468 		
469 		this(void delegate(IMContext) dlg)
470 		{
471 			this.dlg = dlg;
472 			this.listeners ~= this;
473 		}
474 		
475 		void remove(OnPreeditChangedDelegateWrapper source)
476 		{
477 			foreach(index, wrapper; listeners)
478 			{
479 				if (wrapper.handlerId == source.handlerId)
480 				{
481 					listeners[index] = null;
482 					listeners = std.algorithm.remove(listeners, index);
483 					break;
484 				}
485 			}
486 		}
487 	}
488 
489 	/**
490 	 * The ::preedit-changed signal is emitted whenever the preedit sequence
491 	 * currently being entered has changed.  It is also emitted at the end of
492 	 * a preedit sequence, in which case
493 	 * gtk_im_context_get_preedit_string() returns the empty string.
494 	 */
495 	gulong addOnPreeditChanged(void delegate(IMContext) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
496 	{
497 		auto wrapper = new OnPreeditChangedDelegateWrapper(dlg);
498 		wrapper.handlerId = Signals.connectData(
499 			this,
500 			"preedit-changed",
501 			cast(GCallback)&callBackPreeditChanged,
502 			cast(void*)wrapper,
503 			cast(GClosureNotify)&callBackPreeditChangedDestroy,
504 			connectFlags);
505 		return wrapper.handlerId;
506 	}
507 	
508 	extern(C) static void callBackPreeditChanged(GtkIMContext* imcontextStruct, OnPreeditChangedDelegateWrapper wrapper)
509 	{
510 		wrapper.dlg(wrapper.outer);
511 	}
512 	
513 	extern(C) static void callBackPreeditChangedDestroy(OnPreeditChangedDelegateWrapper wrapper, GClosure* closure)
514 	{
515 		wrapper.remove(wrapper);
516 	}
517 
518 	protected class OnPreeditEndDelegateWrapper
519 	{
520 		static OnPreeditEndDelegateWrapper[] listeners;
521 		void delegate(IMContext) dlg;
522 		gulong handlerId;
523 		
524 		this(void delegate(IMContext) dlg)
525 		{
526 			this.dlg = dlg;
527 			this.listeners ~= this;
528 		}
529 		
530 		void remove(OnPreeditEndDelegateWrapper source)
531 		{
532 			foreach(index, wrapper; listeners)
533 			{
534 				if (wrapper.handlerId == source.handlerId)
535 				{
536 					listeners[index] = null;
537 					listeners = std.algorithm.remove(listeners, index);
538 					break;
539 				}
540 			}
541 		}
542 	}
543 
544 	/**
545 	 * The ::preedit-end signal is emitted when a preediting sequence
546 	 * has been completed or canceled.
547 	 */
548 	gulong addOnPreeditEnd(void delegate(IMContext) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
549 	{
550 		auto wrapper = new OnPreeditEndDelegateWrapper(dlg);
551 		wrapper.handlerId = Signals.connectData(
552 			this,
553 			"preedit-end",
554 			cast(GCallback)&callBackPreeditEnd,
555 			cast(void*)wrapper,
556 			cast(GClosureNotify)&callBackPreeditEndDestroy,
557 			connectFlags);
558 		return wrapper.handlerId;
559 	}
560 	
561 	extern(C) static void callBackPreeditEnd(GtkIMContext* imcontextStruct, OnPreeditEndDelegateWrapper wrapper)
562 	{
563 		wrapper.dlg(wrapper.outer);
564 	}
565 	
566 	extern(C) static void callBackPreeditEndDestroy(OnPreeditEndDelegateWrapper wrapper, GClosure* closure)
567 	{
568 		wrapper.remove(wrapper);
569 	}
570 
571 	protected class OnPreeditStartDelegateWrapper
572 	{
573 		static OnPreeditStartDelegateWrapper[] listeners;
574 		void delegate(IMContext) dlg;
575 		gulong handlerId;
576 		
577 		this(void delegate(IMContext) dlg)
578 		{
579 			this.dlg = dlg;
580 			this.listeners ~= this;
581 		}
582 		
583 		void remove(OnPreeditStartDelegateWrapper source)
584 		{
585 			foreach(index, wrapper; listeners)
586 			{
587 				if (wrapper.handlerId == source.handlerId)
588 				{
589 					listeners[index] = null;
590 					listeners = std.algorithm.remove(listeners, index);
591 					break;
592 				}
593 			}
594 		}
595 	}
596 
597 	/**
598 	 * The ::preedit-start signal is emitted when a new preediting sequence
599 	 * starts.
600 	 */
601 	gulong addOnPreeditStart(void delegate(IMContext) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
602 	{
603 		auto wrapper = new OnPreeditStartDelegateWrapper(dlg);
604 		wrapper.handlerId = Signals.connectData(
605 			this,
606 			"preedit-start",
607 			cast(GCallback)&callBackPreeditStart,
608 			cast(void*)wrapper,
609 			cast(GClosureNotify)&callBackPreeditStartDestroy,
610 			connectFlags);
611 		return wrapper.handlerId;
612 	}
613 	
614 	extern(C) static void callBackPreeditStart(GtkIMContext* imcontextStruct, OnPreeditStartDelegateWrapper wrapper)
615 	{
616 		wrapper.dlg(wrapper.outer);
617 	}
618 	
619 	extern(C) static void callBackPreeditStartDestroy(OnPreeditStartDelegateWrapper wrapper, GClosure* closure)
620 	{
621 		wrapper.remove(wrapper);
622 	}
623 
624 	protected class OnRetrieveSurroundingDelegateWrapper
625 	{
626 		static OnRetrieveSurroundingDelegateWrapper[] listeners;
627 		bool delegate(IMContext) dlg;
628 		gulong handlerId;
629 		
630 		this(bool delegate(IMContext) dlg)
631 		{
632 			this.dlg = dlg;
633 			this.listeners ~= this;
634 		}
635 		
636 		void remove(OnRetrieveSurroundingDelegateWrapper source)
637 		{
638 			foreach(index, wrapper; listeners)
639 			{
640 				if (wrapper.handlerId == source.handlerId)
641 				{
642 					listeners[index] = null;
643 					listeners = std.algorithm.remove(listeners, index);
644 					break;
645 				}
646 			}
647 		}
648 	}
649 
650 	/**
651 	 * The ::retrieve-surrounding signal is emitted when the input method
652 	 * requires the context surrounding the cursor.  The callback should set
653 	 * the input method surrounding context by calling the
654 	 * gtk_im_context_set_surrounding() method.
655 	 *
656 	 * Returns: %TRUE if the signal was handled.
657 	 */
658 	gulong addOnRetrieveSurrounding(bool delegate(IMContext) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
659 	{
660 		auto wrapper = new OnRetrieveSurroundingDelegateWrapper(dlg);
661 		wrapper.handlerId = Signals.connectData(
662 			this,
663 			"retrieve-surrounding",
664 			cast(GCallback)&callBackRetrieveSurrounding,
665 			cast(void*)wrapper,
666 			cast(GClosureNotify)&callBackRetrieveSurroundingDestroy,
667 			connectFlags);
668 		return wrapper.handlerId;
669 	}
670 	
671 	extern(C) static int callBackRetrieveSurrounding(GtkIMContext* imcontextStruct, OnRetrieveSurroundingDelegateWrapper wrapper)
672 	{
673 		return wrapper.dlg(wrapper.outer);
674 	}
675 	
676 	extern(C) static void callBackRetrieveSurroundingDestroy(OnRetrieveSurroundingDelegateWrapper wrapper, GClosure* closure)
677 	{
678 		wrapper.remove(wrapper);
679 	}
680 }