src/core/linux/SDL_ibus.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 19 Aug 2014 21:59:56 -0700
changeset 9098 064ea0b1275c
parent 9097 56d712662a82
child 9107 6485aa2e421c
permissions -rw-r--r--
Changed the name of the IME hint to match the naming convention in SDL
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@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;
alex@8889
    45
static SDL_Rect ibus_cursor_rect = {0};
alex@8889
    46
static DBusConnection *ibus_conn = NULL;
alex@8889
    47
static char *ibus_addr_file = NULL;
alex@9096
    48
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 */
alex@8889
    57
    if(sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
alex@8889
    58
    if(sdl_mods & KMOD_CAPS)   ibus_mods |= IBUS_LOCK_MASK;
alex@8889
    59
    if(sdl_mods & KMOD_LCTRL)  ibus_mods |= IBUS_CONTROL_MASK;
alex@8889
    60
    if(sdl_mods & KMOD_LALT)   ibus_mods |= IBUS_MOD1_MASK;
alex@8889
    61
    if(sdl_mods & KMOD_NUM)    ibus_mods |= IBUS_MOD2_MASK;
alex@8889
    62
    if(sdl_mods & KMOD_MODE)   ibus_mods |= IBUS_MOD5_MASK;
alex@8889
    63
    if(sdl_mods & KMOD_LGUI)   ibus_mods |= IBUS_SUPER_MASK;
alex@8889
    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;
alex@8889
    74
    DBusMessageIter sub1, sub2;
alex@8889
    75
alex@8889
    76
    if(dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT){
alex@8889
    77
        return NULL;
alex@8889
    78
    }
alex@8889
    79
    
alex@8889
    80
    dbus->message_iter_recurse(iter, &sub1);
alex@8889
    81
    
alex@8889
    82
    if(dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT){
alex@8889
    83
        return NULL;
alex@8889
    84
    }
alex@8889
    85
    
alex@8889
    86
    dbus->message_iter_recurse(&sub1, &sub2);
alex@8889
    87
    
alex@8889
    88
    if(dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING){
alex@8889
    89
        return NULL;
alex@8889
    90
    }
alex@8889
    91
    
alex@8889
    92
    const char *struct_id = NULL;
alex@8889
    93
    dbus->message_iter_get_basic(&sub2, &struct_id);
alex@8889
    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
    
alex@8889
   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 size_t 
alex@8889
   111
IBus_utf8_strlen(const char *str)
alex@8889
   112
{
alex@8889
   113
    size_t utf8_len = 0;
alex@8889
   114
    const char *p;
alex@8889
   115
    
alex@8889
   116
    for(p = str; *p; ++p){
alex@8889
   117
        if(!((*p & 0x80) && !(*p & 0x40))){
alex@8889
   118
            ++utf8_len;
alex@8889
   119
        }
alex@8889
   120
    }
alex@8889
   121
    
alex@8889
   122
    return utf8_len;
alex@8889
   123
}
alex@8889
   124
alex@8889
   125
static DBusHandlerResult
alex@8889
   126
IBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *user_data)
alex@8889
   127
{
alex@8889
   128
    SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
alex@8889
   129
        
alex@8889
   130
    if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")){
alex@8889
   131
        DBusMessageIter iter;
alex@8889
   132
        dbus->message_iter_init(msg, &iter);
alex@8889
   133
        
alex@8889
   134
        const char *text = IBus_GetVariantText(conn, &iter, dbus);
alex@8889
   135
        if(text && *text){
alex@8889
   136
            char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
alex@8889
   137
            size_t text_bytes = SDL_strlen(text), i = 0;
alex@8889
   138
            
alex@8889
   139
            while(i < text_bytes){
alex@8889
   140
                size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
alex@8889
   141
                SDL_SendKeyboardText(buf);
alex@8889
   142
                
alex@8889
   143
                i += sz;
alex@8889
   144
            }
alex@8889
   145
        }
alex@8889
   146
        
alex@8889
   147
        return DBUS_HANDLER_RESULT_HANDLED;
alex@8889
   148
    }
