src/core/linux/SDL_ibus.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 04 Jan 2019 22:01:14 -0800
changeset 12503 806492103856
parent 11870 b548450528c9
permissions -rw-r--r--
Updated copyright for 2019
alex@8889
     1
/*
alex@8889
     2
  Simple DirectMedia Layer
slouken@12503
     3
  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
alex@8889
     4
alex@8889
     5
  This software is provided 'as-is', without any express or implied
alex@8889
     6
  warranty.  In no event will the authors be held liable for any damages
alex@8889
     7
  arising from the use of this software.
alex@8889
     8
alex@8889
     9
  Permission is granted to anyone to use this software for any purpose,
alex@8889
    10
  including commercial applications, and to alter it and redistribute it
alex@8889
    11
  freely, subject to the following restrictions:
alex@8889
    12
alex@8889
    13
  1. The origin of this software must not be misrepresented; you must not
alex@8889
    14
     claim that you wrote the original software. If you use this software
alex@8889
    15
     in a product, an acknowledgment in the product documentation would be
alex@8889
    16
     appreciated but is not required.
alex@8889
    17
  2. Altered source versions must be plainly marked as such, and must not be
alex@8889
    18
     misrepresented as being the original software.
alex@8889
    19
  3. This notice may not be removed or altered from any source distribution.
alex@8889
    20
*/
alex@8889
    21
#include "../../SDL_internal.h"
alex@8889
    22
alex@8889
    23
#ifdef HAVE_IBUS_IBUS_H
alex@8889
    24
#include "SDL.h"
alex@9095
    25
#include "SDL_syswm.h"
alex@8889
    26
#include "SDL_ibus.h"
alex@8889
    27
#include "SDL_dbus.h"
alex@8889
    28
#include "../../video/SDL_sysvideo.h"
alex@8889
    29
#include "../../events/SDL_keyboard_c.h"
alex@9095
    30
alex@9095
    31
#if SDL_VIDEO_DRIVER_X11
alex@9095
    32
    #include "../../video/x11/SDL_x11video.h"
alex@9095
    33
#endif
alex@9095
    34
alex@8889
    35
#include <sys/inotify.h>
alex@8889
    36
#include <unistd.h>
alex@8889
    37
#include <fcntl.h>
alex@8889
    38
alex@8889
    39
static const char IBUS_SERVICE[]         = "org.freedesktop.IBus";
alex@8889
    40
static const char IBUS_PATH[]            = "/org/freedesktop/IBus";
alex@8889
    41
static const char IBUS_INTERFACE[]       = "org.freedesktop.IBus";
alex@8889
    42
static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
alex@8889
    43
alex@8889
    44
static char *input_ctx_path = NULL;
slouken@10462
    45
static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 };
alex@8889
    46
static DBusConnection *ibus_conn = NULL;
alex@8889
    47
static char *ibus_addr_file = NULL;
philipp@10970
    48
static int inotify_fd = -1, inotify_wd = -1;
alex@8889
    49
alex@8889
    50
static Uint32
alex@8889
    51
