~timo-jyrinki/ubuntu/trusty/maliit-framework/fix_qt52

« back to all changes in this revision

Viewing changes to gtk-input-context/client-gtk/client-imcontext-gtk.c

  • Committer: Package Import Robot
  • Author(s): Ricardo Salveti de Araujo, Sergio Schvezov, Ricardo Salveti de Araujo
  • Date: 2013-07-23 19:47:04 UTC
  • mfrom: (1.1.2) (1.2.1 experimental)
  • Revision ID: package-import@ubuntu.com-20130723194704-1lsy1kmlda069cea
Tags: 0.99.0+git20130615+97e8335-0ubuntu1
[ Sergio Schvezov ]
* New build from HEAD 97e8335.
* Packaging import from lp:phablet-extras/maliit-framework.

[ Ricardo Salveti de Araujo ]
* debian/control: adding vcs and fixing dependencies
* General package cleanup

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2010, Intel Corporation.
3
 
 * Copyright (C) 2012 One Laptop per Child Association
4
 
 *
5
 
 * Author: Raymond Liu <raymond.liu@intel.com>
6
 
 *
7
 
 *
8
 
 * This library is free software; you can redistribute it and/or
9
 
 * modify it under the terms of the GNU Lesser General Public License
10
 
 * version 2.1 as published by the Free Software Foundation.
11
 
 *
12
 
 * This library is distributed in the hope that it will be useful, but
13
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
 
 * Lesser General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU Lesser General Public
18
 
 * License along with this library; if not, write to the Free Software
19
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20
 
 * 02110-1301 USA
21
 
 */
22
 
 
23
 
 
24
 
#include <X11/keysym.h>
25
 
#include <gdk/gdkx.h> // For retrieving XID
26
 
#include <maliit-glib/maliitattributeextensionprivate.h>
27
 
 
28
 
#include "client-imcontext-gtk.h"
29
 
#include "qt-gtk-translate.h"
30
 
#include "debug.h"
31
 
 
32
 
static GType _meego_imcontext_type = 0;
33
 
static GtkIMContextClass *parent_class = NULL;
34
 
 
35
 
static MeegoIMContext *focused_imcontext = NULL;
36
 
static GtkWidget *focused_widget = NULL;
37
 
 
38
 
gboolean redirect_keys = FALSE;
39
 
 
40
 
static void meego_imcontext_finalize(GObject *object);
41
 
 
42
 
static void meego_imcontext_class_init(MeegoIMContextClass *klass);
43
 
static void meego_imcontext_init(MeegoIMContext *meego_imcontext);
44
 
 
45
 
static void meego_imcontext_focus_in(GtkIMContext *context);
46
 
static void meego_imcontext_focus_out(GtkIMContext *context);
47
 
static gboolean meego_imcontext_filter_key_event(GtkIMContext *context, GdkEventKey *event);
48
 
static void meego_imcontext_reset(GtkIMContext *context);
49
 
static void meego_imcontext_get_preedit_string(GtkIMContext *context, gchar **str, PangoAttrList **attrs, gint *cursor_pos);
50
 
static void meego_imcontext_set_preedit_enabled(GtkIMContext *context, gboolean enabled);
51
 
static void meego_imcontext_set_client_window(GtkIMContext *context, GdkWindow *window);
52
 
static void meego_imcontext_set_cursor_location(GtkIMContext *context, GdkRectangle *area);
53
 
static void meego_imcontext_update_widget_info(MeegoIMContext *imcontext);
54
 
 
55
 
static void meego_imcontext_im_initiated_hide(MeegoIMContextDbusObj *obj, gpointer user_data);
56
 
static void meego_imcontext_commit_string(MeegoIMContextDbusObj *obj, char *string, int replacement_start,
57
 
                                          int replacement_length, int cursor_pos, gpointer user_data);
58
 
static void meego_imcontext_update_preedit(MeegoIMContextDbusObj *obj, const char *string, GPtrArray *formatListData, gint32 replaceStart, gint32 replaceLength, gint32 cursorPos, gpointer user_data);
59
 
static void meego_imcontext_key_event(MeegoIMContextDbusObj *obj, int type, int key, int modifiers, char *text,
60
 
                                      gboolean auto_repeat, int count, gpointer user_data);
61
 
static void meego_imcontext_copy(MeegoIMContextDbusObj *obj, gpointer user_data);
62
 
static void meego_imcontext_paste(MeegoIMContextDbusObj *obj, gpointer user_data);
63
 
static void meego_imcontext_invoke_action(MeegoIMContextDbusObj *obj, const char *action, const char* sequence, gpointer user_data);
64
 
static void meego_imcontext_set_redirect_keys(MeegoIMContextDbusObj *obj, gboolean enabled, gpointer user_data);
65
 
static void meego_imcontext_notify_extended_attribute_changed (MeegoIMContextDbusObj *obj, gint id, const gchar *target, const gchar *target_item, const gchar *attribute, GVariant *variant_value, gpointer user_data);
66
 
static void meego_imcontext_update_input_method_area (MeegoIMContextDbusObj *obj, int x, int y, int width, int height, gpointer user_data);
67
 
 
68
 
 
69
 
static GtkIMContext *meego_imcontext_get_slave_imcontext(void);
70
 
 
71
 
static const gchar *const WIDGET_INFO_WIN_ID = "winId";
72
 