alex@8889
   149
    
alex@8889
   150
    if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")){
alex@8889
   151
        DBusMessageIter iter;
alex@8889
   152
        dbus->message_iter_init(msg, &iter);
alex@8889
   153
        const char *text = IBus_GetVariantText(conn, &iter, dbus);
alex@8889
   154
        
alex@8889
   155
        if(text && *text){
alex@8889
   156
            char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
alex@8889
   157
            size_t text_bytes = SDL_strlen(text), i = 0;
alex@8889
   158
            size_t cursor = 0;
alex@8889
   159
            
alex@8889
   160
            while(i < text_bytes){
alex@8889
   161
                size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
alex@8889
   162
                size_t chars = IBus_utf8_strlen(buf);
alex@8889
   163
                
alex@8889
   164
                SDL_SendEditingText(buf, cursor, chars);
alex@8889
   165
alex@8889
   166
                i += sz;
alex@8889
   167
                cursor += chars;
alex@8889
   168
            }
alex@8889
   169
        }
alex@8889
   170
        
alex@8889
   171
        SDL_IBus_UpdateTextRect(NULL);
alex@8889
   172
        
alex@8889
   173
        return DBUS_HANDLER_RESULT_HANDLED;
alex@8889
   174
    }
alex@8889
   175
    
alex@9096
   176
    if(dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "HidePreeditText")){
alex@9096
   177
    	SDL_SendEditingText("", 0, 0);
alex@9096
   178
    	return DBUS_HANDLER_RESULT_HANDLED;
alex@9096
   179
    }
alex@9096
   180
    
alex@8889
   181
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
alex@8889
   182
}
alex@8889
   183
alex@8889
   184
static char *
alex@8889
   185
