src/core/linux/SDL_ibus.c
author Alex Baines <alex@abaines.me.uk>
Wed, 18 Jun 2014 20:11:39 +0100
changeset 8889 26a6243b27c2
child 9009 ddbca09f8f9d
permissions -rw-r--r--
Add IBus IME Support, move DBus code to its own file. (v3.3 squashed)
alex@8889
     1
/*
alex@8889
     2
  Simple DirectMedia Layer
alex@8889
     3
  Copyright (C) 1997-2014 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@8889
    25
#include "SDL_ibus.h"
alex@8889
    26
#include "SDL_dbus.h"
alex@8889
    27
#include "../../video/SDL_sysvideo.h"
alex@8889
    28
#include "../../events/SDL_keyboard_c.h"
alex@8889
    29
#include <sys/inotify.h>
alex@8889
    30
#include <unistd.h>
alex@8889
    31
#include <fcntl.h>
alex@8889
    32
alex@8889
    33
static const char IBUS_SERVICE[]         = "org.freedesktop.IBus";
alex@8889
    34
static const char IBUS_PATH[]            = "/org/freedesktop/IBus";
alex@8889
    35
static const char IBUS_INTERFACE[]       = "org.freedesktop.IBus";
alex@8889
    36
static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
alex@8889
    37
alex@8889
    38
static char *input_ctx_path = NULL;
alex@8889
    39
static SDL_Rect ibus_cursor_rect = {0};
alex@8889
    40
static DBusConnection *ibus_conn = NULL;
alex@8889
    41
static char *ibus_addr_file = NULL;
alex@8889
    42
int inotify_fd = -1;
alex@8889
    43
alex@8889
    44
static Uint32
alex@8889
    45
IBus_ModState(void)
alex@8889
    46
{
alex@8889
    47
    Uint32 ibus_mods = 0;
alex@8889
    48
    SDL_Keymod sdl_mods = SDL_GetModState();
alex@8889
    49
    
alex@8889
    50
    /* Not sure about MOD3, MOD4 and HYPER mappings */
alex@8889
    51
    if(sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
alex@8889
    52
    if(sdl_mods & KMOD_CAPS)   ibus_mods |= IBUS_LOCK_MASK;
alex@8889
    53
    if(sdl_mods & KMOD_LCTRL)  ibus_mods |= IBUS_CONTROL_MASK;
alex@8889
    54
    if(sdl_mods & KMOD_LALT)   ibus_mods |= IBUS_MOD1_MASK;
alex@8889
    55
    if(sdl_mods & KMOD_NUM)    ibus_mods |= IBUS_MOD2_MASK;
alex@8889
    56
    if(sdl_mods & KMOD_MODE)   ibus_mods |= IBUS_MOD5_MASK;
alex@8889
    57
    if(sdl_mods & KMOD_LGUI)   ibus_mods |= IBUS_SUPER_MASK;
alex@8889
    58
    if(sdl_mods & KMOD_RGUI)   ibus_mods |= IBUS_META_MASK;
alex@8889
    59
alex@8889
    60
    return ibus_mods;
alex@8889
    61
}
alex@8889
    62
alex@8889
    63
static const char *
alex@8889
    64
IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
alex@8889
    65
{
alex@8889
    66
    /* The text we need is nested weirdly, use dbus-monitor to see the structure better */
alex@8889
    67
    const char *text = NULL;
alex@8889
    68
    DBusMessageIter sub1, sub2;
alex@8889
    69
alex@8889
    70
    if(dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT){
alex@8889
    71
        return NULL;
alex@8889
    72
    }
alex@8889
    73
    
alex@8889
    74
    dbus->message_iter_recurse(iter, &sub1);
alex@8889
    75
    
alex@8889
    76
    if(dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT){
alex@8889
    77
        return NULL;
alex@8889
    78
    }
alex@8889
    79
    
alex@8889
    80
    dbus->message_iter_recurse(&sub1, &sub2);
alex@8889
    81
    
alex@8889
    82
    if(dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING){
alex@8889
    83
        return NULL;
alex@8889
    84
    }
alex@8889
    85
    
alex@8889
    86
    const char *struct_id = NULL;
alex@8889
    87
    dbus->message_iter_get_basic(&sub2, &struct_id);
alex@8889
    88
    if(!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0){
alex@8889
    89
        return NULL;
alex@8889
    90
    }
alex@8889
    91
    
alex@8889
    92
    dbus->message_iter_next(&sub2);
alex@8889
    93
    dbus->message_iter_next(&sub2);
alex@8889
    94
    
alex@8889
    95
    if(dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING){
alex@8889
    96
        return NULL;
alex@8889
    97
    }
alex@8889
    98
    
alex@8889
    99
    dbus->message_iter_get_basic(&sub2, &text);
alex@8889
   100
    
alex@8889
   101
    return text;
alex@8889
   102
}
alex@8889
   103
alex@8889
   104
static size_t 
alex@8889
   105
IBus_utf8_strlen(const char *str)
alex@8889
   106
{
alex@8889
   107
    size_t utf8_len = 0;
alex@8889
   108
    const char *p;
alex@8889
   109
    
alex@8889
   110
    for(p = str; *p; ++p){
alex@8889
   111
        if(!((*p & 0x80) && !(*p & 0x40))){
alex@8889
   112
            ++utf8_len;
alex@8889
   113
        }
alex@8889
   114
    }
alex@8889
   115
    
alex@8889
   116
    return utf8_len;
alex@8889
   117
}
alex@8889
   118
alex@8889
   119
static DBusHandlerResult
alex@8889
   120
IBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *user_data)
alex@8889
   121
{
alex@8889
   122
    SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
alex@8889
   123
        
alex@8889
   124
    if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")){
alex@8889
   125
        DBusMessageIter iter;
alex@8889
   126
        dbus->message_iter_init(msg, &iter);
alex@8889
   127
        
alex@8889
   128
        const char *text = IBus_GetVariantText(conn, &iter, dbus);
alex@8889
   129
        if(text && *text){
alex@8889
   130
            char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
alex@8889
   131
            size_t text_bytes = SDL_strlen(text), i = 0;
alex@8889
   132
            
alex@8889
   133
            while(i < text_bytes){
alex@8889
   134
                size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
alex@8889
   135
                SDL_SendKeyboardText(buf);
alex@8889
   136
                
alex@8889
   137
                i += sz;
alex@8889
   138
            }
alex@8889
   139
        }
alex@8889
   140
        
alex@8889
   141
        return DBUS_HANDLER_RESULT_HANDLED;
alex@8889
   142
    }
alex@8889
   143
    
alex@8889
   144
    if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")){
alex@8889
   145
        DBusMessageIter iter;
alex@8889
   146
        dbus->message_iter_init(msg, &iter);
alex@8889
   147
        const char *text = IBus_GetVariantText(conn, &iter, dbus);
alex@8889
   148
        
alex@8889
   149
        if(text && *text){
alex@8889
   150
            char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
alex@8889
   151
            size_t text_bytes = SDL_strlen(text), i = 0;
alex@8889
   152
            size_t cursor = 0;
alex@8889
   153
            
alex@8889
   154
            while(i < text_bytes){
alex@8889
   155
                size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
alex@8889
   156
                size_t chars = IBus_utf8_strlen(buf);
alex@8889
   157
                
alex@8889
   158
                SDL_SendEditingText(buf, cursor, chars);
alex@8889
   159
alex@8889
   160
                i += sz;
alex@8889
   161
                cursor += chars;
alex@8889
   162
            }
alex@8889
   163
        } else {
alex@8889
   164
            SDL_SendEditingText("", 0, 0);
alex@8889
   165
        }
alex@8889
   166
        
alex@8889
   167
        SDL_IBus_UpdateTextRect(NULL);
alex@8889
   168
        