static const gchar *const WIDGET_INFO_FOCUS_STATE = "focusState";
73
 
static const gchar *const WIDGET_INFO_ATTRIBUTE_EXTENSION_ID = "toolbarId";
74
 
static const gchar *const WIDGET_INFO_ATTRIBUTE_EXTENSION_FILENAME = "toolbar";
75
 
static const gchar *const WIDGET_INFO_SURROUNDING_TEXT = "surroundingText";
76
 
static const gchar *const WIDGET_INFO_CURSOR_POSITION = "cursorPosition";
77
 
 
78
 
void destroy_g_value(GValue *value)
79
 
{
80
 
    g_value_unset(value);
81
 
    g_free(value);
82
 
}
83
 
 
84
 
GType meego_imcontext_get_type()
85
 
{
86
 
    return _meego_imcontext_type;
87
 
}
88
 
 
89
 
 
90
 
void
91
 
meego_imcontext_register_type(GTypeModule *type_module)
92
 
{
93
 
    static const GTypeInfo meego_imcontext_info = {
94
 
        sizeof(MeegoIMContextClass),
95
 
        (GBaseInitFunc) NULL,
96
 
        (GBaseFinalizeFunc) NULL,
97
 
        (GClassInitFunc) meego_imcontext_class_init,
98
 
        NULL,
99
 
        NULL,
100
 
        sizeof(MeegoIMContext),
101
 
        0,
102
 
        (GInstanceInitFunc) meego_imcontext_init,
103
 
        NULL
104
 
    };
105
 
 
106
 
    if (_meego_imcontext_type)
107
 
        return;
108
 
 
109
 
    if (type_module) {
110
 
        _meego_imcontext_type =
111
 
            g_type_module_register_type(
112
 
                type_module,
113
 
                GTK_TYPE_IM_CONTEXT,
114
 
                "MeegoIMContext",
115
 
                &meego_imcontext_info,
116
 
                (GTypeFlags)0);
117
 
    } else {
118
 
        _meego_imcontext_type =
119
 
            g_type_register_static(
120
 
                GTK_TYPE_IM_CONTEXT,
121
 
                "MeegoIMContext",
122
 
                &meego_imcontext_info,
123
 
                (GTypeFlags)0);
124
 
    }
125
 
}
126
 
 
127
 
 
128
 
 
129
 
// staff for fallback slave GTK simple imcontext
130
 
static void
131
 
slave_commit(GtkIMContext *slave, const char *text, gpointer data)
132
 
{
133
 
    UNUSED(slave);
134
 
    UNUSED(data);
135
 
    DBG("text = %s", text);
136
 
    if (focused_imcontext && text) {
137
 
        g_signal_emit_by_name(focused_imcontext, "commit", text);
138
 
    }
139
 
}
140
 
 
141
 
 
142
 
static void
143
 
slave_preedit_changed(GtkIMContext *slave, gpointer data)
144
 
{
145
 
    UNUSED(data);
146
 
    gchar *str = NULL;
147
 
    gint cursor_pos = 0;
148
 
    PangoAttrList *attrs = NULL;
149
 
 
150
 
    STEP();
151
 
    if (!focused_imcontext || !slave)
152
 
        return;
153
 
 
154
 
    gtk_im_context_get_preedit_string(slave, &str, &attrs, &cursor_pos);
155
 
 
156
 
    if (str != NULL) {
157
 
        g_free(focused_imcontext->preedit_str);
158
 
        focused_imcontext->preedit_str = str;
159
 
    }
160
 
 
161
 
    focused_imcontext->preedit_cursor_pos = cursor_pos;
162
 
 
163
 
    if (focused_imcontext->preedit_attrs != NULL)
164
 
        pango_attr_list_unref(focused_imcontext->preedit_attrs);
165
 
 
166
 
    focused_imcontext->preedit_attrs = attrs;
167
 
 
168
 
    g_signal_emit_by_name(focused_imcontext, "preedit-changed");
169
 
}
170
 
 
171
 
 
172
 
static GtkIMContext *
173
 
meego_imcontext_get_slave_imcontext(void)
174
 
{
175
 
    static GtkIMContext *slave_ic = NULL;
176
 
 
177
 
    if (!slave_ic) {
178
 
        slave_ic = gtk_im_context_simple_new();
179
 
        //g_signal_connect(G_OBJECT(slave_ic), "preedit-start", G_CALLBACK(slave_preedit_start), NULL);
180
 
        //g_signal_connect(G_OBJECT(slave_ic), "preedit-end", G_CALLBACK(slave_preedit_end), NULL);
181
 
        g_signal_connect(G_OBJECT(slave_ic), "preedit-changed", G_CALLBACK(slave_preedit_changed), NULL);
182
 
        g_signal_connect(G_OBJECT(slave_ic), "commit", G_CALLBACK(slave_commit), NULL);
183
 
    }
184
 
 
185
 
    return slave_ic;
186
 
}
187
 
 
188
 
 
189
 
GtkIMContext *
190
 
meego_imcontext_new(void)
191
 
{
192
 
    MeegoIMContext *ic = MEEGO_IMCONTEXT(g_object_new(MEEGO_TYPE_IMCONTEXT, NULL));
193
 
    return GTK_IM_CONTEXT(ic);
194
 
}
195
 
 
196
 
 
197
 
