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 }