alex@8889
   169
        return DBUS_HANDLER_RESULT_HANDLED;
alex@8889
   170
    }
alex@8889
   171
    
alex@8889
   172
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
alex@8889
   173
}
alex@8889
   174
alex@8889
   175
static char *
alex@8889
   176
IBus_ReadAddressFromFile(const char *file_path)
alex@8889
   177
{
alex@8889
   178
    FILE *addr_file = fopen(file_path, "r");
alex@8889
   179
    if(!addr_file){
alex@8889
   180
        return NULL;
alex@8889
   181
    }
alex@8889
   182
alex@8889
   183
    char addr_buf[1024];
alex@8889
   184
    SDL_bool success = SDL_FALSE;
alex@8889
   185
alex@8889
   186
    while(fgets(addr_buf, sizeof(addr_buf), addr_file)){
alex@8889
   187
        if(SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0){
alex@8889
   188
            size_t sz = SDL_strlen(addr_buf);
alex@8889
   189
            if(addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
alex@8889
   190
            if(addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
alex@8889
   191
            success = SDL_TRUE;
alex@8889
   192
            break;
alex@8889
   193
        }
alex@8889
   194
    }
alex@8889
   195
alex@8889
   196
    fclose(addr_file);
alex@8889
   197
alex@8889
   198
    if(success){
alex@8889
   199
        return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
alex@8889
   200
    } else {
alex@8889
   201
        return NULL;
alex@8889
   202
    }
alex@8889
   203
}
alex@8889
   204
alex@8889
   205
static char *
alex@8889
   206
IBus_GetDBusAddressFilename(void)
alex@8889
   207
{
alex@8889
   208
    if(ibus_addr_file){
alex@8889
   209
        return SDL_strdup(ibus_addr_file);
alex@8889
   210
    }
alex@8889
   211
    
alex@8889
   212
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   213
    
alex@8889
   214
    if(!dbus){
alex@8889
   215
        return NULL;
alex@8889
   216
    }
alex@8889
   217
    
alex@8889
   218
    /* Use this environment variable if it exists. */
alex@8889
   219
    const char *addr = SDL_getenv("IBUS_ADDRESS");
alex@8889
   220
    if(addr && *addr){
alex@8889
   221
        return SDL_strdup(addr);
alex@8889
   222
    }
alex@8889
   223
    
alex@8889
   224
    /* Otherwise, we have to get the hostname, display, machine id, config dir
alex@8889
   225
       and look up the address from a filepath using all those bits, eek. */
alex@8889
   226
    const char *disp_env = SDL_getenv("DISPLAY");
alex@8889
   227
    char *display = NULL;
alex@8889
   228
    
alex@8889
   229
    if(!disp_env || !*disp_env){
alex@8889
   230
        display = SDL_strdup(":0.0");
alex@8889
   231
    } else {
alex@8889
   232
        display = SDL_strdup(disp_env);
alex@8889
   233
    }
alex@8889
   234
    
alex@8889
   235
    const char *host = display;
alex@8889
   236
    char *disp_num   = SDL_strrchr(display, ':'), 
alex@8889
   237
         *screen_num = SDL_strrchr(display, '.');
alex@8889
   238
    
alex@8889
   239
    if(!disp_num){
alex@8889
   240
        SDL_free(display);
alex@8889
   241
        return NULL;
alex@8889
   242
    }
alex@8889
   243
    
alex@8889
   244
    *disp_num = 0;
alex@8889
   245
    disp_num++;
alex@8889
   246
    
alex@8889
   247
    if(screen_num){
alex@8889
   248
        *screen_num = 0;
alex@8889
   249
    }
alex@8889
   250
    
alex@8889
   251
    if(!*host){
alex@8889
   252
        host = "unix";
alex@8889
   253
    }
alex@8889
   254
        
alex@8889
   255
    char config_dir[PATH_MAX];
alex@8889
   256
    SDL_memset(config_dir, 0, sizeof(config_dir));
alex@8889
   257
    
alex@8889
   258
    const char *conf_env = SDL_getenv("XDG_CONFIG_HOME");
alex@8889
   259
    if(conf_env && *conf_env){
alex@8889
   260
        SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
alex@8889
   261
    } else {
alex@8889
   262
        const char *home_env = SDL_getenv("HOME");
alex@8889
   263
        if(!home_env || !*home_env){
alex@8889
   264
            SDL_free(display);
alex@8889
   265
            return NULL;
alex@8889
   266
        }
alex@8889
   267
        SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
alex@8889
   268
    }
alex@8889
   269
    
alex@8889
   270
    char *key = dbus->get_local_machine_id();
alex@8889
   271
    
alex@8889
   272
    char file_path[PATH_MAX];
alex@8889
   273
    SDL_memset(file_path, 0, sizeof(file_path));
alex@8889
   274
    SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s", 
alex@8889
   275
                                               config_dir, key, host, disp_num);
alex@8889
   276
    dbus->free(key);
alex@8889
   277
    SDL_free(display);
alex@8889
   278
    
alex@8889
   279
    return SDL_strdup(file_path);
alex@8889
   280
}
alex@8889
   281
alex@8889
   282
static SDL_bool
alex@8889
   283
IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
alex@8889
   284
{
alex@8889
   285
    const char *path = NULL;
alex@8889
   286
    SDL_bool result = SDL_FALSE;
alex@8889
   287
    
alex@8889
   288
    ibus_conn = dbus->connection_open_private(addr, NULL);
alex@8889
   289
alex@8889
   290
    if(!ibus_conn){
alex@8889
   291
        return SDL_FALSE;
alex@8889
   292
    }
alex@8889
   293
alex@8889
   294
    dbus->connection_flush(ibus_conn);
alex@8889
   295
    
alex@8889
   296
    if(!dbus->bus_register(ibus_conn, NULL)){
alex@8889
   297
        ibus_conn = NULL;
alex@8889
   298
        return SDL_FALSE;
alex@8889
   299
    }
alex@8889
   300
    
alex@8889
   301
    dbus->connection_flush(ibus_conn);
alex@8889
   302
alex@8889
   303
    DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   304
                                                     IBUS_PATH,
alex@8889
   305
                                                     IBUS_INTERFACE,
alex@8889
   306
                                                     "CreateInputContext");
alex@8889
   307
    if(msg){
alex@8889
   308
        const char *client_name = "SDL2_Application";
alex@8889
   309
        dbus->message_append_args(msg,
alex@8889
   310
                                  DBUS_TYPE_STRING, &client_name,
alex@8889
   311
                                  DBUS_TYPE_INVALID);
alex@8889
   312
    }
alex@8889
   313
    
alex@8889
   314
    if(msg){
alex@8889
   315
        DBusMessage *reply;
alex@8889
   316
        
alex@8889
   317
        reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
alex@8889
   318
        if(reply){
alex@8889
   319
            if(dbus->message_get_args(reply, NULL,
alex@8889
   320
                                       DBUS_TYPE_OBJECT_PATH, &path,
alex@8889
   321
                                       DBUS_TYPE_INVALID)){
alex@8889
   322
                if(input_ctx_path){
alex@8889
   323
                    SDL_free(input_ctx_path);
alex@8889
   324
                }
alex@8889
   325
                input_ctx_path = SDL_strdup(path);
alex@8889
   326
                result = SDL_TRUE;                          
alex@8889
   327
            }
alex@8889
   328
            dbus->message_unref(reply);
alex@8889
   329
        }
alex@8889
   330
        dbus->message_unref(msg);
alex@8889
   331
    }
alex@8889
   332
alex@8889
   333
    if(result){
alex@8889
   334
        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   335
                                                         input_ctx_path,
alex@8889
   336
                                                         IBUS_INPUT_INTERFACE,
alex@8889
   337
                                                         "SetCapabilities");
alex@8889
   338
        if(msg){
alex@8889
   339
            Uint32 caps = IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT;
alex@8889
   340
            dbus->message_append_args(msg,
alex@8889
   341
                                      DBUS_TYPE_UINT32, &caps,
alex@8889
   342
                                      DBUS_TYPE_INVALID);
alex@8889
   343
        }
alex@8889
   344
        
alex@8889
   345
        if(msg){
alex@8889
   346
            if(dbus->connection_send(ibus_conn, msg, NULL)){
alex@8889
   347
                dbus->connection_flush(ibus_conn);
alex@8889
   348
            }
alex@8889
   349
            dbus->message_unref(msg);
alex@8889
   350
        }
alex@8889
   351
        
alex@8889
   352
        dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
alex@8889
   353
        dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL);