static void
198
 
meego_imcontext_finalize(GObject *object)
199
 
{
200
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(object);
201
 
 
202
 
    g_hash_table_destroy(imcontext->widget_state);
203
 
 
204
 
    if (imcontext->client_window)
205
 
        g_object_unref(imcontext->client_window);
206
 
 
207
 
    if (imcontext->registry)
208
 
        g_object_unref(imcontext->registry);
209
 
 
210
 
    g_signal_handlers_disconnect_by_data (imcontext->connector->dbusobj, object);
211
 
    g_signal_handlers_disconnect_by_data (imcontext->proxy, object);
212
 
 
213
 
    G_OBJECT_CLASS(parent_class)->finalize(object);
214
 
}
215
 
 
216
 
 
217
 
static void
218
 
meego_imcontext_class_init(MeegoIMContextClass *klass)
219
 
{
220
 
    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
221
 
    parent_class = (GtkIMContextClass *)g_type_class_peek_parent(klass);
222
 
    GtkIMContextClass *imclass = GTK_IM_CONTEXT_CLASS(klass);
223
 
 
224
 
    gobject_class->finalize = meego_imcontext_finalize;
225
 
 
226
 
    imclass->focus_in = meego_imcontext_focus_in;
227
 
    imclass->focus_out = meego_imcontext_focus_out;
228
 
    imclass->filter_keypress = meego_imcontext_filter_key_event;
229
 
    imclass->reset = meego_imcontext_reset;
230
 
    imclass->set_client_window = meego_imcontext_set_client_window;
231
 
    imclass->get_preedit_string = meego_imcontext_get_preedit_string;
232
 
    imclass->set_cursor_location = meego_imcontext_set_cursor_location;
233
 
    imclass->set_use_preedit = meego_imcontext_set_preedit_enabled;
234
 
}
235
 
 
236
 
 
237
 
static void
238
 
meego_imcontext_init(MeegoIMContext *self)
239
 
{
240
 
    self->client_window = NULL;
241
 
 
242
 
    self->cursor_location.x = -1;
243
 
    self->cursor_location.y = -1;
244
 
    self->cursor_location.width = 0;
245
 
    self->cursor_location.height = 0;
246
 
 
247
 
    self->preedit_str = NULL;
248
 
    self->preedit_attrs = NULL;
249
 
    self->preedit_cursor_pos = 0;
250
 
 
251
 
    self->widget_state = g_hash_table_new_full(&g_str_hash, &g_str_equal,
252
 
                         &g_free, (GDestroyNotify)destroy_g_value);
253
 
    self->focus_state = FALSE;
254
 
 
255
 
    self->connector = meego_im_connector_get_singleton();
256
 
    self->proxy = self->connector->proxy;
257
 
 
258
 
    self->registry = maliit_attribute_extension_registry_get_instance();
259
 
 
260
 
    MeegoIMContextDbusObj *dbusobj = self->connector->dbusobj;
261
 
    g_signal_connect(dbusobj, "im-initiated-hide",
262
 
                     G_CALLBACK(meego_imcontext_im_initiated_hide), self);
263
 
    g_signal_connect(dbusobj, "commit-string",
264
 
                     G_CALLBACK(meego_imcontext_commit_string), self);
265
 
    g_signal_connect(dbusobj, "update-preedit",
266
 
                     G_CALLBACK(meego_imcontext_update_preedit), self);
267
 
    g_signal_connect(dbusobj, "key-event",
268
 
                     G_CALLBACK(meego_imcontext_key_event), self);
269
 
    g_signal_connect(dbusobj, "copy",
270
 
                     G_CALLBACK(meego_imcontext_copy), self);
271
 
    g_signal_connect(dbusobj, "paste",
272
 
                     G_CALLBACK(meego_imcontext_paste), self);
273
 
    g_signal_connect(dbusobj, "set-redirect-keys",
274
 
                     G_CALLBACK(meego_imcontext_set_redirect_keys), self);
275
 
    g_signal_connect(dbusobj, "notify-extended-attribute-changed",
276
 
                     G_CALLBACK(meego_imcontext_notify_extended_attribute_changed), self);
277
 
    g_signal_connect(dbusobj, "update-input-method-area",
278
 
                     G_CALLBACK(meego_imcontext_update_input_method_area), self);
279
 
    g_signal_connect(self->proxy, "invoke-action",
280
 
                     G_CALLBACK(meego_imcontext_invoke_action), self);
281
 
}
282
 
 
283
 
 
284
 
static void
285
 
meego_imcontext_focus_in(GtkIMContext *context)
286
 
{
287
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(context);
288
 
    gboolean ret = TRUE;
289
 
    gboolean focus_changed = TRUE;
290
 
 
291
 
    DBG("imcontext = %p", imcontext);
292
 
 
293
 
    if (focused_imcontext && focused_imcontext != imcontext)
294
 
        meego_imcontext_focus_out(GTK_IM_CONTEXT(focused_imcontext));
295
 
    focused_imcontext = imcontext;
296
 
 
297
 
    imcontext->focus_state = TRUE;
298
 
    meego_imcontext_update_widget_info(imcontext);
299
 
 
300
 
    ret = meego_im_proxy_activate_context(imcontext->proxy);
301
 
    if (ret) {
302
 
        meego_im_proxy_update_widget_info(imcontext->proxy,
303
 
                                          imcontext->widget_state, focus_changed);
304
 
        meego_im_proxy_show_input_method(imcontext->proxy);
305
 
    }
306
 
    // TODO: anything else than call "activateContext" and "showInputMethod" ?
307
 
 
308
 
}
309
 
 
310
 
 
311
 
