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 }