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