static void
312
 
meego_imcontext_focus_out(GtkIMContext *context)
313
 
{
314
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(context);
315
 
    DBG("imcontext = %p", imcontext);
316
 
 
317
 
    meego_imcontext_reset(context);
318
 
 
319
 
    imcontext->focus_state = FALSE;
320
 
    focused_imcontext = NULL;
321
 
    focused_widget = NULL;
322
 
 
323
 
    meego_imcontext_update_widget_info(imcontext);
324
 
    meego_im_proxy_update_widget_info(imcontext->proxy,
325
 
                                      imcontext->widget_state, TRUE);
326
 
 
327
 
    meego_im_proxy_hide_input_method(imcontext->proxy);
328
 
 
329
 
    // TODO: anything else than call "hideInputMethod" ?
330
 
}
331
 
 
332
 
 
333
 
static gboolean
334
 
meego_imcontext_filter_key_event(GtkIMContext *context, GdkEventKey *event)
335
 
{
336
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(context);
337
 
    int qevent_type = 0, qt_keycode = 0, qt_modifier = 0;
338
 
    gchar *text = "";
339
 
 
340
 
    focused_widget = gtk_get_event_widget((GdkEvent *)event);
341
 
 
342
 
    DBG("event type=0x%x, state=0x%x, keyval=0x%x, keycode=0x%x, group=%d",
343
 
        event->type, event->state, event->keyval, event->hardware_keycode, event->group);
344
 
 
345
 
    if (focused_imcontext != imcontext)
346
 
        meego_imcontext_focus_in(context);
347
 
 
348
 
    if ((event->state & IM_FORWARD_MASK) || !redirect_keys) {
349
 
        GtkIMContext *slave = meego_imcontext_get_slave_imcontext();
350
 
        return gtk_im_context_filter_keypress(slave, event);
351
 
    }
352
 
 
353
 
    if (!gdk_key_event_to_qt(event, &qevent_type, &qt_keycode, &qt_modifier))
354
 
        return FALSE;
355
 
 
356
 
    meego_im_proxy_process_key_event(imcontext->proxy, qevent_type, qt_keycode, qt_modifier,
357
 
                                     text, 0, 1, event->hardware_keycode, event->state, event->time);
358
 
 
359
 
    return TRUE;
360
 
}
361
 
 
362
 
 
363
 
static void
364
 
meego_imcontext_reset(GtkIMContext *context)
365
 
{
366
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(context);
367
 
    DBG("imcontext = %p", imcontext);
368
 
 
369
 
    if (imcontext != focused_imcontext) {
370
 
        return;
371
 
    }
372
 
 
373
 
    /* Commit preedit if it is not empty */
374
 
    if (focused_imcontext && focused_imcontext->preedit_str && focused_imcontext->preedit_str[0]) {
375
 
        char *commit_string = focused_imcontext->preedit_str;
376
 
        focused_imcontext->preedit_str = g_strdup("");
377
 
        focused_imcontext->preedit_cursor_pos = 0;
378
 
        g_signal_emit_by_name(focused_imcontext, "preedit-changed");
379
 
        g_signal_emit_by_name(focused_imcontext, "commit", commit_string);
380
 
        g_free(commit_string);
381
 
    }
382
 
 
383
 
    meego_im_proxy_reset(imcontext->proxy);
384
 
}
385
 
 
386
 
 
387
 
static void
388
 
meego_imcontext_get_preedit_string(GtkIMContext *context, gchar **str, PangoAttrList **attrs, gint *cursor_pos)
389
 
{
390
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(context);
391
 
 
392
 
    DBG("imcontext = %p", imcontext);
393
 
 
394
 
    if (str) {
395
 
        if (imcontext->preedit_str)
396
 
            *str = g_strdup(imcontext->preedit_str);
397
 
        else
398
 
            *str = g_strdup("");
399
 
    }
400
 
 
401
 
    if (attrs) {
402
 
        if (imcontext->preedit_attrs) {
403
 
            *attrs = imcontext->preedit_attrs;
404
 
            pango_attr_list_ref(imcontext->preedit_attrs);
405
 
        } else {
406
 
            *attrs = pango_attr_list_new();
407
 
        }
408
 
    }
409
 
 
410
 
    if (cursor_pos)
411
 
        *cursor_pos = imcontext->preedit_cursor_pos;
412
 
}
413
 
 
414
 
 
415
 
static void
416
 
meego_imcontext_set_preedit_enabled(GtkIMContext *context, gboolean enabled)
417
 
{
418
 
    UNUSED(context);
419
 
    UNUSED(enabled);
420
 
    // TODO: Seems QT/MEEGO don't need it, it will always showing preedit.
421
 
    return;
422
 
}
423
 
 
424
 
 
425
 
static void
426
 
meego_imcontext_set_client_window(GtkIMContext *context, GdkWindow *window)
427
 