IBus_ModState(void)
alex@8889
    52
{
alex@8889
    53
    Uint32 ibus_mods = 0;
alex@8889
    54
    SDL_Keymod sdl_mods = SDL_GetModState();
alex@8889
    55
    
alex@8889
    56
    /* Not sure about MOD3, MOD4 and HYPER mappings */
icculus@9107
    57
    if (sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
icculus@9107
    58
    if (sdl_mods & KMOD_CAPS)   ibus_mods |= IBUS_LOCK_MASK;
icculus@9107
    59
    if (sdl_mods & KMOD_LCTRL)  ibus_mods |= IBUS_CONTROL_MASK;
icculus@9107
    60
    if (sdl_mods & KMOD_LALT)   ibus_mods |= IBUS_MOD1_MASK;
icculus@9107
    61
    if (sdl_mods & KMOD_NUM)    ibus_mods |= IBUS_MOD2_MASK;
icculus@9107
    62
    if (sdl_mods & KMOD_MODE)   ibus_mods |= IBUS_MOD5_MASK;
icculus@9107
    63
    if (sdl_mods & KMOD_LGUI)   ibus_mods |= IBUS_SUPER_MASK;
icculus@9107
    64
    if (sdl_mods & KMOD_RGUI)   ibus_mods |= IBUS_META_MASK;
alex@8889
    65
alex@8889
    66
    return ibus_mods;
alex@8889
    67
}
alex@8889
    68
alex@8889
    69
static const char *
alex@8889
    70
IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
alex@8889
    71
{
alex@8889
    72
    /* The text we need is nested weirdly, use dbus-monitor to see the structure better */
alex@8889
    73
    const char *text = NULL;
icculus@9108
    74
    const char *struct_id = NULL;
alex@8889
    75
    DBusMessageIter sub1, sub2;
alex@8889
    76
icculus@9107
    77
    if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
alex@8889
    78
        return NULL;
alex@8889
    79
    }
alex@8889
    80
    
alex@8889
    81
    dbus->message_iter_recurse(iter, &sub1);
alex@8889
    82
    
icculus@9107
    83
    if (dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) {
alex@8889
    84
        return NULL;
alex@8889
    85
    }
alex@8889
    86
    
alex@8889
    87
    dbus->message_iter_recurse(&sub1, &sub2);
alex@8889
    88
    
icculus@9107
    89
    if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
alex@8889
    90
        return NULL;
alex@8889
    91
    }
alex@8889
    92
    
alex@8889
    93
    dbus->message_iter_get_basic(&sub2, &struct_id);
icculus@9107
    94
    if (!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0) {
alex@8889
    95
        return NULL;
alex@8889
    96
    }
alex@8889
    97
    
alex@8889
    98
    dbus->message_iter_next(&sub2);
alex@8889
    99
    dbus->message_iter_next(&sub2);
alex@8889
   100
    
icculus@9107
   101
    if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
alex@8889
   102
        return NULL;
alex@8889
   103
    }
alex@8889
   104
    
alex@8889
   105
    dbus->message_iter_get_basic(&sub2, &text);
alex@8889
   106
    
alex@8889
   107
    return text;
alex@8889
   108
}
alex@8889
   109
alex@8889
   110
static DBusHandlerResult
alex@9646
   111
IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data)
alex@8889
   112
{
alex@8889
   113
    SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
alex@8889
   114
        
icculus@9107
   115
    if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")) {
alex@8889
   116
        DBusMessageIter iter;
icculus@9108
   117
        const char *text;
icculus@9107
   118
alex@8889
   119
        dbus->message_iter_init(msg, &iter);
alex@8889
   120
        
icculus@9108
   121
        text = IBus_GetVariantText(conn, &iter, dbus);
icculus@9107
   122
        if (text && *text) {
philipp@11099
   123
            char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
alex@8889
   124
            size_t text_bytes = SDL_strlen(text), i = 0;
alex@8889
   125
            
icculus@9107
   126
            while (i < text_bytes) {
alex@8889
   127
                size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
alex@8889
   128
                SDL_SendKeyboardText(buf);
alex@8889
   129
                
alex@8889
   130
                i += sz;
alex@8889
   131
            }
alex@8889
   132
        }
alex@8889
   133
        
alex@8889
   134
        return DBUS_HANDLER_RESULT_HANDLED;
alex@8889
   135
    }
alex@8889
   136
    
icculus@9107
   137
    if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")) {
alex@8889
   138
        DBusMessageIter iter;
icculus@9108
   139
        const char *text;
icculus@9108
   140
alex@8889
   141
        dbus->message_iter_init(msg, &iter);
icculus@9108
   142
        text = IBus_GetVariantText(conn, &iter, dbus);
alex@8889
   143
        