alex@8889
   354
        dbus->connection_flush(ibus_conn);
alex@8889
   355
    }
alex@8889
   356
alex@8889
   357
    SDL_IBus_SetFocus(SDL_GetFocusWindow() != NULL);
alex@8889
   358
    SDL_IBus_UpdateTextRect(NULL);
alex@8889
   359
    
alex@8889
   360
    return result;
alex@8889
   361
}
alex@8889
   362
alex@8889
   363
static SDL_bool
alex@8889
   364
IBus_CheckConnection(SDL_DBusContext *dbus)
alex@8889
   365
{
alex@8889
   366
    if(!dbus) return SDL_FALSE;
alex@8889
   367
    
alex@8889
   368
    if(ibus_conn && dbus->connection_get_is_connected(ibus_conn)){
alex@8889
   369
        return SDL_TRUE;
alex@8889
   370
    }
alex@8889
   371
    
alex@8889
   372
    if(inotify_fd != -1){
alex@8889
   373
        char buf[1024];
alex@8889
   374
        ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
alex@8889
   375
        if(readsize > 0){
alex@8889
   376
        
alex@8889
   377
            char *p;
alex@8889
   378
            SDL_bool file_updated = SDL_FALSE;
alex@8889
   379
            
alex@8889
   380
            for(p = buf; p < buf + readsize; /**/){
alex@8889
   381
                struct inotify_event *event = (struct inotify_event*) p;
alex@8889
   382
                if(event->len > 0){
alex@8889
   383
                    char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
alex@8889
   384
                    if(!addr_file_no_path) return SDL_FALSE;
alex@8889
   385
                 
alex@8889
   386
                    if(SDL_strcmp(addr_file_no_path + 1, event->name) == 0){
alex@8889
   387
                        file_updated = SDL_TRUE;
alex@8889
   388
                        break;
alex@8889
   389
                    }
alex@8889
   390
                }
alex@8889
   391
                
alex@8889
   392
                p += sizeof(struct inotify_event) + event->len;
alex@8889
   393
            }
alex@8889
   394
            
alex@8889
   395
            if(file_updated){
alex@8889
   396
                char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
alex@8889
   397
                if(addr){
alex@8889
   398
                    SDL_bool result = IBus_SetupConnection(dbus, addr);
alex@8889
   399
                    SDL_free(addr);
alex@8889
   400
                    return result;
alex@8889
   401
                }
alex@8889
   402
            }
alex@8889
   403
        }
alex@8889
   404
    }
alex@8889
   405
    
alex@8889
   406
    return SDL_FALSE;
alex@8889
   407
}
alex@8889
   408