{
428
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(context);
429
 
    STEP();
430
 
 
431
 
    if (imcontext->client_window)
432
 
        g_object_unref(imcontext->client_window);
433
 
 
434
 
    if (window)
435
 
        g_object_ref(window);
436
 
 
437
 
    imcontext->client_window = window;
438
 
 
439
 
    // TODO: might need to update cursor position or other staff later using this info?
440
 
}
441
 
 
442
 
 
443
 
static void
444
 
meego_imcontext_set_cursor_location(GtkIMContext *context, GdkRectangle *area)
445
 
{
446
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(context);
447
 
    //DBG("imcontext = %p, x=%d, y=%d, w=%d, h=%d", imcontext,
448
 
    //  area->x, area->y, area->width, area->height);
449
 
 
450
 
    imcontext->cursor_location = *area;
451
 
 
452
 
    // TODO: call updateWidgetInformation?
453
 
    //The cursor location from GTK widget is simillar to ImMicroFocus info of a QWidget
454
 
    //Thus we might need to update Qt::ImMicroFocus info according to this.
455
 
    //But MEEGO IM seems not using this info at all
456
 
}
457
 
 
458
 
/* Update the widget_state map with current information about the widget. */
459
 
void
460
 
meego_imcontext_update_widget_info(MeegoIMContext *imcontext)
461
 
{
462
 
    /* Clear table */
463
 
    g_hash_table_remove_all(imcontext->widget_state);
464
 
 
465
 
    /* Focus state */
466
 
    GValue *focus_value = g_new0(GValue, 1);
467
 
    g_value_init(focus_value, G_TYPE_BOOLEAN);
468
 
    g_value_set_boolean(focus_value, imcontext->focus_state);
469
 
    g_hash_table_insert(imcontext->widget_state, g_strdup(WIDGET_INFO_FOCUS_STATE), focus_value);
470
 
 
471
 
    if (!imcontext->focus_state)
472
 
        return;
473
 
 
474
 
    /* Window ID */
475
 
    if (imcontext->client_window) {
476
 
        guint64 xid = GDK_WINDOW_XID(imcontext->client_window);
477
 
        GValue *xid_value = g_new0(GValue, 1);
478
 
        g_value_init(xid_value, G_TYPE_UINT64);
479
 
        g_value_set_uint64(xid_value, xid);
480
 
        g_hash_table_insert(imcontext->widget_state, g_strdup(WIDGET_INFO_WIN_ID), xid_value);
481
 
    }
482
 
 
483
 
    /* Attribute extensions */
484
 
    if (imcontext->client_window) {
485
 
        gpointer user_data = NULL;
486
 
        GtkWidget* widget = NULL;
487
 
        MaliitAttributeExtension *extension;
488
 
        GValue *id_value;
489
 
        GValue *filename_value;
490
 
 
491
 
        gdk_window_get_user_data (imcontext->client_window, &user_data);
492
 
 
493
 
        widget = GTK_WIDGET (user_data);
494
 
 
495
 
        user_data = g_object_get_qdata (G_OBJECT (widget),
496
 
                                        MALIIT_ATTRIBUTE_EXTENSION_DATA_QUARK);
497
 
 
498
 
        if (user_data) {
499
 
            extension = MALIIT_ATTRIBUTE_EXTENSION (user_data);
500
 
            id_value = g_new0 (GValue, 1);
501
 
            filename_value = g_new0 (GValue, 1);
502
 
 
503
 
            g_value_init (id_value, G_TYPE_INT);
504
 
            g_value_set_int (id_value, maliit_attribute_extension_get_id (extension));
505
 
            g_value_init (filename_value, G_TYPE_STRING);
506
 
            g_value_set_string (filename_value, maliit_attribute_extension_get_filename (extension));
507
 
            g_hash_table_replace (imcontext->widget_state,
508
 
                                  g_strdup(WIDGET_INFO_ATTRIBUTE_EXTENSION_ID),
509
 
                                  id_value);
510
 
            g_hash_table_replace (imcontext->widget_state,
511
 
                                  g_strdup(WIDGET_INFO_ATTRIBUTE_EXTENSION_FILENAME),
512
 
                                  filename_value);
513
 
        }
514
 
    }
515
 
 
516
 
    /* Surrounding text */
517
 
    GtkIMContext *context = GTK_IM_CONTEXT(imcontext);
518
 
    gchar *surrounding_text;
519
 
    gint cursor_index;
520
 
    if (gtk_im_context_get_surrounding(context, &surrounding_text, &cursor_index))
521
 
    {
522
 
        GValue *surrounding_text_value = g_new0 (GValue, 1);
523
 
        GValue *cursor_position_value = g_new0 (GValue, 1);
524
 
 
525
 
        g_value_init (surrounding_text_value, G_TYPE_STRING);
526
 
        g_value_take_string (surrounding_text_value, surrounding_text);
527
 
        g_hash_table_replace(imcontext->widget_state, g_strdup(WIDGET_INFO_SURROUNDING_TEXT), surrounding_text_value);
528
 
 
529
 
        g_value_init (cursor_position_value, G_TYPE_INT);
530
 
        g_value_set_int(cursor_position_value, cursor_index);
531
 
        g_hash_table_replace(imcontext->widget_state, g_strdup(WIDGET_INFO_CURSOR_POSITION), cursor_position_value);
532
 
    }
533
 
}
534
 
 
535
 
