SDL  2.0
SDL_ibus.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #ifdef HAVE_IBUS_IBUS_H
24 #include "SDL.h"
25 #include "SDL_syswm.h"
26 #include "SDL_ibus.h"
27 #include "SDL_dbus.h"
28 #include "../../video/SDL_sysvideo.h"
29 #include "../../events/SDL_keyboard_c.h"
30 
31 #if SDL_VIDEO_DRIVER_X11
32  #include "../../video/x11/SDL_x11video.h"
33 #endif
34 
35 #include <sys/inotify.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 
39 static const char IBUS_SERVICE[] = "org.freedesktop.IBus";
40 static const char IBUS_PATH[] = "/org/freedesktop/IBus";
41 static const char IBUS_INTERFACE[] = "org.freedesktop.IBus";
42 static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
43 
44 static char *input_ctx_path = NULL;
45 static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 };
46 static DBusConnection *ibus_conn = NULL;
47 static char *ibus_addr_file = NULL;
48 int inotify_fd = -1, inotify_wd = -1;
49 
50 static Uint32
51 IBus_ModState(void)
52 {
53  Uint32 ibus_mods = 0;
54  SDL_Keymod sdl_mods = SDL_GetModState();
55 
56  /* Not sure about MOD3, MOD4 and HYPER mappings */
57  if (sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
58  if (sdl_mods & KMOD_CAPS) ibus_mods |= IBUS_LOCK_MASK;
59  if (sdl_mods & KMOD_LCTRL) ibus_mods |= IBUS_CONTROL_MASK;
60  if (sdl_mods & KMOD_LALT) ibus_mods |= IBUS_MOD1_MASK;
61  if (sdl_mods & KMOD_NUM) ibus_mods |= IBUS_MOD2_MASK;
62  if (sdl_mods & KMOD_MODE) ibus_mods |= IBUS_MOD5_MASK;
63  if (sdl_mods & KMOD_LGUI) ibus_mods |= IBUS_SUPER_MASK;
64  if (sdl_mods & KMOD_RGUI) ibus_mods |= IBUS_META_MASK;
65 
66  return ibus_mods;
67 }
68 
69 static const char *
70 IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
71 {
72  /* The text we need is nested weirdly, use dbus-monitor to see the structure better */
73  const char *text = NULL;
74  const char *struct_id = NULL;
75  DBusMessageIter sub1, sub2;
76 
77  if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
78  return NULL;
79  }
80 
81  dbus->message_iter_recurse(iter, &sub1);
82 
83  if (dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) {
84  return NULL;
85  }
86 
87  dbus->message_iter_recurse(&sub1, &sub2);
88 
89  if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
90  return NULL;
91  }
92 
93  dbus->message_iter_get_basic(&sub2, &struct_id);
94  if (!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0) {
95  return NULL;
96  }
97 
98  dbus->message_iter_next(&sub2);
99  dbus->message_iter_next(&sub2);
100 
101  if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
102  return NULL;
103  }
104 
105  dbus->message_iter_get_basic(&sub2, &text);
106 
107  return text;
108 }
109 
110 static size_t
111 IBus_utf8_strlen(const char *str)
112 {
113  size_t utf8_len = 0;
114  const char *p;
115 
116  for (p = str; *p; ++p) {
117  if (!((*p & 0x80) && !(*p & 0x40))) {
118  ++utf8_len;
119  }
120  }
121 
122  return utf8_len;
123 }
124 
125 static DBusHandlerResult
126 IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data)
127 {
128  SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
129 
130  if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")) {
131  DBusMessageIter iter;
132  const char *text;
133 
134  dbus->message_iter_init(msg, &iter);
135 
136  text = IBus_GetVariantText(conn, &iter, dbus);
137  if (text && *text) {
139  size_t text_bytes = SDL_strlen(text), i = 0;
140 
141  while (i < text_bytes) {
142  size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
144 
145  i += sz;
146  }
147  }
148 
149  return DBUS_HANDLER_RESULT_HANDLED;
150  }
151 
152  if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")) {
153  DBusMessageIter iter;
154  const char *text;
155 
156  dbus->message_iter_init(msg, &iter);
157  text = IBus_GetVariantText(conn, &iter, dbus);
158 
159  if (text) {
161  size_t text_bytes = SDL_strlen(text), i = 0;
162  size_t cursor = 0;
163 
164  do {
165  size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
166  size_t chars = IBus_utf8_strlen(buf);
167 
168  SDL_SendEditingText(buf, cursor, chars);
169 
170  i += sz;
171  cursor += chars;
172  } while (i < text_bytes);
173  }
174 
175  SDL_IBus_UpdateTextRect(NULL);
176 
177  return DBUS_HANDLER_RESULT_HANDLED;
178  }
179 
180  if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "HidePreeditText")) {
181  SDL_SendEditingText("", 0, 0);
182  return DBUS_HANDLER_RESULT_HANDLED;
183  }
184 
185  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
186 }
187 
188 static char *
189 IBus_ReadAddressFromFile(const char *file_path)
190 {
191  char addr_buf[1024];
192  SDL_bool success = SDL_FALSE;
193  FILE *addr_file;
194 
195  addr_file = fopen(file_path, "r");
196  if (!addr_file) {
197  return NULL;
198  }
199 
200  while (fgets(addr_buf, sizeof(addr_buf), addr_file)) {
201  if (SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
202  size_t sz = SDL_strlen(addr_buf);
203  if (addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
204  if (addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
205  success = SDL_TRUE;
206  break;
207  }
208  }
209 
210  fclose(addr_file);
211 
212  if (success) {
213  return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
214  } else {
215  return NULL;
216  }
217 }
218 
219 static char *
220 IBus_GetDBusAddressFilename(void)
221 {
222  SDL_DBusContext *dbus;
223  const char *disp_env;
224  char config_dir[PATH_MAX];
225  char *display = NULL;
226  const char *addr;
227  const char *conf_env;
228  char *key;
229  char file_path[PATH_MAX];
230  const char *host;
231  char *disp_num, *screen_num;
232 
233  if (ibus_addr_file) {
234  return SDL_strdup(ibus_addr_file);
235  }
236 
237  dbus = SDL_DBus_GetContext();
238  if (!dbus) {
239  return NULL;
240  }
241 
242  /* Use this environment variable if it exists. */
243  addr = SDL_getenv("IBUS_ADDRESS");
244  if (addr && *addr) {
245  return SDL_strdup(addr);
246  }
247 
248  /* Otherwise, we have to get the hostname, display, machine id, config dir
249  and look up the address from a filepath using all those bits, eek. */
250  disp_env = SDL_getenv("DISPLAY");
251 
252  if (!disp_env || !*disp_env) {
253  display = SDL_strdup(":0.0");
254  } else {
255  display = SDL_strdup(disp_env);
256  }
257 
258  host = display;
259  disp_num = SDL_strrchr(display, ':');
260  screen_num = SDL_strrchr(display, '.');
261 
262  if (!disp_num) {
263  SDL_free(display);
264  return NULL;
265  }
266 
267  *disp_num = 0;
268  disp_num++;
269 
270  if (screen_num) {
271  *screen_num = 0;
272  }
273 
274  if (!*host) {
275  host = "unix";
276  }
277 
278  SDL_memset(config_dir, 0, sizeof(config_dir));
279 
280  conf_env = SDL_getenv("XDG_CONFIG_HOME");
281  if (conf_env && *conf_env) {
282  SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
283  } else {
284  const char *home_env = SDL_getenv("HOME");
285  if (!home_env || !*home_env) {
286  SDL_free(display);
287  return NULL;
288  }
289  SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
290  }
291 
292  key = dbus->get_local_machine_id();
293 
294  SDL_memset(file_path, 0, sizeof(file_path));
295  SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s",
296  config_dir, key, host, disp_num);
297  dbus->free(key);
298  SDL_free(display);
299 
300  return SDL_strdup(file_path);
301 }
302 
303 static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
304 
305 static void
306 IBus_SetCapabilities(void *data, const char *name, const char *old_val,
307  const char *internal_editing)
308 {
309  SDL_DBusContext *dbus = SDL_DBus_GetContext();
310 
311  if (IBus_CheckConnection(dbus)) {
312 
313  DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
314  input_ctx_path,
315  IBUS_INPUT_INTERFACE,
316  "SetCapabilities");
317  if (msg) {
318  Uint32 caps = IBUS_CAP_FOCUS;
319  if (!(internal_editing && *internal_editing == '1')) {
320  caps |= IBUS_CAP_PREEDIT_TEXT;
321  }
322 
323  dbus->message_append_args(msg,
324  DBUS_TYPE_UINT32, &caps,
325  DBUS_TYPE_INVALID);
326  }
327 
328  if (msg) {
329  if (dbus->connection_send(ibus_conn, msg, NULL)) {
330  dbus->connection_flush(ibus_conn);
331  }
332  dbus->message_unref(msg);
333  }
334  }
335 }
336 
337 
338 static SDL_bool
339 IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
340 {
341  const char *path = NULL;
343  DBusMessage *msg;
344  DBusObjectPathVTable ibus_vtable;
345 
346  SDL_zero(ibus_vtable);
347  ibus_vtable.message_function = &IBus_MessageHandler;
348 
349  ibus_conn = dbus->connection_open_private(addr, NULL);
350 
351  if (!ibus_conn) {
352  return SDL_FALSE;
353  }
354 
355  dbus->connection_flush(ibus_conn);
356 
357  if (!dbus->bus_register(ibus_conn, NULL)) {
358  ibus_conn = NULL;
359  return SDL_FALSE;
360  }
361 
362  dbus->connection_flush(ibus_conn);
363 
364  msg = dbus->message_new_method_call(IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext");
365  if (msg) {
366  const char *client_name = "SDL2_Application";
367  dbus->message_append_args(msg,
368  DBUS_TYPE_STRING, &client_name,
369  DBUS_TYPE_INVALID);
370  }
371 
372  if (msg) {
373  DBusMessage *reply;
374 
375  reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
376  if (reply) {
377  if (dbus->message_get_args(reply, NULL,
378  DBUS_TYPE_OBJECT_PATH, &path,
379  DBUS_TYPE_INVALID)) {
380  if (input_ctx_path) {
381  SDL_free(input_ctx_path);
382  }
383  input_ctx_path = SDL_strdup(path);
384  result = SDL_TRUE;
385  }
386  dbus->message_unref(reply);
387  }
388  dbus->message_unref(msg);
389  }
390 
391  if (result) {
392  SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
393 
394  dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
395  dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL);
396  dbus->connection_flush(ibus_conn);
397  }
398 
399  SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
400  SDL_IBus_UpdateTextRect(NULL);
401 
402  return result;
403 }
404 
405 static SDL_bool
406 IBus_CheckConnection(SDL_DBusContext *dbus)
407 {
408  if (!dbus) return SDL_FALSE;
409 
410  if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
411  return SDL_TRUE;
412  }
413 
414  if (inotify_fd > 0 && inotify_wd > 0) {
415  char buf[1024];
416  ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
417  if (readsize > 0) {
418 
419  char *p;
420  SDL_bool file_updated = SDL_FALSE;
421 
422  for (p = buf; p < buf + readsize; /**/) {
423  struct inotify_event *event = (struct inotify_event*) p;
424  if (event->len > 0) {
425  char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
426  if (!addr_file_no_path) return SDL_FALSE;
427 
428  if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) {
429  file_updated = SDL_TRUE;
430  break;
431  }
432  }
433 
434  p += sizeof(struct inotify_event) + event->len;
435  }
436 
437  if (file_updated) {
438  char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
439  if (addr) {
440  SDL_bool result = IBus_SetupConnection(dbus, addr);
441  SDL_free(addr);
442  return result;
443  }
444  }
445  }
446  }
447 
448  return SDL_FALSE;
449 }
450 
451 SDL_bool
452 SDL_IBus_Init(void)
453 {
454  SDL_bool result = SDL_FALSE;
455  SDL_DBusContext *dbus = SDL_DBus_GetContext();
456 
457  if (dbus) {
458  char *addr_file = IBus_GetDBusAddressFilename();
459  char *addr;
460  char *addr_file_dir;
461 
462  if (!addr_file) {
463  return SDL_FALSE;
464  }
465 
466  /* !!! FIXME: if ibus_addr_file != NULL, this will overwrite it and leak (twice!) */
467  ibus_addr_file = SDL_strdup(addr_file);
468 
469  addr = IBus_ReadAddressFromFile(addr_file);
470  if (!addr) {
471  SDL_free(addr_file);
472  return SDL_FALSE;
473  }
474 
475  if (inotify_fd < 0) {
476  inotify_fd = inotify_init();
477  fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
478  }
479 
480  addr_file_dir = SDL_strrchr(addr_file, '/');
481  if (addr_file_dir) {
482  *addr_file_dir = 0;
483  }
484 
485  inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
486  SDL_free(addr_file);
487 
488  if (addr) {
489  result = IBus_SetupConnection(dbus, addr);
490  SDL_free(addr);
491  }
492  }
493 
494  return result;
495 }
496 
497 void
498 SDL_IBus_Quit(void)
499 {
500  SDL_DBusContext *dbus;
501 
502  if (input_ctx_path) {
503  SDL_free(input_ctx_path);
504  input_ctx_path = NULL;
505  }
506 
507  if (ibus_addr_file) {
508  SDL_free(ibus_addr_file);
509  ibus_addr_file = NULL;
510  }
511 
512  dbus = SDL_DBus_GetContext();
513 
514  if (dbus && ibus_conn) {
515  dbus->connection_close(ibus_conn);
516  dbus->connection_unref(ibus_conn);
517  }
518 
519  if (inotify_fd > 0 && inotify_wd > 0) {
520  inotify_rm_watch(inotify_fd, inotify_wd);
521  inotify_wd = -1;
522  }
523 
524  SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
525 
526  SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
527 }
528 
529 static void
530 IBus_SimpleMessage(const char *method)
531 {
532  SDL_DBusContext *dbus = SDL_DBus_GetContext();
533 
534  if (IBus_CheckConnection(dbus)) {
535  DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
536  input_ctx_path,
537  IBUS_INPUT_INTERFACE,
538  method);
539  if (msg) {
540  if (dbus->connection_send(ibus_conn, msg, NULL)) {
541  dbus->connection_flush(ibus_conn);
542  }
543  dbus->message_unref(msg);
544  }
545  }
546 }
547 
548 void
549 SDL_IBus_SetFocus(SDL_bool focused)
550 {
551  const char *method = focused ? "FocusIn" : "FocusOut";
552  IBus_SimpleMessage(method);
553 }
554 
555 void
556 SDL_IBus_Reset(void)
557 {
558  IBus_SimpleMessage("Reset");
559 }
560 
561 SDL_bool
562 SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
563 {
564  SDL_bool result = SDL_FALSE;
565  SDL_DBusContext *dbus = SDL_DBus_GetContext();
566 
567  if (IBus_CheckConnection(dbus)) {
568  DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
569  input_ctx_path,
570  IBUS_INPUT_INTERFACE,
571  "ProcessKeyEvent");
572  if (msg) {
573  Uint32 mods = IBus_ModState();
574  dbus->message_append_args(msg,
575  DBUS_TYPE_UINT32, &keysym,
576  DBUS_TYPE_UINT32, &keycode,
577  DBUS_TYPE_UINT32, &mods,
578  DBUS_TYPE_INVALID);
579  }
580 
581  if (msg) {
582  DBusMessage *reply;
583 
584  reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
585  if (reply) {
586  if (!dbus->message_get_args(reply, NULL,
587  DBUS_TYPE_BOOLEAN, &result,
588  DBUS_TYPE_INVALID)) {
589  result = SDL_FALSE;
590  }
591  dbus->message_unref(reply);
592  }
593  dbus->message_unref(msg);
594  }
595 
596  }
597 
598  SDL_IBus_UpdateTextRect(NULL);
599 
600  return result;
601 }
602 
603 void
604 SDL_IBus_UpdateTextRect(SDL_Rect *rect)
605 {
606  SDL_Window *focused_win;
607  SDL_SysWMinfo info;
608  int x = 0, y = 0;
609  SDL_DBusContext *dbus;
610 
611  if (rect) {
612  SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
613  }
614 
615  focused_win = SDL_GetKeyboardFocus();
616  if (!focused_win) {
617  return;
618  }
619 
620  SDL_VERSION(&info.version);
621  if (!SDL_GetWindowWMInfo(focused_win, &info)) {
622  return;
623  }
624 
625  SDL_GetWindowPosition(focused_win, &x, &y);
626 
627 #if SDL_VIDEO_DRIVER_X11
628  if (info.subsystem == SDL_SYSWM_X11) {
629  SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
630 
631  Display *x_disp = info.info.x11.display;
632  Window x_win = info.info.x11.window;
633  int x_screen = displaydata->screen;
634  Window unused;
635 
636  X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
637  }
638 #endif
639 
640  x += ibus_cursor_rect.x;
641  y += ibus_cursor_rect.y;
642 
643  dbus = SDL_DBus_GetContext();
644 
645  if (IBus_CheckConnection(dbus)) {
646  DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
647  input_ctx_path,
648  IBUS_INPUT_INTERFACE,
649  "SetCursorLocation");
650  if (msg) {
651  dbus->message_append_args(msg,
652  DBUS_TYPE_INT32, &x,
653  DBUS_TYPE_INT32, &y,
654  DBUS_TYPE_INT32, &ibus_cursor_rect.w,
655  DBUS_TYPE_INT32, &ibus_cursor_rect.h,
656  DBUS_TYPE_INVALID);
657  }
658 
659  if (msg) {
660  if (dbus->connection_send(ibus_conn, msg, NULL)) {
661  dbus->connection_flush(ibus_conn);
662  }
663  dbus->message_unref(msg);
664  }
665  }
666 }
667 
668 void
669 SDL_IBus_PumpEvents(void)
670 {
671  SDL_DBusContext *dbus = SDL_DBus_GetContext();
672 
673  if (IBus_CheckConnection(dbus)) {
674  dbus->connection_read_write(ibus_conn, 0);
675 
676  while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
677  /* Do nothing, actual work happens in IBus_MessageHandler */
678  }
679  }
680 }
681 
682 #endif
#define SDL_strlcpy
GLuint64EXT * result
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
SDL_Rect rect
Definition: testrelative.c:27
GLfloat GLfloat p
#define SDL_utf8strlcpy
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_version version
Definition: SDL_syswm.h:195
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:196
GLuint const GLchar * name
#define SDL_GetKeyboardFocus
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:161
#define SDL_strncmp
GLenum GLsizei len
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
Definition: SDL_version.h:79
#define SDL_memcpy
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:774
struct _cl_event * event
void SDL_free(void *mem)
GLenum const void * addr
#define SDL_zero(x)
Definition: SDL_stdinc.h:361
#define SDL_GetWindowPosition
int x
Definition: SDL_rect.h:66
GLenum GLuint GLenum GLsizei const GLchar * buf
int w
Definition: SDL_rect.h:67
struct SDL_SysWMinfo::@18::@19 x11
#define SDL_HINT_IME_INTERNAL_EDITING
A variable to control whether certain IMEs should handle text editing internally instead of sending S...
Definition: SDL_hints.h:623
SDL_Keymod
Enumeration of valid key mods (possibly OR&#39;d together).
Definition: SDL_keycode.h:317
SDL_Cursor * cursor
#define SDL_getenv
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define SDL_GetWindowWMInfo
#define NULL
Definition: begin_code.h:143
SDL_bool
Definition: SDL_stdinc.h:130
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1058
#define SDL_strlen
int h
Definition: SDL_rect.h:67
#define SDL_strdup
The type used to identify a window.
Definition: SDL_sysvideo.h:71
#define SDL_AddHintCallback
#define SDL_DelHintCallback
#define SDL_snprintf
union SDL_SysWMinfo::@18 info
GLsizei const GLchar *const * path
#define SDL_strcmp
#define SDL_strrchr
#define SDL_GetModState
int y
Definition: SDL_rect.h:66
int SDL_SendEditingText(const char *text, int start, int length)
Definition: SDL_keyboard.c:797
#define SDL_memset
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
#define SDL_TEXTEDITINGEVENT_TEXT_SIZE
Definition: SDL_events.h:202