alex@9645
   144
        if (text) {
alex@8889
   145
            char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
alex@8889
   146
            size_t text_bytes = SDL_strlen(text), i = 0;
alex@8889
   147
            size_t cursor = 0;
alex@8889
   148
            
alex@9645
   149
            do {
icculus@11051
   150
                const size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
icculus@11051
   151
                const size_t chars = SDL_utf8strlen(buf);
alex@8889
   152
                
alex@8889
   153
                SDL_SendEditingText(buf, cursor, chars);
alex@8889
   154
alex@8889
   155
                i += sz;
alex@8889
   156
                cursor += chars;
alex@9645
   157
            } while (i < text_bytes);
alex@8889
   158
        }
alex@8889
   159
        
alex@8889
   160
        SDL_IBus_UpdateTextRect(NULL);
alex@8889
   161
        
alex@8889
   162
        return DBUS_HANDLER_RESULT_HANDLED;
alex@8889
   163
    }
alex@8889
   164
    
icculus@9107
   165
    if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "HidePreeditText")) {
icculus@9107
   166
        SDL_SendEditingText("", 0, 0);
icculus@9107
   167
        return DBUS_HANDLER_RESULT_HANDLED;
alex@9096
   168
    }
alex@9096
   169
    
alex@8889
   170
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
alex@8889
   171
}
alex@8889
   172
alex@8889
   173
static char *
alex@8889
   174
