Atlas - SDL_ibus.c

Home / ext / SDL / src / core / linux Lines: 2 | Size: 22636 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 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_ibus.h" 25#include "SDL_dbus.h" 26 27#ifdef SDL_USE_LIBDBUS 28 29#include "../../video/SDL_sysvideo.h" 30#include "../../events/SDL_keyboard_c.h" 31 32#ifdef SDL_VIDEO_DRIVER_X11 33#include "../../video/x11/SDL_x11video.h" 34#endif 35 36#include <sys/inotify.h> 37#include <unistd.h> 38#include <fcntl.h> 39 40static const char IBUS_PATH[] = "/org/freedesktop/IBus"; 41 42static const char IBUS_SERVICE[] = "org.freedesktop.IBus"; 43static const char IBUS_INTERFACE[] = "org.freedesktop.IBus"; 44static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext"; 45 46static const char IBUS_PORTAL_SERVICE[] = "org.freedesktop.portal.IBus"; 47static const char IBUS_PORTAL_INTERFACE[] = "org.freedesktop.IBus.Portal"; 48static const char IBUS_PORTAL_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext"; 49 50static const char *ibus_service = NULL; 51static const char *ibus_interface = NULL; 52static const char *ibus_input_interface = NULL; 53static char *input_ctx_path = NULL; 54static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 }; 55static DBusConnection *ibus_conn = NULL; 56static bool ibus_is_portal_interface = false; 57static char *ibus_addr_file = NULL; 58static int inotify_fd = -1, inotify_wd = -1; 59 60static Uint32 IBus_ModState(void) 61{ 62 Uint32 ibus_mods = 0; 63 SDL_Keymod sdl_mods = SDL_GetModState(); 64 65 // Not sure about MOD3, MOD4 and HYPER mappings 66 if (sdl_mods & SDL_KMOD_LSHIFT) { 67 ibus_mods |= IBUS_SHIFT_MASK; 68 } 69 if (sdl_mods & SDL_KMOD_CAPS) { 70 ibus_mods |= IBUS_LOCK_MASK; 71 } 72 if (sdl_mods & SDL_KMOD_LCTRL) { 73 ibus_mods |= IBUS_CONTROL_MASK; 74 } 75 if (sdl_mods & SDL_KMOD_LALT) { 76 ibus_mods |= IBUS_MOD1_MASK; 77 } 78 if (sdl_mods & SDL_KMOD_NUM) { 79 ibus_mods |= IBUS_MOD2_MASK; 80 } 81 if (sdl_mods & SDL_KMOD_MODE) { 82 ibus_mods |= IBUS_MOD5_MASK; 83 } 84 if (sdl_mods & SDL_KMOD_LGUI) { 85 ibus_mods |= IBUS_SUPER_MASK; 86 } 87 if (sdl_mods & SDL_KMOD_RGUI) { 88 ibus_mods |= IBUS_META_MASK; 89 } 90 91 return ibus_mods; 92} 93 94static bool IBus_EnterVariant(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus, 95 DBusMessageIter *inside, const char *struct_id, size_t id_size) 96{ 97 DBusMessageIter sub; 98 if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) { 99 return false; 100 } 101 102 dbus->message_iter_recurse(iter, &sub); 103 104 if (dbus->message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { 105 return false; 106 } 107 108 dbus->message_iter_recurse(&sub, inside); 109 110 if (dbus->message_iter_get_arg_type(inside) != DBUS_TYPE_STRING) { 111 return false; 112 } 113 114 dbus->message_iter_get_basic(inside, &struct_id); 115 if (!struct_id || SDL_strncmp(struct_id, struct_id, id_size) != 0) { 116 return false; 117 } 118 return true; 119} 120 121static bool IBus_GetDecorationPosition(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus, 122 Uint32 *start_pos, Uint32 *end_pos) 123{ 124 DBusMessageIter sub1, sub2, array; 125 126 if (!IBus_EnterVariant(conn, iter, dbus, &sub1, "IBusText", sizeof("IBusText"))) { 127 return false; 128 } 129 130 dbus->message_iter_next(&sub1); 131 dbus->message_iter_next(&sub1); 132 dbus->message_iter_next(&sub1); 133 134 if (!IBus_EnterVariant(conn, &sub1, dbus, &sub2, "IBusAttrList", sizeof("IBusAttrList"))) { 135 return false; 136 } 137 138 dbus->message_iter_next(&sub2); 139 dbus->message_iter_next(&sub2); 140 141 if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY) { 142 return false; 143 } 144 145 dbus->message_iter_recurse(&sub2, &array); 146 147 while (dbus->message_iter_get_arg_type(&array) == DBUS_TYPE_VARIANT) { 148 DBusMessageIter sub; 149 if (IBus_EnterVariant(conn, &array, dbus, &sub, "IBusAttribute", sizeof("IBusAttribute"))) { 150 Uint32 type; 151 152 dbus->message_iter_next(&sub); 153 dbus->message_iter_next(&sub); 154 155 // From here on, the structure looks like this: 156 // Uint32 type: 1=underline, 2=foreground, 3=background 157 // Uint32 value: for underline it's 0=NONE, 1=SINGLE, 2=DOUBLE, 158 // 3=LOW, 4=ERROR 159 // for foreground and background it's a color 160 // Uint32 start_index: starting position for the style (utf8-char) 161 // Uint32 end_index: end position for the style (utf8-char) 162 163 dbus->message_iter_get_basic(&sub, &type); 164 // We only use the background type to determine the selection 165 if (type == 3) { 166 Uint32 start = -1; 167 dbus->message_iter_next(&sub); 168 dbus->message_iter_next(&sub); 169 if (dbus->message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32) { 170 dbus->message_iter_get_basic(&sub, &start); 171 dbus->message_iter_next(&sub); 172 if (dbus->message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32) { 173 dbus->message_iter_get_basic(&sub, end_pos); 174 *start_pos = start; 175 return true; 176 } 177 } 178 } 179 } 180 dbus->message_iter_next(&array); 181 } 182 return false; 183} 184 185static const char *IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus) 186{ 187 // The text we need is nested weirdly, use dbus-monitor to see the structure better 188 const char *text = NULL; 189 DBusMessageIter sub; 190 191 if (!IBus_EnterVariant(conn, iter, dbus, &sub, "IBusText", sizeof("IBusText"))) { 192 return NULL; 193 } 194 195 dbus->message_iter_next(&sub); 196 dbus->message_iter_next(&sub); 197 198 if (dbus->message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { 199 return NULL; 200 } 201 dbus->message_iter_get_basic(&sub, &text); 202 203 return text; 204} 205 206static bool IBus_GetVariantCursorPos(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus, 207 Uint32 *pos) 208{ 209 dbus->message_iter_next(iter); 210 211 if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32) { 212 return false; 213 } 214 215 dbus->message_iter_get_basic(iter, pos); 216 217 return true; 218} 219 220static DBusHandlerResult IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data) 221{ 222 SDL_DBusContext *dbus = (SDL_DBusContext *)user_data; 223 224 if (dbus->message_is_signal(msg, ibus_input_interface, "CommitText")) { 225 DBusMessageIter iter; 226 const char *text; 227 228 dbus->message_iter_init(msg, &iter); 229 text = IBus_GetVariantText(conn, &iter, dbus); 230 231 SDL_SendKeyboardText(text); 232 233 return DBUS_HANDLER_RESULT_HANDLED; 234 } 235 236 if (dbus->message_is_signal(msg, ibus_input_interface, "UpdatePreeditText")) { 237 DBusMessageIter iter; 238 const char *text; 239 240 dbus->message_iter_init(msg, &iter); 241 text = IBus_GetVariantText(conn, &iter, dbus); 242 243 if (text) { 244 Uint32 pos, start_pos, end_pos; 245 bool has_pos = false; 246 bool has_dec_pos = false; 247 248 dbus->message_iter_init(msg, &iter); 249 has_dec_pos = IBus_GetDecorationPosition(conn, &iter, dbus, &start_pos, &end_pos); 250 if (!has_dec_pos) { 251 dbus->message_iter_init(msg, &iter); 252 has_pos = IBus_GetVariantCursorPos(conn, &iter, dbus, &pos); 253 } 254 255 if (has_dec_pos) { 256 SDL_SendEditingText(text, start_pos, end_pos - start_pos); 257 } else if (has_pos) { 258 SDL_SendEditingText(text, pos, -1); 259 } else { 260 SDL_SendEditingText(text, -1, -1); 261 } 262 } 263 264 SDL_IBus_UpdateTextInputArea(SDL_GetKeyboardFocus()); 265 266 return DBUS_HANDLER_RESULT_HANDLED; 267 } 268 269 if (dbus->message_is_signal(msg, ibus_input_interface, "HidePreeditText")) { 270 SDL_SendEditingText("", 0, 0); 271 return DBUS_HANDLER_RESULT_HANDLED; 272 } 273 274 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 275} 276 277static char *IBus_ReadAddressFromFile(const char *file_path) 278{ 279 char addr_buf[1024]; 280 bool success = false; 281 FILE *addr_file; 282 283 addr_file = fopen(file_path, "r"); 284 if (!addr_file) { 285 return NULL; 286 } 287 288 while (fgets(addr_buf, sizeof(addr_buf), addr_file)) { 289 if (SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=") - 1) == 0) { 290 size_t sz = SDL_strlen(addr_buf); 291 if (addr_buf[sz - 1] == '\n') { 292 addr_buf[sz - 1] = 0; 293 } 294 if (addr_buf[sz - 2] == '\r') { 295 addr_buf[sz - 2] = 0; 296 } 297 success = true; 298 break; 299 } 300 } 301 302 (void)fclose(addr_file); 303 304 if (success) { 305 return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1)); 306 } else { 307 return NULL; 308 } 309} 310 311static char *IBus_GetDBusAddressFilename(void) 312{ 313 SDL_DBusContext *dbus; 314 const char *disp_env; 315 char config_dir[PATH_MAX]; 316 char *display = NULL; 317 const char *addr; 318 const char *conf_env; 319 char *key; 320 char file_path[PATH_MAX]; 321 const char *host; 322 char *disp_num, *screen_num; 323 324 if (ibus_addr_file) { 325 return SDL_strdup(ibus_addr_file); 326 } 327 328 dbus = SDL_DBus_GetContext(); 329 if (!dbus) { 330 return NULL; 331 } 332 333 // Use this environment variable if it exists. 334 addr = SDL_getenv("IBUS_ADDRESS"); 335 if (addr && *addr) { 336 return SDL_strdup(addr); 337 } 338 339 /* Otherwise, we have to get the hostname, display, machine id, config dir 340 and look up the address from a filepath using all those bits, eek. */ 341 disp_env = SDL_getenv("DISPLAY"); 342 343 if (!disp_env || !*disp_env) { 344 display = SDL_strdup(":0.0"); 345 } else { 346 display = SDL_strdup(disp_env); 347 } 348 349 host = display; 350 disp_num = SDL_strrchr(display, ':'); 351 screen_num = SDL_strrchr(display, '.'); 352 353 if (!disp_num) { 354 SDL_free(display); 355 return NULL; 356 } 357 358 *disp_num = 0; 359 disp_num++; 360 361 if (screen_num) { 362 *screen_num = 0; 363 } 364 365 if (!*host) { 366 const char *session = SDL_getenv("XDG_SESSION_TYPE"); 367 if (session && SDL_strcmp(session, "wayland") == 0) { 368 host = "unix-wayland"; 369 } else { 370 host = "unix"; 371 } 372 } 373 374 SDL_zeroa(config_dir); 375 376 conf_env = SDL_getenv("XDG_CONFIG_HOME"); 377 if (conf_env && *conf_env) { 378 SDL_strlcpy(config_dir, conf_env, sizeof(config_dir)); 379 } else { 380 const char *home_env = SDL_getenv("HOME"); 381 if (!home_env || !*home_env) { 382 SDL_free(display); 383 return NULL; 384 } 385 (void)SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env); 386 } 387 388 key = SDL_DBus_GetLocalMachineId(); 389 390 if (!key) { 391 SDL_free(display); 392 return NULL; 393 } 394 395 SDL_zeroa(file_path); 396 (void)SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s", 397 config_dir, key, host, disp_num); 398 dbus->free(key); 399 SDL_free(display); 400 401 return SDL_strdup(file_path); 402} 403 404static bool IBus_CheckConnection(SDL_DBusContext *dbus); 405 406static void SDLCALL IBus_SetCapabilities(void *data, const char *name, const char *old_val, 407 const char *hint) 408{ 409 SDL_DBusContext *dbus = SDL_DBus_GetContext(); 410 411 if (IBus_CheckConnection(dbus)) { 412 Uint32 caps = IBUS_CAP_FOCUS; 413 414 if (hint && SDL_strstr(hint, "composition")) { 415 caps |= IBUS_CAP_PREEDIT_TEXT; 416 } 417 if (hint && SDL_strstr(hint, "candidates")) { 418 // FIXME, turn off native candidate rendering 419 } 420 421 SDL_DBus_CallVoidMethodOnConnection(ibus_conn, ibus_service, input_ctx_path, ibus_input_interface, "SetCapabilities", 422 DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID); 423 } 424} 425 426static bool IBus_SetupConnection(SDL_DBusContext *dbus, const char *addr) 427{ 428 const char *client_name = "SDL3_Application"; 429 DBusMessage *reply = NULL; 430 const char *path = NULL; 431 bool result = false; 432 DBusObjectPathVTable ibus_vtable; 433 434 SDL_zero(ibus_vtable); 435 ibus_vtable.message_function = &IBus_MessageHandler; 436 437 /* try the portal interface first. Modern systems have this in general, 438 and sandbox things like FlakPak and Snaps, etc, require it. */ 439 440 ibus_is_portal_interface = true; 441 ibus_service = IBUS_PORTAL_SERVICE; 442 ibus_interface = IBUS_PORTAL_INTERFACE; 443 ibus_input_interface = IBUS_PORTAL_INPUT_INTERFACE; 444 ibus_conn = dbus->session_conn; 445 446 result = SDL_DBus_CallMethodOnConnection(ibus_conn, &reply, ibus_service, IBUS_PATH, ibus_interface, "CreateInputContext", 447 DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID, 448 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); 449 if (!result) { 450 ibus_is_portal_interface = false; 451 ibus_service = IBUS_SERVICE; 452 ibus_interface = IBUS_INTERFACE; 453 ibus_input_interface = IBUS_INPUT_INTERFACE; 454 ibus_conn = dbus->connection_open_private(addr, NULL); 455 456 if (!ibus_conn) { 457 return false; // oh well. 458 } 459 460 dbus->connection_flush(ibus_conn); 461 462 if (!dbus->bus_register(ibus_conn, NULL)) { 463 ibus_conn = NULL; 464 return false; 465 } 466 467 dbus->connection_flush(ibus_conn); 468 469 result = SDL_DBus_CallMethodOnConnection(ibus_conn, &reply, ibus_service, IBUS_PATH, ibus_interface, "CreateInputContext", 470 DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID, 471 DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); 472 } else { 473 // reusing dbus->session_conn 474 dbus->connection_ref(ibus_conn); 475 } 476 477 if (result) { 478 char matchstr[128]; 479 (void)SDL_snprintf(matchstr, sizeof(matchstr), "type='signal',interface='%s'", ibus_input_interface); 480 SDL_free(input_ctx_path); 481 input_ctx_path = SDL_strdup(path); 482 SDL_AddHintCallback(SDL_HINT_IME_IMPLEMENTED_UI, IBus_SetCapabilities, NULL); 483 dbus->bus_add_match(ibus_conn, matchstr, NULL); 484 dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL); 485 dbus->connection_flush(ibus_conn); 486 } 487 SDL_DBus_FreeReply(&reply); 488 489 SDL_Window *window = SDL_GetKeyboardFocus(); 490 if (SDL_TextInputActive(window)) { 491 SDL_IBus_SetFocus(true); 492 SDL_IBus_UpdateTextInputArea(window); 493 } else { 494 SDL_IBus_SetFocus(false); 495 } 496 return result; 497} 498 499static bool IBus_CheckConnection(SDL_DBusContext *dbus) 500{ 501 if (!dbus) { 502 return false; 503 } 504 505 if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) { 506 return true; 507 } 508 509 if (inotify_fd > 0 && inotify_wd > 0) { 510 char buf[1024]; 511 ssize_t readsize = read(inotify_fd, buf, sizeof(buf)); 512 if (readsize > 0) { 513 514 char *p; 515 bool file_updated = false; 516 517 for (p = buf; p < buf + readsize; /**/) { 518 struct inotify_event *event = (struct inotify_event *)p; 519 if (event->len > 0) { 520 char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/'); 521 if (!addr_file_no_path) { 522 return false; 523 } 524 525 if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) { 526 file_updated = true; 527 break; 528 } 529 } 530 531 p += sizeof(struct inotify_event) + event->len; 532 } 533 534 if (file_updated) { 535 char *addr = IBus_ReadAddressFromFile(ibus_addr_file); 536 if (addr) { 537 bool result = IBus_SetupConnection(dbus, addr); 538 SDL_free(addr); 539 return result; 540 } 541 } 542 } 543 } 544 545 return false; 546} 547 548bool SDL_IBus_Init(void) 549{ 550 bool result = false; 551 SDL_DBusContext *dbus = SDL_DBus_GetContext(); 552 553 if (dbus) { 554 char *addr_file = IBus_GetDBusAddressFilename(); 555 char *addr; 556 char *addr_file_dir; 557 558 if (!addr_file) { 559 return false; 560 } 561 562 addr = IBus_ReadAddressFromFile(addr_file); 563 if (!addr) { 564 SDL_free(addr_file); 565 return false; 566 } 567 568 SDL_free(ibus_addr_file); 569 ibus_addr_file = SDL_strdup(addr_file); 570 571 if (inotify_fd < 0) { 572 inotify_fd = inotify_init(); 573 fcntl(inotify_fd, F_SETFL, O_NONBLOCK); 574 } 575 576 addr_file_dir = SDL_strrchr(addr_file, '/'); 577 if (addr_file_dir) { 578 *addr_file_dir = 0; 579 } 580 581 inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY); 582 SDL_free(addr_file); 583 584 result = IBus_SetupConnection(dbus, addr); 585 SDL_free(addr); 586 587 // don't use the addr_file if using the portal interface. 588 if (result && ibus_is_portal_interface) { 589 if (inotify_fd > 0) { 590 if (inotify_wd > 0) { 591 inotify_rm_watch(inotify_fd, inotify_wd); 592 inotify_wd = -1; 593 } 594 close(inotify_fd); 595 inotify_fd = -1; 596 } 597 } 598 } 599 600 return result; 601} 602 603void SDL_IBus_Quit(void) 604{ 605 SDL_DBusContext *dbus; 606 607 if (input_ctx_path) { 608 SDL_free(input_ctx_path); 609 input_ctx_path = NULL; 610 } 611 612 if (ibus_addr_file) { 613 SDL_free(ibus_addr_file); 614 ibus_addr_file = NULL; 615 } 616 617 dbus = SDL_DBus_GetContext(); 618 619 // if using portal, ibus_conn == session_conn; don't release it here. 620 if (dbus && ibus_conn && !ibus_is_portal_interface) { 621 dbus->connection_close(ibus_conn); 622 dbus->connection_unref(ibus_conn); 623 } 624 625 ibus_conn = NULL; 626 ibus_service = NULL; 627 ibus_interface = NULL; 628 ibus_input_interface = NULL; 629 ibus_is_portal_interface = false; 630 631 if (inotify_fd > 0 && inotify_wd > 0) { 632 inotify_rm_watch(inotify_fd, inotify_wd); 633 inotify_wd = -1; 634 } 635 636 // !!! FIXME: should we close(inotify_fd) here? 637 638 SDL_RemoveHintCallback(SDL_HINT_IME_IMPLEMENTED_UI, IBus_SetCapabilities, NULL); 639 640 SDL_zero(ibus_cursor_rect); 641} 642 643static void IBus_SimpleMessage(const char *method) 644{ 645 SDL_DBusContext *dbus = SDL_DBus_GetContext(); 646 647 if ((input_ctx_path) && (IBus_CheckConnection(dbus))) { 648 SDL_DBus_CallVoidMethodOnConnection(ibus_conn, ibus_service, input_ctx_path, ibus_input_interface, method, DBUS_TYPE_INVALID); 649 } 650} 651 652void SDL_IBus_SetFocus(bool focused) 653{ 654 const char *method = focused ? "FocusIn" : "FocusOut"; 655 IBus_SimpleMessage(method); 656} 657 658void SDL_IBus_Reset(void) 659{ 660 IBus_SimpleMessage("Reset"); 661} 662 663bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, bool down) 664{ 665 Uint32 result = 0; 666 SDL_DBusContext *dbus = SDL_DBus_GetContext(); 667 668 if (IBus_CheckConnection(dbus)) { 669 Uint32 mods = IBus_ModState(); 670 Uint32 ibus_keycode = keycode - 8; 671 if (!down) { 672 mods |= (1 << 30); // IBUS_RELEASE_MASK 673 } 674 if (!SDL_DBus_CallMethodOnConnection(ibus_conn, NULL, ibus_service, input_ctx_path, ibus_input_interface, "ProcessKeyEvent", 675 DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &ibus_keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID, 676 DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) { 677 result = 0; 678 } 679 } 680 681 SDL_IBus_UpdateTextInputArea(SDL_GetKeyboardFocus()); 682 683 return (result != 0); 684} 685 686void SDL_IBus_UpdateTextInputArea(SDL_Window *window) 687{ 688 int x = 0, y = 0; 689 SDL_DBusContext *dbus; 690 691 if (!window) { 692 return; 693 } 694 695 // We'll use a square at the text input cursor location for the ibus_cursor 696 ibus_cursor_rect.x = window->text_input_rect.x + window->text_input_cursor; 697 ibus_cursor_rect.y = window->text_input_rect.y; 698 ibus_cursor_rect.w = window->text_input_rect.h; 699 ibus_cursor_rect.h = window->text_input_rect.h; 700 701 SDL_GetWindowPosition(window, &x, &y); 702 703#ifdef SDL_VIDEO_DRIVER_X11 704 { 705 SDL_PropertiesID props = SDL_GetWindowProperties(window); 706 Display *x_disp = (Display *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL); 707 int x_screen = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_SCREEN_NUMBER, 0); 708 Window x_win = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); 709 Window unused; 710 711 if (x_disp && x_win) { 712 X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused); 713 } 714 } 715#endif 716 717 x += ibus_cursor_rect.x; 718 y += ibus_cursor_rect.y; 719 720 dbus = SDL_DBus_GetContext(); 721 722 if (IBus_CheckConnection(dbus)) { 723 SDL_DBus_CallVoidMethodOnConnection(ibus_conn, ibus_service, input_ctx_path, ibus_input_interface, "SetCursorLocation", 724 DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &ibus_cursor_rect.w, DBUS_TYPE_INT32, &ibus_cursor_rect.h, DBUS_TYPE_INVALID); 725 } 726} 727 728void SDL_IBus_PumpEvents(void) 729{ 730 SDL_DBusContext *dbus = SDL_DBus_GetContext(); 731 732 if (IBus_CheckConnection(dbus)) { 733 dbus->connection_read_write(ibus_conn, 0); 734 735 while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) { 736 // Do nothing, actual work happens in IBus_MessageHandler 737 } 738 } 739} 740 741#endif // SDL_USE_LIBDBUS 742 743#endif 744
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.