IBus_ReadAddressFromFile(const char *file_path)
alex@8889
   186
{
alex@8889
   187
    FILE *addr_file = fopen(file_path, "r");
alex@8889
   188
    if(!addr_file){
alex@8889
   189
        return NULL;
alex@8889
   190
    }
alex@8889
   191
alex@8889
   192
    char addr_buf[1024];
alex@8889
   193
    SDL_bool success = SDL_FALSE;
alex@8889
   194
alex@8889
   195
    while(fgets(addr_buf, sizeof(addr_buf), addr_file)){
alex@8889
   196
        if(SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0){
alex@8889
   197
            size_t sz = SDL_strlen(addr_buf);
alex@8889
   198
            if(addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
alex@8889
   199
            if(addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
alex@8889
   200
            success = SDL_TRUE;
alex@8889
   201
            break;
alex@8889
   202
        }
alex@8889
   203
    }
alex@8889
   204
alex@8889
   205
    fclose(addr_file);
alex@8889
   206
alex@8889
   207
    if(success){
alex@8889
   208
        return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
alex@8889
   209
    } else {
alex@8889
   210
        return NULL;
alex@8889
   211
    }
alex@8889
   212
}
alex@8889
   213
alex@8889
   214
static char *
alex@8889
   215
IBus_GetDBusAddressFilename(void)
alex@8889
   216
{
alex@8889
   217
    if(ibus_addr_file){
alex@8889
   218
        return SDL_strdup(ibus_addr_file);
alex@8889
   219
    }
alex@8889
   220
    
alex@8889
   221
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   222
    
alex@8889
   223
    if(!dbus){
alex@8889
   224
        return NULL;
alex@8889
   225
    }
alex@8889
   226
    
alex@8889
   227
    /* Use this environment variable if it exists. */
alex@8889
   228
    const char *addr = SDL_getenv("IBUS_ADDRESS");
alex@8889
   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. */
alex@8889
   235
    const char *disp_env = SDL_getenv("DISPLAY");
alex@8889
   236
    char *display = NULL;
alex@8889
   237
    
alex@8889
   238
    if(!disp_env || !*disp_env){
alex@8889
   239
        display = SDL_strdup(":0.0");
alex@8889
   240
    } else {
alex@8889
   241
        display = SDL_strdup(disp_env);
alex@8889
   242
    }
alex@8889
   243
    
alex@8889
   244
    const char *host = display;
alex@8889
   245
    char *disp_num   = SDL_strrchr(display, ':'), 
alex@8889
   246
         *screen_num = SDL_strrchr(display, '.');
alex@8889
   247
    
alex@8889
   248
    if(!disp_num){
alex@8889
   249
        SDL_free(display);
alex@8889
   250
        return NULL;
alex@8889
   251
    }
alex@8889
   252
    
alex@8889
   253
    *disp_num = 0;
alex@8889
   254
    disp_num++;
alex@8889
   255
    
alex@8889
   256
    if(screen_num){
alex@8889
   257
        *screen_num = 0;
alex@8889
   258
    }
alex@8889
   259
    
alex@8889
   260
    if(!*host){
alex@8889
   261
        host = "unix";
alex@8889
   262
    }
alex@8889
   263
        
alex@8889
   264
    char config_dir[PATH_MAX];
alex@8889
   265
    SDL_memset(config_dir, 0, sizeof(config_dir));
alex@8889
   266
    
alex@8889
   267
    const char *conf_env = SDL_getenv("XDG_CONFIG_HOME");
alex@8889
   268
    if(conf_env && *conf_env){
alex@8889
   269
        SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
alex@8889
   270
    } else {
alex@8889
   271
        const char *home_env = SDL_getenv("HOME");
alex@8889
   272
        if(!home_env || !*home_env){
alex@8889
   273
            SDL_free(display);
alex@8889
   274
            return NULL;
alex@8889
   275
        }
alex@8889
   276
        SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
alex@8889
   277
    }
alex@8889
   278
    
alex@8889
   279
    char *key = dbus->get_local_machine_id();
alex@8889
   280
    
alex@8889
   281
    char file_path[PATH_MAX];
alex@8889
   282
    SDL_memset(file_path, 0, sizeof(file_path));
alex@8889
   283
    SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s", 
alex@8889
   284
                                               config_dir, key, host, disp_num);
alex@8889
   285
    dbus->free(key);
alex@8889
   286
    SDL_free(display);
alex@8889
   287
    
alex@8889
   288
    return SDL_strdup(file_path);
alex@8889
   289
}
alex@8889
   290
alex@9097
   291
static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
alex@9097
   292
alex@9097
   293
static void
alex@9097
   294
IBus_SetCapabilities(void *data, const char *name, const char *old_val,
alex@9097
   295
                                                   const char *internal_editing)
alex@9097
   296
{
alex@9097
   297
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@9097
   298
    
alex@9097
   299
    if(IBus_CheckConnection(dbus)){
alex@9097
   300
alex@9097
   301
        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@9097
   302
                                                         input_ctx_path,
alex@9097
   303
                                                         IBUS_INPUT_INTERFACE,
alex@9097
   304
                                                         "SetCapabilities");
alex@9097
   305
        if(msg){
alex@9097
   306
            Uint32 caps = IBUS_CAP_FOCUS;
alex@9097
   307
            if(!(internal_editing && *internal_editing == '1')){
alex@9097
   308
                caps |= IBUS_CAP_PREEDIT_TEXT;
alex@9097
   309
            }
alex@9097
   310
            
alex@9097
   311
            dbus->message_append_args(msg,
alex@9097
   312
                                      DBUS_TYPE_UINT32, &caps,
alex@9097
   313
                                      DBUS_TYPE_INVALID);
alex@9097
   314
        }
alex@9097
   315
        
alex@9097
   316
        if(msg){
alex@9097
   317
            if(dbus->connection_send(ibus_conn, msg, NULL)){
alex@9097
   318
                dbus->connection_flush(ibus_conn);
alex@9097
   319
            }
alex@9097
   320
            dbus->message_unref(msg);
alex@9097
   321
        }
alex@9097
   322
    }
alex@9097
   323
}
alex@9097
   324