// Call back functions for dbus obj
536
 
void
537
 
meego_imcontext_im_initiated_hide(MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
538
 
                                  gpointer user_data)
539
 
{
540
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
541
 
    if (imcontext != focused_imcontext)
542
 
        return;
543
 
 
544
 
    if (focused_imcontext && focused_imcontext->client_window) {
545
 
        gpointer user_data = NULL;
546
 
        GtkWidget* parent_widget = NULL;
547
 
 
548
 
        gdk_window_get_user_data (focused_imcontext->client_window, &user_data);
549
 
 
550
 
        parent_widget = GTK_WIDGET (user_data);
551
 
 
552
 
        while (parent_widget && !GTK_IS_WINDOW (parent_widget)) {
553
 
            parent_widget = gtk_widget_get_parent (parent_widget);
554
 
        }
555
 
        if (parent_widget) {
556
 
            gtk_window_set_focus (GTK_WINDOW (parent_widget), NULL);
557
 
            return;
558
 
        }
559
 
    }
560
 
}
561
 
 
562
 
void
563
 
meego_imcontext_commit_string(MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
564
 
                              char *string,
565
 
                              int replacement_start G_GNUC_UNUSED,
566
 
                              int replacement_length G_GNUC_UNUSED,
567
 
                              int cursor_pos G_GNUC_UNUSED,
568
 
                              gpointer user_data)
569
 
{
570
 
    DBG("string is:%s", string);
571
 
 
572
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
573
 
    if (imcontext != focused_imcontext)
574
 
        return;
575
 
 
576
 
    if (focused_imcontext) {
577
 
        g_free(focused_imcontext->preedit_str);
578
 
        focused_imcontext->preedit_str = g_strdup("");
579
 
        focused_imcontext->preedit_cursor_pos = 0;
580
 
        g_signal_emit_by_name(focused_imcontext, "preedit-changed");
581
 
        g_signal_emit_by_name(focused_imcontext, "commit", string);
582
 
    }
583
 
}
584
 
 
585
 
typedef enum
586
 
{
587
 
    MaliitPreeditDefault,
588
 
    MaliitPreeditNoCandidates,
589
 
    MaliitPreeditKeyPress,
590
 
    MaliitPreeditUnconvertible,
591
 
    MaliitPreeditActive
592
 
} MaliitPreeditFace;
593
 
 
594
 
static void
595
 
get_byte_range_from_unicode_offsets (const gchar *string,
596
 
                                     gint         utf8_start,
597
 
                                     gint         utf8_length,
598
 
                                     gint        *byte_start,
599
 
                                     gint        *byte_end)
600
 
{
601
 
    gint start;
602
 
    gint end;
603
 
 
604
 
    /* we provide start index and length in utf8 characters, but pango
605
 
     * expects start and end indices in bytes.
606
 
     */
607
 
    if (g_utf8_validate (string, -1, NULL)) {
608
 
        const gchar * const start_pointer = g_utf8_offset_to_pointer (string, utf8_start);
609
 
        const gchar * const end_pointer = g_utf8_offset_to_pointer (string, utf8_start + utf8_length);
610
 
 
611
 
        /* pointer arithmetics, there you have it. */
612
 
        start = start_pointer - string;
613
 
        end = end_pointer - string;
614
 
    } else {
615
 
        start = utf8_start;
616
 
        end = utf8_start + utf8_length;
617
 
    }
618
 
 
619
 
    if (byte_start) {
620
 
        *byte_start = start;
621
 
    }
622
 
    if (byte_end) {
623
 
        *byte_end = end;
624
 
    }
625
 
}
626
 
 
627
 
void
628
 
meego_imcontext_update_preedit(MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
629
 
                               const char *string,
630
 
                               GPtrArray *formatListData,
631
 
                               gint32 replaceStart G_GNUC_UNUSED,
632
 
                               gint32 replaceLength G_GNUC_UNUSED,
633
 
                               gint32 cursorPos,
634
 
                               gpointer user_data)
635
 