IBus_ReadAddressFromFile(const char *file_path)
alex@8889
   175
{
icculus@9108
   176
    char addr_buf[1024];
icculus@9108
   177
    SDL_bool success = SDL_FALSE;
icculus@9108
   178
    FILE *addr_file;
icculus@9108
   179
icculus@9108
   180
    addr_file = fopen(file_path, "r");
icculus@9107
   181
    if (!addr_file) {
alex@8889
   182
        return NULL;
alex@8889
   183
    }
alex@8889
   184
icculus@9107
   185
    while (fgets(addr_buf, sizeof(addr_buf), addr_file)) {
icculus@9107
   186
        if (SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
alex@8889
   187
            size_t sz = SDL_strlen(addr_buf);
icculus@9107
   188
            if (addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
icculus@9107
   189
            if (addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
alex@8889
   190
            success = SDL_TRUE;
alex@8889
   191
            break;
alex@8889
   192
        }
alex@8889
   193
    }
alex@8889
   194
alex@8889
   195
    fclose(addr_file);
alex@8889
   196
icculus@9107
   197
    if (success) {
alex@8889
   198
        return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
alex@8889
   199
    } else {
alex@8889
   200
        return NULL;
alex@8889
   201
    }
alex@8889
   202
}
alex@8889
   203
alex@8889
   204
static char *
alex@8889
   205
IBus_GetDBusAddressFilename(void)
alex@8889
   206
{
icculus@9108
   207
    SDL_DBusContext *dbus;
icculus@9108
   208
    const char *disp_env;
icculus@9108
   209
    char config_dir[PATH_MAX];
icculus@9108
   210
    char *display = NULL;
icculus@9108
   211
    const char *addr;
icculus@9108
   212
    const char *conf_env;
icculus@9108
   213
    char *key;
icculus@9108
   214
    char file_path[PATH_MAX];
slouken@9114
   215
    const char *host;
slouken@9114
   216
    char *disp_num, *screen_num;
icculus@9108
   217
icculus@9107
   218
    if (ibus_addr_file) {
alex@8889
   219
        return SDL_strdup(ibus_addr_file);
alex@8889
   220
    }
alex@8889
   221
    
icculus@9108
   222
    dbus = SDL_DBus_GetContext();
icculus@9107
   223
    if (!dbus) {
alex@8889
   224
        return NULL;
alex@8889
   225
    }
alex@8889
   226
    
alex@8889
   227
    /* Use this environment variable if it exists. */
icculus@9108
   228
    addr = SDL_getenv("IBUS_ADDRESS");
icculus@9107
   229
    if (addr && *addr) {
alex@8889
   230
        return SDL_strdup(addr);
alex@8889
   231
    }
alex@8889
   232
    
alex@8889
   233
    /* Otherwise, we have to get the hostname, display, machine id, config dir
alex@8889
   234
       and look up the address from a filepath using all those bits, eek. */
icculus@9108
   235
    disp_env = SDL_getenv("DISPLAY");
icculus@9108
   236
icculus@9107
   237
    if (!disp_env || !*disp_env) {
alex@8889
   238
        display = SDL_strdup(":0.0");
alex@8889
   239
    } else {
alex@8889
   240
        display = SDL_strdup(disp_env);
alex@8889
   241
    }
alex@8889
   242
    
slouken@9114
   243
    host = display;
slouken@9114
   244
    disp_num   = SDL_strrchr(display, ':');
slouken@9114
   245
    screen_num = SDL_strrchr(display, '.');
alex@8889
   246
    
icculus@9107
   247
    if (!disp_num) {
alex@8889
   248
        SDL_free(display);
alex@8889
   249
        return NULL;
alex@8889
   250
    }
alex@8889
   251
    
alex@8889
   252
    *disp_num = 0;
alex@8889
   253
    disp_num++;
alex@8889
   254
    
icculus@9107
   255
    if (screen_num) {
alex@8889
   256
        *screen_num = 0;
alex@8889
   257
    }
alex@8889
   258
    
icculus@9107
   259
    if (!*host) {
alex@8889
   260
        host = "unix";
alex@8889
   261
    }
alex@8889
   262
        
alex@8889
   263
    SDL_memset(config_dir, 0, sizeof(config_dir));
alex@8889
   264
    
icculus@9108
   265
    conf_env = SDL_getenv("XDG_CONFIG_HOME");
icculus@9107
   266
    if (conf_env && *conf_env) {
alex@8889
   267
        SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
alex@8889
   268
    } else {
alex@8889
   269
        const char *home_env = SDL_getenv("HOME");
icculus@9107
   270
        if (!home_env || !*home_env) {
alex@8889
   271
            SDL_free(display);
alex@8889
   272
            return NULL;
alex@8889
   273
        }
alex@8889
   274
        SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
alex@8889
   275
    }
alex@8889
   276
    
icculus@9108
   277
    key = dbus->get_local_machine_id();
icculus@9108
   278
alex@8889
   279
    SDL_memset(file_path, 0, sizeof(file_path));
alex@8889
   280
    SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s", 
alex@8889
   281
                                               config_dir, key, host, disp_num);
alex@8889
   282
    dbus->free(key);
alex@8889
   283
    SDL_free(display);
alex@8889
   284
    
alex@8889
   285
    return SDL_strdup(file_path);
alex@8889
   286
}
alex@8889
   287
alex@9097
   288
static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
alex@9097
   289
slouken@11284
   290
static void SDLCALL
alex@9097
   291
IBus_SetCapabilities(void *data, const char *name, const char *old_val,
alex@9097
   292
                                                   const char *internal_editing)
alex@9097
   293
{
alex@9097
   294
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@9097
   295
    
icculus@9107
   296
    if (IBus_CheckConnection(dbus)) {
icculus@11042
   297
        Uint32 caps = IBUS_CAP_FOCUS;
icculus@11042
   298
        if (!(internal_editing && *internal_editing == '1')) {
icculus@11042
   299
            caps |= IBUS_CAP_PREEDIT_TEXT;
icculus@11042
   300
        }
alex@9097
   301
slouken@11870
   302
        SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "SetCapabilities",
icculus@11042
   303
                                DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID);
alex@9097
   304
    }
alex@9097
   305
}
alex@9097
   306
alex@9097
   307
alex@8889
   308
static SDL_bool
alex@8889
   309
IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
alex@8889
   310
{
icculus@11042
   311
    const char *client_name = "SDL2_Application";
alex@8889
   312
    const char *path = NULL;
alex@8889
   313
    SDL_bool result = SDL_FALSE;
slouken@10462
   314
    DBusObjectPathVTable ibus_vtable;
slouken@10462
   315
slouken@10462
   316
    SDL_zero(ibus_vtable);
alex@9646
   317
    ibus_vtable.message_function = &IBus_MessageHandler;
icculus@9108
   318
alex@8889
   319
    ibus_conn = dbus->connection_open_private(addr, NULL);
alex@8889
   320
icculus@9107
   321
    if (!ibus_conn) {
alex@8889
   322
        return SDL_FALSE;
alex@8889
   323
    }
alex@8889
   324
alex@8889
   325
    dbus->connection_flush(ibus_conn);
alex@8889
   326
    
icculus@9107
   327
    if (!dbus->bus_register(ibus_conn, NULL)) {
alex@8889
   328
        ibus_conn = NULL;
alex@8889
   329
        return SDL_FALSE;
alex@8889
   330
    }
alex@8889
   331
    
alex@8889
   332
    dbus->connection_flush(ibus_conn);
alex@8889
   333
icculus@11042
   334
    if (SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext",
icculus@11042
   335
            DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID,
icculus@11042
   336
            DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
icculus@11042
   337
        SDL_free(input_ctx_path);
icculus@11042
   338
        input_ctx_path = SDL_strdup(path);
slouken@11284
   339
        SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, IBus_SetCapabilities, NULL);
alex@8889
   340
        
alex@8889
   341
        dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
alex@9646
   342
        dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL);
alex@8889
   343
        dbus->connection_flush(ibus_conn);
slouken@11870
   344
        result = SDL_TRUE;
alex@8889
   345
    }
alex@8889
   346
alex@9096
   347
    SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
alex@8889
   348
    SDL_IBus_UpdateTextRect(NULL);
alex@8889
   349
    
alex@8889
   350
    return result;
alex@8889
   351
}
alex@8889
   352
alex@8889
   353
static SDL_bool
alex@8889
   354
IBus_CheckConnection(SDL_DBusContext *dbus)
alex@8889
   355
{
icculus@9107
   356
    if (!dbus) return SDL_FALSE;
alex@8889
   357
    
icculus@9107
   358
    if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
alex@8889
   359
        return SDL_TRUE;
alex@8889
   360
    }
alex@8889
   361
    
icculus@9107
   362
    if (inotify_fd > 0 && inotify_wd > 0) {
alex@8889
   363
        char buf[1024];
alex@8889
   364
        ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
icculus@9107
   365
        if (readsize > 0) {
alex@8889
   366
        
alex@8889
   367
            char *p;
alex@8889
   368
            SDL_bool file_updated = SDL_FALSE;
alex@8889
   369
            
icculus@9107
   370
            for (p = buf; p < buf + readsize; /**/) {
alex@8889
   371
                struct inotify_event *event = (struct inotify_event*) p;
icculus@9107
   372
                if (event->len > 0) {
alex@8889
   373
                    char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
icculus@9107
   374
                    if (!addr_file_no_path) return SDL_FALSE;
alex@8889
   375
                 
icculus@9107
   376
                    if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) {
alex@8889
   377
                        file_updated = SDL_TRUE;
alex@8889
   378
                        break;
alex@8889
   379
                    }
alex@8889
   380
                }
alex@8889
   381
                
alex@8889
   382
                p += sizeof(struct inotify_event) + event->len;
alex@8889
   383
            }
alex@8889
   384
            
icculus@9107
   385
            if (file_updated) {
alex@8889
   386
                char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
icculus@9107
   387
                if (addr) {
alex@8889
   388
                    SDL_bool result = IBus_SetupConnection(dbus, addr);
alex@8889
   389
                    SDL_free(addr);
alex@8889
   390
                    return result;
alex@8889
   391
                }
alex@8889
   392
            }
alex@8889
   393
        }
alex@8889
   394
    }
alex@8889
   395
    
alex@8889
   396
    return SDL_FALSE;
alex@8889
   397
}
alex@8889
   398
alex@8889
   399
SDL_bool
alex@8889
   400