alex@9097
   325
alex@8889
   326
static SDL_bool
alex@8889
   327
IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
alex@8889
   328
{
alex@8889
   329
    const char *path = NULL;
alex@8889
   330
    SDL_bool result = SDL_FALSE;
alex@8889
   331
    
alex@8889
   332
    ibus_conn = dbus->connection_open_private(addr, NULL);
alex@8889
   333
alex@8889
   334
    if(!ibus_conn){
alex@8889
   335
        return SDL_FALSE;
alex@8889
   336
    }
alex@8889
   337
alex@8889
   338
    dbus->connection_flush(ibus_conn);
alex@8889
   339
    
alex@8889
   340
    if(!dbus->bus_register(ibus_conn, NULL)){
alex@8889
   341
        ibus_conn = NULL;
alex@8889
   342
        return SDL_FALSE;
alex@8889
   343
    }
alex@8889
   344
    
alex@8889
   345
    dbus->connection_flush(ibus_conn);
alex@8889
   346
alex@8889
   347
    DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   348
                                                     IBUS_PATH,
alex@8889
   349
                                                     IBUS_INTERFACE,
alex@8889
   350
                                                     "CreateInputContext");
alex@8889
   351
    if(msg){
alex@8889
   352
        const char *client_name = "SDL2_Application";
alex@8889
   353
        dbus->message_append_args(msg,
alex@8889
   354
                                  DBUS_TYPE_STRING, &client_name,
alex@8889
   355
                                  DBUS_TYPE_INVALID);
alex@8889
   356
    }
alex@8889
   357
    
alex@8889
   358
    if(msg){
alex@8889
   359
        DBusMessage *reply;
alex@8889
   360
        
alex@8889
   361
        reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
alex@8889
   362
        if(reply){
alex@8889
   363
            if(dbus->message_get_args(reply, NULL,
alex@8889
   364
                                       DBUS_TYPE_OBJECT_PATH, &path,
alex@8889
   365
                                       DBUS_TYPE_INVALID)){
alex@8889
   366
                if(input_ctx_path){
alex@8889
   367
                    SDL_free(input_ctx_path);
alex@8889
   368
                }
alex@8889
   369
                input_ctx_path = SDL_strdup(path);
alex@8889
   370
                result = SDL_TRUE;                          
alex@8889
   371
            }
alex@8889
   372
            dbus->message_unref(reply);
alex@8889
   373
        }
alex@8889
   374
        dbus->message_unref(msg);
alex@8889
   375
    }
alex@8889
   376
alex@8889
   377
    if(result){
slouken@9098
   378
        SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
alex@8889
   379
        
alex@8889
   380
        dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
alex@8889
   381
        dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL);
alex@8889
   382
        dbus->connection_flush(ibus_conn);
alex@8889
   383
    }
alex@8889
   384
alex@9096
   385
    SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
alex@8889
   386
    SDL_IBus_UpdateTextRect(NULL);
alex@8889
   387
    
alex@8889
   388
    return result;
alex@8889
   389
}
alex@8889
   390
alex@8889
   391
static SDL_bool
alex@8889
   392