{
636
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
637
 
    if (imcontext != focused_imcontext)
638
 
        return;
639
 
 
640
 
    DBG("imcontext = %p string = %s cursorPos = %d", imcontext, string, cursorPos);
641
 
 
642
 
    if (focused_imcontext) {
643
 
        guint iter;
644
 
        PangoAttrList* attrs;
645
 
 
646
 
        g_free(focused_imcontext->preedit_str);
647
 
        focused_imcontext->preedit_str = g_strdup(string);
648
 
        /* If cursorPos is -1 explicitly set it to the end of the preedit */
649
 
        if (cursorPos == -1) {
650
 
            cursorPos = g_utf8_strlen(string, -1);
651
 
        }
652
 
        focused_imcontext->preedit_cursor_pos = cursorPos;
653
 
 
654
 
        /* attributes */
655
 
        attrs = pango_attr_list_new();
656
 
 
657
 
        for (iter = 0; iter < formatListData->len; ++iter) {
658
 
            GValueArray *text_format = g_ptr_array_index (formatListData, iter);
659
 
            gint start = g_value_get_int(g_value_array_get_nth(text_format, 0));
660
 
            gint length = g_value_get_int(g_value_array_get_nth(text_format, 1));
661
 
            MaliitPreeditFace preedit_face = (MaliitPreeditFace)g_value_get_int(g_value_array_get_nth(text_format, 2));
662
 
            gint byte_start;
663
 
            gint byte_end;
664
 
            PangoAttribute* new_attrs[2] = { NULL, NULL };
665
 
            gint attr_iter;
666
 
 
667
 
            get_byte_range_from_unicode_offsets(string, start, length, &byte_start, &byte_end);
668
 
 
669
 
            switch (preedit_face) {
670
 
            case MaliitPreeditNoCandidates:
671
 
                new_attrs[0] = pango_attr_underline_new (PANGO_UNDERLINE_ERROR);
672
 
                new_attrs[1] = pango_attr_underline_color_new (65535, 0, 0);
673
 
                break;
674
 
 
675
 
            case MaliitPreeditUnconvertible: {
676
 
                const gint gray = (2 << 15) - 1; /* halfway from 0 to 65535 */
677
 
 
678
 
                new_attrs[0] = pango_attr_foreground_new (gray, gray, gray);
679
 
            } break;
680
 
 
681
 
            case MaliitPreeditActive:
682
 
                new_attrs[0] = pango_attr_foreground_new(39168, 12800, 52224);
683
 
                new_attrs[1] = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
684
 
                break;
685
 
 
686
 
            case MaliitPreeditKeyPress:
687
 
            case MaliitPreeditDefault:
688
 
                new_attrs[0] = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
689
 
                new_attrs[1] = pango_attr_underline_color_new(0, 0, 0);
690
 
                break;
691
 
            }
692
 
 
693
 
            for (attr_iter = 0; attr_iter < 2; ++attr_iter) {
694
 
                if (new_attrs[attr_iter]) {
695
 
                    new_attrs[attr_iter]->start_index = byte_start;
696
 
                    new_attrs[attr_iter]->end_index = byte_end;
697
 
 
698
 
                    pango_attr_list_insert(attrs, new_attrs[attr_iter]);
699
 
                }
700
 
            }
701
 
        }
702
 
 
703
 
        if (focused_imcontext->preedit_attrs) {
704
 
            pango_attr_list_unref (focused_imcontext->preedit_attrs);
705
 
        }
706
 
        focused_imcontext->preedit_attrs = attrs;
707
 
 
708
 
        g_signal_emit_by_name(focused_imcontext, "preedit-changed");
709
 
    }
710
 
}
711
 
 
712
 
void
713
 
meego_imcontext_key_event(MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
714
 
                          int type,
715
 
                          int key,
716
 
                          int modifiers,
717
 
                          char *text,
718
 
                          gboolean auto_repeat G_GNUC_UNUSED,
719
 
                          int count G_GNUC_UNUSED,
720
 
                          gpointer user_data)
721
 
{
722
 
    GdkEventKey *event = NULL;
723
 
    GdkWindow *window = NULL;
724
 
 
725
 
    STEP();
726
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
727
 
    if (imcontext != focused_imcontext)
728
 
        return;
729
 
 
730
 
    if (focused_imcontext)
731
 
        window = focused_imcontext->client_window;
732
 
 
733
 
    event = qt_key_event_to_gdk(type, key, modifiers, text, window);
734
 
    if (!event)
735
 
        return;
736
 
 
737
 
    event->send_event = TRUE;
738
 
    event->state |= IM_FORWARD_MASK;
739
 
 
740
 
    gdk_event_put((GdkEvent *)event);
741
 
    gdk_event_free((GdkEvent *)event);
742
 
}
743
 
 
744
 
void
745
 
meego_imcontext_copy(MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
746
 
                     gpointer user_data)
747
 
{
748
 
    GdkWindow *window = NULL;
749
 
    GdkEventKey *event = NULL;
750
 
 
751
 
    STEP();
752
 
 
753
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
754
 
    if (imcontext != focused_imcontext)
755
 
        return;
756
 
 
757
 
    if (focused_imcontext)
758
 
        window = focused_imcontext->client_window;
759
 
 
760
 
    event = compose_gdk_keyevent(GDK_KEY_PRESS, XK_C, GDK_CONTROL_MASK, window);
761
 
    if (event) {
762
 
        event->send_event = TRUE;
763
 
        event->state |= IM_FORWARD_MASK;
764
 
        gdk_event_put((GdkEvent *)event);
765
 
        gdk_event_free((GdkEvent *)event);
766
 
    }
767
 
 
768
 
    event = compose_gdk_keyevent(GDK_KEY_RELEASE, XK_C, GDK_CONTROL_MASK, window);
769
 
    if (event) {
770
 
        event->send_event = TRUE;
771
 
        event->state |= IM_FORWARD_MASK;
772
 
        gdk_event_put((GdkEvent *)event);
773
 
        gdk_event_free((GdkEvent *)event);
774
 
    }
775
 
}
776
 
 
777
 
static unsigned int
778
 
find_signal(const char *action, const char *alternative, GtkWidget *widget)
779
 
{
780
 
    unsigned int signal = g_signal_lookup(action, G_OBJECT_TYPE(widget));
781
 
 
782
 
    if (signal || alternative == NULL) {
783
 
        return signal;
784
 
    }
785
 
 
786
 
    return g_signal_lookup(alternative, G_OBJECT_TYPE(widget));
787
 
}
788
 
 
789
 
void
790
 
