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