IBus_CheckConnection(SDL_DBusContext *dbus)
alex@8889
   393
{
alex@8889
   394
    if(!dbus) return SDL_FALSE;
alex@8889
   395
    
alex@8889
   396
    if(ibus_conn && dbus->connection_get_is_connected(ibus_conn)){
alex@8889
   397
        return SDL_TRUE;
alex@8889
   398
    }
alex@8889
   399
    
alex@9096
   400
    if(inotify_fd > 0 && inotify_wd > 0){
alex@8889
   401
        char buf[1024];
alex@8889
   402
        ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
alex@8889
   403
        if(readsize > 0){
alex@8889
   404
        
alex@8889
   405
            char *p;
alex@8889
   406
            SDL_bool file_updated = SDL_FALSE;
alex@8889
   407
            
alex@8889
   408
            for(p = buf; p < buf + readsize; /**/){
alex@8889
   409
                struct inotify_event *event = (struct inotify_event*) p;
alex@8889
   410
                if(event->len > 0){
alex@8889
   411
                    char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
alex@8889
   412
                    if(!addr_file_no_path) return SDL_FALSE;
alex@8889
   413
                 
alex@8889
   414
                    if(SDL_strcmp(addr_file_no_path + 1, event->name) == 0){
alex@8889
   415
                        file_updated = SDL_TRUE;
alex@8889
   416
                        break;
alex@8889
   417
                    }
alex@8889
   418
                }
alex@8889
   419
                
alex@8889
   420
                p += sizeof(struct inotify_event) + event->len;
alex@8889
   421
            }
alex@8889
   422
            
alex@8889
   423
            if(file_updated){
alex@8889
   424
                char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
alex@8889
   425
                if(addr){
alex@8889
   426
                    SDL_bool result = IBus_SetupConnection(dbus, addr);
alex@8889
   427
                    SDL_free(addr);
alex@8889
   428
                    return result;
alex@8889
   429
                }
alex@8889
   430
            }
alex@8889
   431
        }
alex@8889
   432
    }
alex@8889
   433
    
alex@8889
   434
    return SDL_FALSE;
alex@8889
   435
}
alex@8889
   436
alex@8889
   437
SDL_bool
alex@8889
   438
SDL_IBus_Init(void)
alex@8889
   439
{
alex@8889
   440
    SDL_bool result = SDL_FALSE;
alex@8889
   441
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   442
    
alex@8889
   443
    if(dbus){
alex@8889
   444
        char *addr_file = IBus_GetDBusAddressFilename();
alex@8889
   445
        if(!addr_file){
alex@8889
   446
            return SDL_FALSE;
alex@8889
   447
        }
alex@8889
   448
        
alex@8889
   449
        ibus_addr_file = SDL_strdup(addr_file);
alex@8889
   450
        
alex@8889
   451
        char *addr = IBus_ReadAddressFromFile(addr_file);
alex@8889
   452
        
alex@9096
   453
        if(inotify_fd < 0){
alex@9096
   454
            inotify_fd = inotify_init();
alex@9096
   455
            fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
alex@9096
   456
        }
alex@8889
   457
        
alex@8889
   458
        char *addr_file_dir = SDL_strrchr(addr_file, '/');
alex@8889
   459
        if(addr_file_dir){
alex@8889
   460
            *addr_file_dir = 0;
alex@8889
   461
        }
alex@8889
   462
        
alex@9096
   463
        inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
alex@8889
   464
        SDL_free(addr_file);
alex@8889
   465
        
alex@8889
   466
        result = IBus_SetupConnection(dbus, addr);
alex@8889
   467
        SDL_free(addr);
alex@8889
   468
    }
alex@8889
   469
    
alex@8889
   470
    return result;
alex@8889
   471
}
alex@8889
   472
alex@8889
   473
void
alex@8889
   474
SDL_IBus_Quit(void)
alex@8889
   475
{   
alex@8889
   476
    if(input_ctx_path){
alex@8889
   477
        SDL_free(input_ctx_path);
alex@8889
   478
        input_ctx_path = NULL;
alex@8889
   479
    }
alex@8889
   480
    
alex@8889
   481
    if(ibus_addr_file){
alex@8889
   482
        SDL_free(ibus_addr_file);
alex@8889
   483
        ibus_addr_file = NULL;
alex@8889
   484
    }
alex@8889
   485
    
alex@8889
   486
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   487
    
alex@8889
   488
    if(dbus && ibus_conn){
alex@8889
   489
        dbus->connection_close(ibus_conn);
alex@8889
   490
        dbus->connection_unref(ibus_conn);
alex@8889
   491
    }
alex@8889
   492
    
alex@9096
   493
    if(inotify_fd > 0 && inotify_wd > 0){
alex@9096
   494
        inotify_rm_watch(inotify_fd, inotify_wd);
alex@9096
   495
        inotify_wd = -1;
alex@9096
   496
    }
alex@9096
   497
    
slouken@9098
   498
    SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
alex@9097
   499
    
alex@8889
   500
    SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
alex@8889
   501
}
alex@8889
   502