SDL_IBus_Init(void)
alex@8889
   401
{
alex@8889
   402
    SDL_bool result = SDL_FALSE;
alex@8889
   403
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   404
    
icculus@9107
   405
    if (dbus) {
alex@8889
   406
        char *addr_file = IBus_GetDBusAddressFilename();
icculus@9108
   407
        char *addr;
icculus@9108
   408
        char *addr_file_dir;
icculus@9108
   409
icculus@9107
   410
        if (!addr_file) {
alex@8889
   411
            return SDL_FALSE;
alex@8889
   412
        }
alex@8889
   413
        
icculus@9712
   414
        /* !!! FIXME: if ibus_addr_file != NULL, this will overwrite it and leak (twice!) */
alex@8889
   415
        ibus_addr_file = SDL_strdup(addr_file);
alex@8889
   416
        
icculus@9108
   417
        addr = IBus_ReadAddressFromFile(addr_file);
urkle@9451
   418
        if (!addr) {
icculus@9712
   419
            SDL_free(addr_file);
urkle@9451
   420
            return SDL_FALSE;
urkle@9451
   421
        }
alex@8889
   422
        
icculus@9107
   423
        if (inotify_fd < 0) {
alex@9096
   424
            inotify_fd = inotify_init();
alex@9096
   425
            fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
alex@9096
   426
        }
alex@8889
   427
        
icculus@9108
   428
        addr_file_dir = SDL_strrchr(addr_file, '/');
icculus@9107
   429
        if (addr_file_dir) {
alex@8889
   430
            *addr_file_dir = 0;
alex@8889
   431
        }
alex@8889
   432
        
alex@9096
   433
        inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
alex@8889
   434
        SDL_free(addr_file);
alex@8889
   435
        
alex@9462
   436
        if (addr) {
alex@9462
   437
            result = IBus_SetupConnection(dbus, addr);
alex@9462
   438
            SDL_free(addr);
alex@9462
   439
        }
alex@8889
   440
    }
alex@8889
   441
    
alex@8889
   442
    return result;
alex@8889
   443
}
alex@8889
   444
alex@8889
   445
void
alex@8889
   446
SDL_IBus_Quit(void)
alex@8889
   447
{   
icculus@9108
   448
    SDL_DBusContext *dbus;
icculus@9108
   449
icculus@9107
   450
    if (input_ctx_path) {
alex@8889
   451
        SDL_free(input_ctx_path);
alex@8889
   452
        input_ctx_path = NULL;
alex@8889
   453
    }
alex@8889
   454
    
icculus@9107
   455
    if (ibus_addr_file) {
alex@8889
   456
        SDL_free(ibus_addr_file);
alex@8889
   457
        ibus_addr_file = NULL;
alex@8889
   458
    }
alex@8889
   459
    
icculus@9108
   460
    dbus = SDL_DBus_GetContext();
alex@8889
   461
    
icculus@9107
   462
    if (dbus && ibus_conn) {
alex@8889
   463
        dbus->connection_close(ibus_conn);
alex@8889
   464
        dbus->connection_unref(ibus_conn);
alex@8889
   465
    }
alex@8889
   466
    
icculus@9107
   467
    if (inotify_fd > 0 && inotify_wd > 0) {
alex@9096
   468
        inotify_rm_watch(inotify_fd, inotify_wd);
alex@9096
   469
        inotify_wd = -1;
alex@9096
   470
    }
alex@9096
   471
    
slouken@11284
   472
    SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, IBus_SetCapabilities, NULL);
alex@9097
   473
    
alex@8889
   474
    SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
alex@8889
   475
}
alex@8889
   476
alex@8889
   477
static void
alex@8889
   478
IBus_SimpleMessage(const char *method)
alex@8889
   479
{   
alex@8889
   480
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   481
    
icculus@9107
   482
    if (IBus_CheckConnection(dbus)) {
slouken@11567
   483
        SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID);
alex@8889
   484
    }
alex@8889
   485
}
alex@8889
   486
alex@8889
   487
void
alex@8889
   488
SDL_IBus_SetFocus(SDL_bool focused)
alex@8889
   489
{ 
alex@8889
   490
    const char *method = focused ? "FocusIn" : "FocusOut";
alex@8889
   491
    IBus_SimpleMessage(method);
alex@8889
   492
}
alex@8889
   493
alex@8889
   494
void
alex@8889
   495
