Fix handling of backspace key press
[profile/ivi/weekeyboard.git] / src / wkb-ibus-panel.c
1 /*
2  * Copyright © 2013 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include <Eldbus.h>
22
23 #include "wkb-ibus.h"
24
25 #define PANEL_CHECK_MESSAGE_ERRORS(_msg) \
26    do \
27      { \
28         const char *error, *error_msg; \
29         if (eldbus_message_error_get(_msg, &error, &error_msg)) \
30           { \
31              ERR("DBus message error: %s: %s", error, error_msg); \
32              return NULL; \
33           } \
34         DBG("Message '%s' with signature '%s'", eldbus_message_member_get(_msg), eldbus_message_signature_get(_msg)); \
35      } while (0);
36
37 static Eina_Array *_get_properties_from_message_iter(Eldbus_Message_Iter *iter);
38
39 struct _ibus_serializable
40 {
41    /*
42     * All messages sent by IBus will start with the sa{sv} signature, but
43     * those fields don't seem useful for us, this struct is used to help
44     * on deserializing those fields
45     */
46    char *text;
47    Eldbus_Message_Iter *variant;
48 };
49
50 struct _ibus_attr
51 {
52    unsigned int type;
53    unsigned int value;
54    unsigned int start_idx;
55    unsigned int end_idx;
56 };
57
58 struct _ibus_text
59 {
60    char *text;
61    Eina_Array *attrs;
62 };
63
64 struct _ibus_lookup_table
65 {
66    unsigned int page_size;
67    unsigned int cursor_pos;
68    Eina_Bool cursor_visible;
69    Eina_Bool round;
70    int orientation;
71    Eina_Array *candidates;
72    Eina_Array *labels;
73 };
74
75 struct _ibus_property
76 {
77    char *key;
78    char *icon;
79    struct _ibus_text *label;
80    struct _ibus_text *symbol;
81    struct _ibus_text *tooltip;
82    Eina_Bool sensitive;
83    Eina_Bool visible;
84    unsigned int type;
85    unsigned int state;
86    Eina_Array *sub_properties;
87 };
88
89 static struct _ibus_attr *
90 _get_attr_from_message_iter(Eldbus_Message_Iter *iter)
91 {
92    struct _ibus_attr *attr = calloc(1, sizeof(*attr));
93
94    EINA_SAFETY_ON_NULL_RETURN_VAL(attr, NULL);
95
96    DBG("Attribute iter signature '%s'", eldbus_message_iter_signature_get(iter));
97
98    if (!eldbus_message_iter_arguments_get(iter, "uuuu", &attr->type,
99                                           &attr->value, &attr->start_idx,
100                                           &attr->end_idx))
101      {
102         ERR("Error deserializing IBusAttribute");
103         free(attr);
104         attr = NULL;
105      }
106
107    return attr;
108 }
109
110 static void
111 _free_eina_array(Eina_Array *array, void (* free_func)(void *))
112 {
113    if (!array)
114       return;
115
116    while (eina_array_count(array))
117       free_func(eina_array_pop(array));
118
119    eina_array_free(array);
120 }
121
122 static void
123 _free_text(struct _ibus_text *text)
124 {
125    if (!text)
126       return;
127
128    _free_eina_array(text->attrs, free);
129    free(text->text);
130    free(text);
131 }
132
133 static struct _ibus_text *
134 _get_text_from_message_iter(Eldbus_Message_Iter *iter)
135 {
136    struct _ibus_serializable ignore = { 0 };
137    struct _ibus_text *text = calloc(1, sizeof(*text));
138    struct _ibus_attr *attr = NULL;
139    Eldbus_Message_Iter *attrs = NULL, *a = NULL;
140
141    EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
142
143    DBG("Text iter signature '%s'", eldbus_message_iter_signature_get(iter));
144
145    if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}sv)", &ignore.text,
146                                           &ignore.variant, &text->text, &attrs))
147      {
148         ERR("Error deserializing IBusText");
149         free(text);
150         text = NULL;
151         goto end;
152      }
153
154    /* Check for attributes */
155    if (attrs == NULL)
156      {
157         INF("Text has no attributes");
158         goto end;
159      }
160
161    while (eldbus_message_iter_get_and_next(attrs, 'v', &a))
162      {
163         if (!text->attrs)
164            text->attrs = eina_array_new(10);
165
166         if (!(attr = _get_attr_from_message_iter(a)))
167           {
168              _free_text(text);
169              text = NULL;
170              goto end;
171           }
172
173         eina_array_push(text->attrs, attr);
174      }
175
176 end:
177    return text;
178 }
179
180 static void
181 _free_lookup_table(struct _ibus_lookup_table *table)
182 {
183    if (!table)
184       return;
185
186    _free_eina_array(table->candidates, _free_text);
187    _free_eina_array(table->labels, _free_text);
188    free(table);
189 }
190
191 static struct _ibus_lookup_table *
192 _get_lookup_table_from_message_iter(Eldbus_Message_Iter *iter)
193 {
194    struct _ibus_serializable ignore = { 0 };
195    struct _ibus_lookup_table *table = calloc(1, sizeof(*table));
196    struct _ibus_text *text = NULL;
197    Eldbus_Message_Iter *candidates = NULL, *labels = NULL, *t = NULL;
198
199    EINA_SAFETY_ON_NULL_RETURN_VAL(table, NULL);
200
201    DBG("LookupTable iter signature '%s'", eldbus_message_iter_signature_get(iter));
202
203    if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}uubbiavav)",
204                                           &ignore.text, &ignore.variant,
205                                           &table->page_size, &table->cursor_pos,
206                                           &table->cursor_visible, &table->round,
207                                           &table->orientation, &candidates,
208                                           &labels))
209      {
210         ERR("Error deserializing IBusLookupTable");
211         free(table);
212         table = NULL;
213         goto end;
214      }
215
216    DBG("Lookup table:");
217    DBG("\tPage size.......: '%d'", table->page_size);
218    DBG("\tCursor position.: '%d'", table->cursor_pos);
219    DBG("\tCursor visible..: '%d'", table->cursor_visible);
220    DBG("\tRound...........: '%d'", table->round);
221    DBG("\tOrientation.....: '%d'", table->orientation);
222    DBG("\tCandidates......: '%p'", candidates);
223    DBG("\tLabels..........: '%p'", labels);
224
225    if (!candidates)
226      {
227         INF("Lookup table has no candidates");
228         goto labels;
229      }
230
231    while (eldbus_message_iter_get_and_next(candidates, 'v', &t))
232      {
233         if (!table->candidates)
234            table->candidates = eina_array_new(10);
235
236         if (!(text = _get_text_from_message_iter(t)))
237           {
238              _free_lookup_table(table);
239              table = NULL;
240              goto end;
241           }
242
243         DBG("Appending new candidate %s", text->text);
244         eina_array_push(table->candidates, text);
245      }
246
247 labels:
248    if (!labels)
249      {
250         INF("Lookup table has no labels");
251         goto end;
252      }
253
254    while (eldbus_message_iter_get_and_next(labels, 'v', &t))
255      {
256         if (!table->labels)
257            table->labels = eina_array_new(10);
258
259         if (!(text = _get_text_from_message_iter(t)))
260           {
261              _free_lookup_table(table);
262              table = NULL;
263              goto end;
264           }
265
266         DBG("Appending new label %s", text->text);
267         eina_array_push(table->labels, text);
268      }
269
270 end:
271    return table;
272 }
273
274 static void
275 _free_property(struct _ibus_property *property)
276 {
277    if (!property)
278       return;
279
280    free(property->key);
281    free(property->icon);
282    _free_text(property->label);
283    _free_text(property->symbol);
284    _free_text(property->tooltip);
285    _free_eina_array(property->sub_properties, _free_property);
286    free(property);
287 }
288
289 static struct _ibus_property *
290 _get_property_from_message_iter(Eldbus_Message_Iter *iter)
291 {
292    struct _ibus_serializable ignore = { 0 };
293    struct _ibus_property *prop = calloc(1, sizeof(*prop));
294    Eldbus_Message_Iter *label = NULL, *symbol = NULL, *tooltip = NULL, *sub_props = NULL;
295
296    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, NULL);
297
298    DBG("Property iter signature '%s'", eldbus_message_iter_signature_get(iter));
299
300    if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}suvsvbbuvv)",
301                                           &ignore.text, &ignore.variant,
302                                           &prop->key, &prop->type,
303                                           &label, &prop->icon, &tooltip,
304                                           &prop->sensitive, &prop->visible,
305                                           &prop->state, &sub_props, &symbol))
306      {
307         ERR("Error deserializing IBusProperty");
308         free(prop);
309         prop = NULL;
310         goto end;
311      }
312
313    DBG("Property :");
314    DBG("\tKey.............: '%s'", prop->key);
315    DBG("\tType............: '%d'", prop->type);
316    DBG("\tLabel...........: '%p'", label);
317    DBG("\tIcon............: '%s'", prop->icon);
318    DBG("\tTooltip.........: '%p'", tooltip);
319    DBG("\tSensitive.......: '%d'", prop->sensitive);
320    DBG("\tVisible.........: '%d'", prop->visible);
321    DBG("\tState...........: '%d'", prop->state);
322    DBG("\tSub Properties..: '%p'", sub_props);
323    DBG("\tSymbol..........: '%p'", symbol);
324
325    if (!label)
326      {
327         INF("Property has no label");
328         goto symbol;
329      }
330
331    if (!(prop->label = _get_text_from_message_iter(label)))
332      {
333         _free_property(prop);
334         prop = NULL;
335         goto end;
336      }
337
338 symbol:
339    if (!symbol)
340      {
341         INF("Property has no symbol");
342         goto tooltip;
343      }
344
345    if (!(prop->symbol = _get_text_from_message_iter(symbol)))
346      {
347         _free_property(prop);
348         prop = NULL;
349         goto end;
350      }
351
352 tooltip:
353    if (!tooltip)
354      {
355         INF("Property has no tooltip");
356         goto sub_props;
357      }
358
359    if (!(prop->tooltip = _get_text_from_message_iter(tooltip)))
360      {
361         _free_property(prop);
362         prop = NULL;
363         goto end;
364      }
365
366 sub_props:
367    if (!sub_props)
368      {
369         INF("Property has no sub properties");
370         goto end;
371      }
372
373    prop->sub_properties = _get_properties_from_message_iter(sub_props);
374
375 end:
376    return prop;
377 }
378
379 static Eina_Array *
380 _get_properties_from_message_iter(Eldbus_Message_Iter *iter)
381 {
382    Eina_Array *properties = NULL;
383    Eldbus_Message_Iter *props = NULL, *prop = NULL;
384    struct _ibus_serializable ignore = { 0 };
385    struct _ibus_property *property = NULL;
386
387    DBG("PropList iter signature '%s'", eldbus_message_iter_signature_get(iter));
388
389    if (!eldbus_message_iter_arguments_get(iter, "(sa{sv}av)", &ignore.text, &ignore.variant, &props))
390      {
391         ERR("Error deserializing IBusPropList");
392         goto end;
393      }
394
395    if (!props)
396      {
397         INF("PropList has no property");
398         goto end;
399      }
400
401    while (eldbus_message_iter_get_and_next(props, 'v', &prop))
402      {
403         if (!properties)
404            properties = eina_array_new(10);
405
406         if (!(property = _get_property_from_message_iter(prop)))
407           {
408              _free_eina_array(properties, _free_property);
409              properties = NULL;
410              goto end;
411           }
412
413         DBG("Appending new property %p", property);
414         eina_array_push(properties, property);
415      }
416
417 end:
418    return properties;
419 }
420
421 static Eldbus_Message *
422 _panel_update_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
423 {
424    Eldbus_Message_Iter *text = NULL;
425    unsigned int cursor_pos = 0;
426    Eina_Bool visible = 0;
427    struct _ibus_text *ibus_text;
428
429    PANEL_CHECK_MESSAGE_ERRORS(msg)
430
431    if (!eldbus_message_arguments_get(msg, "vub", &text, &cursor_pos, &visible))
432      {
433         ERR("Error reading message arguments");
434         return NULL;
435      }
436
437    DBG("text: '%p', cursor_pos: '%d', visible: '%d')", text, cursor_pos, visible);
438
439    ibus_text = _get_text_from_message_iter(text);
440    DBG("Preedit text = '%s'", ibus_text->text);
441    _free_text(ibus_text);
442
443    return NULL;
444 }
445
446 static Eldbus_Message *
447 _panel_show_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
448 {
449    PANEL_CHECK_MESSAGE_ERRORS(msg)
450
451    return NULL;
452 }
453
454 static Eldbus_Message *
455 _panel_hide_preedit_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
456 {
457    PANEL_CHECK_MESSAGE_ERRORS(msg)
458
459    return NULL;
460 }
461
462 static Eldbus_Message *
463 _panel_update_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
464 {
465    Eldbus_Message_Iter *text = NULL;
466    Eina_Bool visible = 0;
467    struct _ibus_text *ibus_text;
468
469    PANEL_CHECK_MESSAGE_ERRORS(msg)
470
471    if (!eldbus_message_arguments_get(msg, "vb", &text, &visible))
472      {
473         ERR("Error reading message arguments");
474         return NULL;
475      }
476
477    DBG("text: '%p', visible: '%d'", text, visible);
478
479    ibus_text = _get_text_from_message_iter(text);
480    DBG("Auxiliary text = '%s'", ibus_text->text);
481    _free_text(ibus_text);
482
483    return NULL;
484 }
485
486 static Eldbus_Message *
487 _panel_show_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
488 {
489    PANEL_CHECK_MESSAGE_ERRORS(msg)
490
491    return NULL;
492 }
493
494 static Eldbus_Message *
495 _panel_hide_auxiliary_text(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
496 {
497    PANEL_CHECK_MESSAGE_ERRORS(msg)
498
499    return NULL;
500 }
501
502 static Eldbus_Message *
503 _panel_update_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
504 {
505    Eldbus_Message_Iter *table = NULL;
506    Eina_Bool visible =  0;
507    struct _ibus_lookup_table *ibus_lookup_table;
508
509    PANEL_CHECK_MESSAGE_ERRORS(msg)
510
511    if (!eldbus_message_arguments_get(msg, "vb", &table, &visible))
512      {
513         ERR("Error reading message arguments");
514         return NULL;
515      }
516
517    DBG("table: '%p', visible: '%d'", table, visible);
518
519    ibus_lookup_table = _get_lookup_table_from_message_iter(table);
520    _free_lookup_table(ibus_lookup_table);
521
522    return NULL;
523 }
524
525 static Eldbus_Message *
526 _panel_show_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
527 {
528    PANEL_CHECK_MESSAGE_ERRORS(msg)
529
530    return NULL;
531 }
532
533 static Eldbus_Message *
534 _panel_hide_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
535 {
536    PANEL_CHECK_MESSAGE_ERRORS(msg)
537
538    DBG("here");
539
540    return NULL;
541 }
542
543 static Eldbus_Message *
544 _panel_cursor_up_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
545 {
546    PANEL_CHECK_MESSAGE_ERRORS(msg)
547
548    DBG("here");
549
550    return NULL;
551 }
552
553 static Eldbus_Message *
554 _panel_cursor_down_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
555 {
556    PANEL_CHECK_MESSAGE_ERRORS(msg)
557
558    return NULL;
559 }
560
561 static Eldbus_Message *
562 _panel_page_up_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
563 {
564    PANEL_CHECK_MESSAGE_ERRORS(msg)
565
566    return NULL;
567 }
568
569 static Eldbus_Message *
570 _panel_page_down_lookup_table(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
571 {
572    PANEL_CHECK_MESSAGE_ERRORS(msg)
573
574    return NULL;
575 }
576
577 static Eldbus_Message *
578 _panel_register_properties(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
579 {
580    Eldbus_Message_Iter *props = NULL;
581    Eina_Array *properties = NULL;
582
583    PANEL_CHECK_MESSAGE_ERRORS(msg)
584
585    if (!eldbus_message_arguments_get(msg, "v", &props))
586      {
587         ERR("Error reading message arguments");
588         return NULL;
589      }
590
591    DBG("properties: '%p'", props);
592
593    properties = _get_properties_from_message_iter(props);
594    _free_eina_array(properties, _free_property);
595
596    return NULL;
597 }
598
599 static Eldbus_Message *
600 _panel_update_property(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
601 {
602    Eldbus_Message_Iter *prop = NULL;
603
604    PANEL_CHECK_MESSAGE_ERRORS(msg)
605
606    if (!eldbus_message_arguments_get(msg, "v", &prop))
607      {
608         ERR("Error reading message arguments");
609         return NULL;
610      }
611
612    DBG("property : '%p'", prop);
613    DBG("Property iter signature: %s", eldbus_message_iter_signature_get(prop));
614
615    return NULL;
616 }
617
618 static Eldbus_Message *
619 _panel_focus_in(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
620 {
621    PANEL_CHECK_MESSAGE_ERRORS(msg)
622
623    return NULL;
624 }
625
626 static Eldbus_Message *
627 _panel_focus_out(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
628 {
629    PANEL_CHECK_MESSAGE_ERRORS(msg)
630
631    return NULL;
632 }
633
634 static Eldbus_Message *
635 _panel_set_cursor_location(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
636 {
637    int x = 0, y = 0, w = 0, h = 0;
638
639    PANEL_CHECK_MESSAGE_ERRORS(msg)
640
641    if (!eldbus_message_arguments_get(msg, "iiii", &x, &y, &w, &h))
642      {
643         ERR("Error reading message arguments");
644         return NULL;
645      }
646
647    DBG("x: %d, y: %d, w: %d, h: %d", x, y, w, h);
648
649    return NULL;
650 }
651
652 static Eldbus_Message *
653 _panel_reset(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
654 {
655    PANEL_CHECK_MESSAGE_ERRORS(msg)
656
657    return NULL;
658 }
659
660 static Eldbus_Message *
661 _panel_start_setup(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
662 {
663    PANEL_CHECK_MESSAGE_ERRORS(msg)
664
665    return NULL;
666 }
667
668 static Eldbus_Message *
669 _panel_state_changed(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
670 {
671    PANEL_CHECK_MESSAGE_ERRORS(msg)
672
673    return NULL;
674 }
675
676 static Eldbus_Message *
677 _panel_hide_language_bar(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
678 {
679    PANEL_CHECK_MESSAGE_ERRORS(msg)
680
681    return NULL;
682 }
683
684 static Eldbus_Message *
685 _panel_show_language_bar(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
686 {
687    PANEL_CHECK_MESSAGE_ERRORS(msg)
688
689    return NULL;
690 }
691
692 static const Eldbus_Method _wkb_ibus_panel_methods[] =
693 {
694 /* typedef struct _Eldbus_Method
695  * {
696  *    const char *member;
697  *    const Eldbus_Arg_Info *in;
698  *    const Eldbus_Arg_Info *out;
699  *    Eldbus_Method_Cb cb;
700  *    unsigned int flags;
701  * } Eldbus_Method;
702  */
703    { .member = "UpdatePreeditText",
704      .in = ELDBUS_ARGS({"v", "text"}, {"u", "cursor_pos"}, {"b", "visible"}),
705      .cb = _panel_update_preedit_text, },
706
707    { .member = "ShowPreeditText",
708      .cb = _panel_show_preedit_text, },
709
710    { .member = "HidePreeditText",
711      .cb = _panel_hide_preedit_text, },
712
713    { .member = "UpdateAuxiliaryText",
714      .in = ELDBUS_ARGS({"v", "text"}, {"b", "visible"}),
715      .cb = _panel_update_auxiliary_text, },
716
717    { .member = "ShowAuxiliaryText",
718      .cb = _panel_show_auxiliary_text, },
719
720    { .member = "HideAuxiliaryText",
721      .cb = _panel_hide_auxiliary_text, },
722
723    { .member = "UpdateLookupTable",
724      .in = ELDBUS_ARGS({"v", "table"}, {"b", "visible"}),
725      .cb = _panel_update_lookup_table, },
726
727    { .member = "ShowLookupTable",
728      .cb = _panel_show_lookup_table, },
729
730    { .member = "HideLookupTable",
731      .cb = _panel_hide_lookup_table, },
732
733    { .member = "CursorUpLookupTable",
734      .cb = _panel_cursor_up_lookup_table, },
735
736    { .member = "CursorDownLookupTable",
737      .cb = _panel_cursor_down_lookup_table, },
738
739    { .member = "PageUpLookupTable",
740      .cb = _panel_page_up_lookup_table, },
741
742    { .member = "PageDownLookupTable",
743      .cb = _panel_page_down_lookup_table, },
744
745    { .member = "RegisterProperties",
746      .in = ELDBUS_ARGS({"v", "props"}),
747      .cb = _panel_register_properties, },
748
749    { .member = "UpdateProperty",
750      .in = ELDBUS_ARGS({"v", "prop"}),
751      .cb = _panel_update_property, },
752
753    { .member = "FocusIn",
754      .in = ELDBUS_ARGS({"o", "ic"}),
755      .cb = _panel_focus_in, },
756
757    { .member = "FocusOut",
758      .in = ELDBUS_ARGS({"o", "ic"}),
759      .cb = _panel_focus_out, },
760
761    { .member = "SetCursorLocation",
762      .in = ELDBUS_ARGS({"i", "x"}, {"i", "y"}, {"i", "w"}, {"i", "h"}),
763      .cb = _panel_set_cursor_location, },
764
765    { .member = "Reset",
766      .cb = _panel_reset, },
767
768    { .member = "StartSetup",
769      .cb = _panel_start_setup, },
770
771    { .member = "StateChanged",
772      .cb = _panel_state_changed, },
773
774    { .member = "HideLanguageBar",
775      .cb = _panel_hide_language_bar, },
776
777    { .member = "ShowLanguageBar",
778      .cb = _panel_show_language_bar, },
779
780    { NULL },
781 };
782
783 static const Eldbus_Signal _wkb_ibus_panel_signals[] =
784 {
785 /* typedef struct _Eldbus_Signal
786  * {
787  *    const char *name;
788  *    const Eldbus_Arg_Info *args;
789  *    unsigned int flags;
790  * } Eldbus_Signal;
791  */
792    { .name = "CursorUp", },
793
794    { .name = "CursorDown", },
795
796    { .name = "PageUp", },
797
798    { .name = "PageDown", },
799
800    { .name = "PropertyActivate",
801      .args = ELDBUS_ARGS({"s", "prop_name"}, {"i", "prop_state"}),
802      .flags = 0, },
803
804    { .name = "PropertyShow",
805      .args = ELDBUS_ARGS({"s", "prop_name"}),
806      .flags = 0, },
807
808    { .name = "PropertyHide",
809      .args = ELDBUS_ARGS({"s", "prop_name"}),
810      .flags = 0, },
811
812    { .name = "CandidateClicked",
813      .args = ELDBUS_ARGS({"u", "index"}, {"u", "button"}, {"u", "state"}),
814      .flags = 0, },
815
816    { NULL },
817 };
818
819 static const Eldbus_Service_Interface_Desc _wkb_ibus_panel_interface =
820 {
821    .interface = IBUS_INTERFACE_PANEL,
822    .methods = _wkb_ibus_panel_methods,
823    .signals = _wkb_ibus_panel_signals,
824 };
825
826 Eldbus_Service_Interface *
827 wkb_ibus_panel_register(Eldbus_Connection *conn)
828 {
829    return eldbus_service_interface_register(conn, IBUS_PATH_PANEL, &_wkb_ibus_panel_interface);
830 }
831