alex@8889
   503
static void
alex@8889
   504
IBus_SimpleMessage(const char *method)
alex@8889
   505
{   
alex@8889
   506
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   507
    
alex@8889
   508
    if(IBus_CheckConnection(dbus)){
alex@8889
   509
        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   510
                                                         input_ctx_path,
alex@8889
   511
                                                         IBUS_INPUT_INTERFACE,
alex@8889
   512
                                                         method);
alex@8889
   513
        if(msg){
alex@8889
   514
            if(dbus->connection_send(ibus_conn, msg, NULL)){
alex@8889
   515
                dbus->connection_flush(ibus_conn);
alex@8889
   516
            }
alex@8889
   517
            dbus->message_unref(msg);
alex@8889
   518
        }
alex@8889
   519
    }
alex@8889
   520
}
alex@8889
   521
alex@8889
   522
void
alex@8889
   523
SDL_IBus_SetFocus(SDL_bool focused)
alex@8889
   524
{ 
alex@8889
   525
    const char *method = focused ? "FocusIn" : "FocusOut";
alex@8889
   526
    IBus_SimpleMessage(method);
alex@8889
   527
}
alex@8889
   528
alex@8889
   529
void
alex@8889
   530
SDL_IBus_Reset(void)
alex@8889
   531
{
alex@8889
   532
    IBus_SimpleMessage("Reset");
alex@8889
   533
}
alex@8889
   534
alex@8889
   535
SDL_bool
alex@8889
   536
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
alex@8889
   537
{ 
alex@8889
   538
    SDL_bool result = SDL_FALSE;   
alex@8889
   539
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   540
    
alex@8889
   541
    if(IBus_CheckConnection(dbus)){
alex@8889
   542
        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   543
                                                         input_ctx_path,
alex@8889
   544
                                                         IBUS_INPUT_INTERFACE,
alex@8889
   545
                                                         "ProcessKeyEvent");
alex@8889
   546
        if(msg){
alex@8889
   547
            Uint32 mods = IBus_ModState();
alex@8889
   548
            dbus->message_append_args(msg,
alex@8889
   549
                                      DBUS_TYPE_UINT32, &keysym,
alex@8889
   550
                                      DBUS_TYPE_UINT32, &keycode,
alex@8889
   551
                                      DBUS_TYPE_UINT32, &mods,
alex@8889
   552
                                      DBUS_TYPE_INVALID);
alex@8889
   553
        }
alex@8889
   554
        
alex@8889
   555
        if(msg){
alex@8889
   556
            DBusMessage *reply;
alex@8889
   557
            
alex@8889
   558
            reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
alex@8889
   559
            if(reply){
alex@8889
   560
                if(!dbus->message_get_args(reply, NULL,
alex@8889
   561
                                           DBUS_TYPE_BOOLEAN, &result,
alex@8889
   562
                                           DBUS_TYPE_INVALID)){
alex@8889
   563
                    result = SDL_FALSE;                         
alex@8889
   564
                }
alex@8889
   565
                dbus->message_unref(reply);
alex@8889
   566
            }
alex@8889
   567
            dbus->message_unref(msg);
alex@8889
   568
        }
alex@8889
   569
        
alex@8889
   570
    }
alex@8889
   571
    
alex@9097
   572
    SDL_IBus_UpdateTextRect(NULL);
alex@9097
   573
alex@8889
   574
    return result;