SDL_IBus_Reset(void)
alex@8889
   496
{
alex@8889
   497
    IBus_SimpleMessage("Reset");
alex@8889
   498
}
alex@8889
   499
alex@8889
   500
SDL_bool
alex@8889
   501
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
alex@8889
   502
{ 
icculus@11042
   503
    Uint32 result = 0;
alex@8889
   504
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   505
    
icculus@9107
   506
    if (IBus_CheckConnection(dbus)) {
icculus@11042
   507
        Uint32 mods = IBus_ModState();
icculus@11042
   508
        if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
icculus@11042
   509
                DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID,
icculus@11042
   510
                DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) {
icculus@11042
   511
            result = 0;
alex@8889
   512
        }
alex@8889
   513
    }
alex@8889
   514
    
alex@9097
   515
    SDL_IBus_UpdateTextRect(NULL);
alex@9097
   516
icculus@11042
   517
    return result ? SDL_TRUE : SDL_FALSE;
alex@8889
   518
}
alex@8889
   519
alex@8889
   520
void
alex@8889
   521
SDL_IBus_UpdateTextRect(SDL_Rect *rect)
alex@8889
   522
{
slouken@9113
   523
    SDL_Window *focused_win;
slouken@9113
   524
    SDL_SysWMinfo info;
icculus@9108
   525
    int x = 0, y = 0;
icculus@9108
   526
    SDL_DBusContext *dbus;
icculus@9108
   527
icculus@9107
   528
    if (rect) {
alex@8889
   529
        SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
alex@8889
   530
    }
alex@8889
   531
slouken@9113
   532
    focused_win = SDL_GetKeyboardFocus();
icculus@9107
   533
    if (!focused_win) {
icculus@9107
   534
        return;
icculus@9107
   535
    }
icculus@9107
   536
alex@9095
   537
    SDL_VERSION(&info.version);
icculus@9107
   538
    if (!SDL_GetWindowWMInfo(focused_win, &info)) {
icculus@9107
   539
        return;
icculus@9107
   540
    }
icculus@9108
   541
alex@9095
   542
    SDL_GetWindowPosition(focused_win, &x, &y);
alex@9095
   543
   
alex@9095
   544
#if SDL_VIDEO_DRIVER_X11    
icculus@9107
   545
    if (info.subsystem == SDL_SYSWM_X11) {
icculus@9107
   546
        SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
alex@9095
   547
            
alex@9095
   548
        Display *x_disp = info.info.x11.display;
alex@9095
   549
        Window x_win = info.info.x11.window;
alex@9095
   550
        int x_screen = displaydata->screen;
alex@9095
   551
        Window unused;
alex@9095
   552
            
icculus@9107
   553
        X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
alex@9095
   554
    }
alex@9095
   555
#endif
alex@8889
   556
alex@8889
   557
    x += ibus_cursor_rect.x;
alex@8889
   558
    y += ibus_cursor_rect.y;
alex@8889
   559
        
icculus@9108
   560
    dbus = SDL_DBus_GetContext();
alex@8889
   561
    
icculus@9107
   562
    if (IBus_CheckConnection(dbus)) {
icculus@11042
   563
        SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "SetCursorLocation",
icculus@11042
   564
                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);
alex@8889
   565
    }
alex@8889
   566
}
alex@8889
   567
alex@8889
   568
void
alex@8889
   569
SDL_IBus_PumpEvents(void)
alex@8889
   570
{
alex@8889
   571
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   572
    
icculus@9107
   573
    if (IBus_CheckConnection(dbus)) {
alex@8889
   574
        dbus->connection_read_write(ibus_conn, 0);
alex@8889
   575
    
icculus@9107
   576
        while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
alex@9646
   577
            /* Do nothing, actual work happens in IBus_MessageHandler */
alex@8889
   578
        }
alex@8889
   579
    }
alex@8889
   580
}
alex@8889
   581
alex@8889
   582
#endif
slouken@10660
   583
slouken@10660
   584
/* vi: set ts=4 sw=4 expandtab: */