alex@8889
   409
SDL_bool
alex@8889
   410
SDL_IBus_Init(void)
alex@8889
   411
{
alex@8889
   412
    SDL_bool result = SDL_FALSE;
alex@8889
   413
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   414
    
alex@8889
   415
    if(dbus){
alex@8889
   416
        char *addr_file = IBus_GetDBusAddressFilename();
alex@8889
   417
        if(!addr_file){
alex@8889
   418
            return SDL_FALSE;
alex@8889
   419
        }
alex@8889
   420
        
alex@8889
   421
        ibus_addr_file = SDL_strdup(addr_file);
alex@8889
   422
        
alex@8889
   423
        char *addr = IBus_ReadAddressFromFile(addr_file);
alex@8889
   424
        
alex@8889
   425
        inotify_fd = inotify_init();
alex@8889
   426
        fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
alex@8889
   427
        
alex@8889
   428
        char *addr_file_dir = SDL_strrchr(addr_file, '/');
alex@8889
   429
        if(addr_file_dir){
alex@8889
   430
            *addr_file_dir = 0;
alex@8889
   431
        }
alex@8889
   432
        
alex@8889
   433
        inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
alex@8889
   434
        SDL_free(addr_file);
alex@8889
   435
        
alex@8889
   436
        result = IBus_SetupConnection(dbus, addr);
alex@8889
   437
        SDL_free(addr);
alex@8889
   438
    }
alex@8889
   439
    
alex@8889
   440
    return result;
alex@8889
   441
}
alex@8889
   442