meego_imcontext_invoke_action(MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
791
 
                              const char *action,
792
 
                              const char *sequence G_GNUC_UNUSED,
793
 
                              gpointer user_data)
794
 
{
795
 
    GtkWidget* widget = NULL;
796
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
797
 
 
798
 
    if (imcontext != focused_imcontext)
799
 
        return;
800
 
 
801
 
    gdk_window_get_user_data (imcontext->client_window, &user_data);
802
 
    widget = GTK_WIDGET (user_data);
803
 
 
804
 
    if (widget) {
805
 
        char *alternative = NULL;
806
 
        unsigned int signal;
807
 
 
808
 
        if (g_strcmp0(action, "copy") == 0 ||
809
 
            g_strcmp0(action, "cut") == 0 ||
810
 
            g_strcmp0(action, "paste") == 0)
811
 
        {
812
 
            alternative = g_strdup_printf("%s-clipboard", action);
813
 
        }
814
 
 
815
 
        signal = find_signal(action, alternative, widget);
816
 
        g_free(alternative);
817
 
 
818
 
        if (signal) {
819
 
            g_signal_emit(widget, signal, 0);
820
 
            return;
821
 
        }
822
 
    }
823
 
}
824
 
 
825
 
void
826
 
meego_imcontext_paste(MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
827
 
                      gpointer user_data)
828
 
{
829
 
    GdkWindow *window = NULL;
830
 
    GdkEventKey *event = NULL;
831
 
 
832
 
    STEP();
833
 
 
834
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
835
 
    if (imcontext != focused_imcontext)
836
 
        return;
837
 
 
838
 
    if (focused_imcontext)
839
 
        window = focused_imcontext->client_window;
840
 
 
841
 
    event = compose_gdk_keyevent(GDK_KEY_PRESS, XK_V, GDK_CONTROL_MASK, window);
842
 
    if (event) {
843
 
        event->send_event = TRUE;
844
 
        event->state |= IM_FORWARD_MASK;
845
 
        gdk_event_put((GdkEvent *)event);
846
 
        gdk_event_free((GdkEvent *)event);
847
 
    }
848
 
 
849
 
    event = compose_gdk_keyevent(GDK_KEY_RELEASE, XK_V, GDK_CONTROL_MASK, window);
850
 
    if (event) {
851
 
        event->send_event = TRUE;
852
 
        event->state |= IM_FORWARD_MASK;
853
 
        gdk_event_put((GdkEvent *)event);
854
 
        gdk_event_free((GdkEvent *)event);
855
 
    }
856
 
}
857
 
 
858
 
void
859
 
meego_imcontext_set_redirect_keys(MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
860
 
                                  gboolean enabled,
861
 
                                  gpointer user_data G_GNUC_UNUSED)
862
 
{
863
 
    DBG("enabled = %d", enabled);
864
 
    redirect_keys = enabled;
865
 
}
866
 
 
867
 
void
868
 
meego_imcontext_notify_extended_attribute_changed (MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
869
 
                                                   gint id,
870
 
                                                   const gchar *target,
871
 
                                                   const gchar *target_item,
872
 
                                                   const gchar *attribute,
873
 
                                                   GVariant *variant_value,
874
 
                                                   gpointer user_data G_GNUC_UNUSED)
875
 
{
876
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
877
 
    if (imcontext != focused_imcontext)
878
 
        return;
879
 
 
880
 
    maliit_attribute_extension_registry_update_attribute (focused_imcontext->registry,
881
 
                                                          id,
882
 
                                                          target,
883
 
                                                          target_item,
884
 
                                                          attribute,
885
 
                                                          variant_value);
886
 
}
887
 
 
888
 
void
889
 
meego_imcontext_update_input_method_area (MeegoIMContextDbusObj *obj G_GNUC_UNUSED,
890
 
                                          int x,
891
 
                                          int y,
892
 
                                          int width,
893
 
                                          int height,
894
 
                                          gpointer user_data)
895
 
{
896
 
    MeegoIMContext *imcontext = MEEGO_IMCONTEXT(user_data);
897
 
    GdkRectangle cursor_rect, osk_rect = { x, y, width, height };
898
 
    guint clear_area_id;
899
 
 
900
 
    if (!imcontext->client_window)
901
 
      return;
902
 
 
903
 
    if (imcontext->keyboard_area.x == x &&
904
 
        imcontext->keyboard_area.y == y &&
905
 
        imcontext->keyboard_area.width == width &&
906
 
        imcontext->keyboard_area.height == height)
907
 
      return;
908
 
 
909
 
    clear_area_id = g_signal_lookup ("clear-area", GTK_TYPE_IM_CONTEXT);
910
 
 
911
 
    if (clear_area_id == 0)
912
 
      return;
913
 
 
914
 
    imcontext->keyboard_area = osk_rect;
915
 
 
916
 
    gdk_window_get_root_coords (imcontext->client_window,
917
 
                                imcontext->cursor_location.x,
918
 
                                imcontext->cursor_location.y,
919
 
                                &cursor_rect.x, &cursor_rect.y);
920
 
    cursor_rect.width = imcontext->cursor_location.width;
921
 
    cursor_rect.height = imcontext->cursor_location.height;
922
 
 
923
 
    g_signal_emit (imcontext, clear_area_id, 0, &osk_rect, &cursor_rect);
924
 
}