alex@8889
   575
}
alex@8889
   576
alex@8889
   577
void
alex@8889
   578
SDL_IBus_UpdateTextRect(SDL_Rect *rect)
alex@8889
   579
{
alex@8889
   580
    if(rect){
alex@8889
   581
        SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
alex@8889
   582
    }
alex@8889
   583
    
alex@9096
   584
    SDL_Window *focused_win = SDL_GetKeyboardFocus();
alex@8889
   585
alex@8889
   586
    if(!focused_win) return;
alex@9095
   587
    
alex@9095
   588
    SDL_SysWMinfo info;
alex@9095
   589
    SDL_VERSION(&info.version);
alex@9095
   590
    
alex@9095
   591
    if(!SDL_GetWindowWMInfo(focused_win, &info)) return;
alex@9095
   592
    
alex@9095
   593
    int x = 0, y = 0;
alex@9095
   594
    
alex@9095
   595
    SDL_GetWindowPosition(focused_win, &x, &y);
alex@9095
   596
   
alex@9095
   597
#if SDL_VIDEO_DRIVER_X11    
alex@9095
   598
    if(info.subsystem == SDL_SYSWM_X11){
alex@9095
   599
        SDL_DisplayData *displaydata =
alex@9095
   600
            (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
alex@9095
   601
            
alex@9095
   602
        Display *x_disp = info.info.x11.display;
alex@9095
   603
        Window x_win = info.info.x11.window;
alex@9095
   604
        int x_screen = displaydata->screen;
alex@9095
   605
        Window unused;
alex@9095
   606
            
alex@9095
   607
        X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen),
alex@9095
   608
            0, 0, &x, &y, &unused);
alex@9095
   609
    }
alex@9095
   610
#endif
alex@8889
   611
alex@8889
   612
    x += ibus_cursor_rect.x;
alex@8889
   613
    y += ibus_cursor_rect.y;
alex@8889
   614
        
alex@8889
   615
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   616
    
alex@8889
   617
    if(IBus_CheckConnection(dbus)){
alex@8889
   618
        DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
alex@8889
   619
                                                         input_ctx_path,
alex@8889
   620
                                                         IBUS_INPUT_INTERFACE,
alex@8889
   621
                                                         "SetCursorLocation");
alex@8889
   622
        if(msg){
alex@8889
   623
            dbus->message_append_args(msg,
alex@8889
   624
                                      DBUS_TYPE_INT32, &x,
alex@8889
   625
                                      DBUS_TYPE_INT32, &y,
alex@8889
   626
                                      DBUS_TYPE_INT32, &ibus_cursor_rect.w,
alex@8889
   627
                                      DBUS_TYPE_INT32, &ibus_cursor_rect.h,
alex@8889
   628
                                      DBUS_TYPE_INVALID);
alex@8889
   629
        }
alex@8889
   630
        
alex@8889
   631
        if(msg){
alex@8889
   632
            if(dbus->connection_send(ibus_conn, msg, NULL)){
alex@8889
   633
                dbus->connection_flush(ibus_conn);
alex@8889
   634
            }
alex@8889
   635
            dbus->message_unref(msg);
alex@8889
   636
        }
alex@8889
   637
    }
alex@8889
   638
}
alex@8889
   639
alex@8889
   640
void
alex@8889
   641
SDL_IBus_PumpEvents(void)
alex@8889
   642
{
alex@8889
   643
    SDL_DBusContext *dbus = SDL_DBus_GetContext();
alex@8889
   644
    
alex@8889
   645
    if(IBus_CheckConnection(dbus)){
alex@8889
   646
        dbus->connection_read_write(ibus_conn, 0);
alex@8889
   647
    
alex@8889
   648
        while(dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS){
alex@8889
   649
            /* Do nothing, actual work happens in IBus_MessageFilter */
alex@8889
   650
        }
alex@8889
   651
    }
alex@8889
   652
}
alex@8889
   653
alex@8889
   654
#endif