alex@8889
   443
void
alex@8889
   444
SDL_IBus_Quit(void)
alex@8889
   445
{   
alex@8889
   446
    if(input_ctx_path){
alex@8889
   447
        SDL_free(input_ctx_path);
alex@8889
   448
        input_ctx_path = NULL;
alex@8889
   449
    }
alex@8889
   450
    
alex@8889
   451
    if(ibus_addr_file){
alex@8889
   452
        SDL_free(ibus_addr_file);
alex@8889
   453
        ibus_addr_file = NULL;
alex@8889
   454
    }
alex@8889
   455
    
alex@8889
   456
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   457
    
alex@8889
   458
    if(dbus && ibus_conn){
alex@8889
   459
        dbus->connection_close(ibus_conn);
alex@8889
   460
        dbus->connection_unref(ibus_conn);
alex@8889
   461
    }
alex@8889
   462
    
alex@8889
   463
    SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
alex@8889
   464
}
alex@8889
   465
alex@8889
   466
static void
alex@8889
   467
IBus_SimpleMessage(const char *method)
alex@8889
   468
{   
alex@8889
   469
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   470
    
alex@8889
   471
    if(IBus_CheckConnection(dbus)){
alex@8889
   472
        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   473
                                                         input_ctx_path,
alex@8889
   474
                                                         IBUS_INPUT_INTERFACE,
alex@8889
   475
                                                         method);
alex@8889
   476
        if(msg){
alex@8889
   477
            if(dbus->connection_send(ibus_conn, msg, NULL)){
alex@8889
   478
                dbus->connection_flush(ibus_conn);
alex@8889
   479
            }
alex@8889
   480
            dbus->message_unref(msg);
alex@8889
   481
        }
alex@8889
   482
    }
alex@8889
   483
}
alex@8889
   484
alex@8889
   485
void
alex@8889
   486
SDL_IBus_SetFocus(SDL_bool focused)
alex@8889
   487
{ 
alex@8889
   488
    const char *method = focused ? "FocusIn" : "FocusOut";
alex@8889
   489
    IBus_SimpleMessage(method);
alex@8889
   490
}
alex@8889
   491
alex@8889
   492
void
alex@8889
   493
SDL_IBus_Reset(void)
alex@8889
   494
{
alex@8889
   495
    IBus_SimpleMessage("Reset");
alex@8889
   496
}
alex@8889
   497
alex@8889
   498
SDL_bool
alex@8889
   499
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
alex@8889
   500
{ 
alex@8889
   501
    SDL_bool result = SDL_FALSE;   
alex@8889
   502
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   503
    
alex@8889
   504
    if(IBus_CheckConnection(dbus)){
alex@8889
   505
        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   506
                                                         input_ctx_path,
alex@8889
   507
                                                         IBUS_INPUT_INTERFACE,
alex@8889
   508
                                                         "ProcessKeyEvent");
alex@8889
   509
        if(msg){
alex@8889
   510
            Uint32 mods = IBus_ModState();
alex@8889
   511
            dbus->message_append_args(msg,
alex@8889
   512
                                      DBUS_TYPE_UINT32, &keysym,
alex@8889
   513
                                      DBUS_TYPE_UINT32, &keycode,
alex@8889
   514
                                      DBUS_TYPE_UINT32, &mods,
alex@8889
   515
                                      DBUS_TYPE_INVALID);
alex@8889
   516
        }
alex@8889
   517
        
alex@8889
   518
        if(msg){
alex@8889
   519
            DBusMessage *reply;
alex@8889
   520
            
alex@8889
   521
            reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
alex@8889
   522
            if(reply){
alex@8889
   523
                if(!dbus->message_get_args(reply, NULL,
alex@8889
   524
                                           DBUS_TYPE_BOOLEAN, &result,
alex@8889
   525
                                           DBUS_TYPE_INVALID)){
alex@8889
   526
                    result = SDL_FALSE;                         
alex@8889
   527
                }
alex@8889
   528
                dbus->message_unref(reply);
alex@8889
   529
            }
alex@8889
   530
            dbus->message_unref(msg);
alex@8889
   531
        }
alex@8889
   532
        
alex@8889
   533
    }
alex@8889
   534
    
alex@8889
   535
    return result;
alex@8889
   536
}
alex@8889
   537
alex@8889
   538
void
alex@8889
   539
SDL_IBus_UpdateTextRect(SDL_Rect *rect)
alex@8889
   540
{
alex@8889
   541
    if(rect){
alex@8889
   542
        SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
alex@8889
   543
    }
alex@8889
   544
    
alex@8889
   545
    SDL_Window *focused_win = SDL_GetFocusWindow();
alex@8889
   546
alex@8889
   547
    if(!focused_win) return;
alex@8889
   548
alex@8889
   549
    int x = 0, y = 0;
alex@8889
   550
    SDL_GetWindowPosition(focused_win, &x, &y);
alex@8889
   551
    x += ibus_cursor_rect.x;
alex@8889
   552
    y += ibus_cursor_rect.y;
alex@8889
   553
        
alex@8889
   554
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   555
    
alex@8889
   556
    if(IBus_CheckConnection(dbus)){
alex@8889
   557
        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   558
                                                         input_ctx_path,
alex@8889
   559
                                                         IBUS_INPUT_INTERFACE,
alex@8889
   560
                                                         "SetCursorLocation");
alex@8889
   561
        if(msg){
alex@8889
   562
            dbus->message_append_args(msg,
alex@8889
   563
                                      DBUS_TYPE_INT32, &x,
alex@8889
   564
                                      DBUS_TYPE_INT32, &y,
alex@8889
   565
                                      DBUS_TYPE_INT32, &ibus_cursor_rect.w,
alex@8889
   566
                                      DBUS_TYPE_INT32, &ibus_cursor_rect.h,
alex@8889
   567
                                      DBUS_TYPE_INVALID);
alex@8889
   568
        }
alex@8889
   569
        
alex@8889
   570
        if(msg){
alex@8889
   571
            if(dbus->connection_send(ibus_conn, msg, NULL)){
alex@8889
   572
                dbus->connection_flush(ibus_conn);
alex@8889
   573
            }
alex@8889
   574
            dbus->message_unref(msg);
alex@8889
   575
        }
alex@8889
   576
    }
alex@8889
   577
}
alex@8889
   578
alex@8889
   579
void
alex@8889
   580
SDL_IBus_PumpEvents(void)
alex@8889
   581
{
alex@8889
   582
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   583
    
alex@8889
   584
    if(IBus_CheckConnection(dbus)){
alex@8889
   585
        dbus->connection_read_write(ibus_conn, 0);
alex@8889
   586
    
alex@8889
   587
        while(dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS){
alex@8889
   588
            /* Do nothing, actual work happens in IBus_MessageFilter */
alex@8889
   589
        }
alex@8889
   590
    }
alex@8889
   591
}
alex@8889
   592
alex@8889
   593
#endif