1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4 * Copyright (C) 2008-2014 Peng Huang <shawn.p.huang@gmail.com>
5 * Copyright (C) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
6 * Copyright (C) 2008-2018 Red Hat, Inc.
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
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 */
23 #include "panelproxy.h"
24
25 #include "global.h"
26 #include "marshalers.h"
27 #include "types.h"
28
29 /* panelproxy.c is a very simple proxy class for the panel component that does only the following:
30 *
31 * 1. Handle D-Bus signals from the panel process. For the list of the D-Bus signals, you can check the bus_panel_proxy_g_signal function, or
32 * introspection_xml in src/ibuspanelservice.c. The bus_panel_proxy_g_signal function simply emits a corresponding glib signal for each
33 * D-Bus signal.
34 * 2. Handle glib signals for a BusPanelProxy object (which is usually emitted by bus_panel_proxy_g_signal.) The list of such glib signals is
35 * in the bus_panel_proxy_class_init function. The signal handler function, e.g. bus_panel_proxy_candidate_clicked, simply calls the
36 * corresponding function in inputcontext.c, e.g. bus_input_context_candidate_clicked, using the current focused context.
37 * 3. Provide a way to call D-Bus methods in the panel process. For the list of the D-Bus methods, you can check the header file (panelproxy.h)
38 * or introspection_xml in src/ibuspanelservice.c. Functions that calls g_dbus_proxy_call, e.g. bus_panel_proxy_set_cursor_location, would
39 * fall into this category.
40 * 4. Handle glib signals for a BusInputContext object. The list of such glib signals is in the input_context_signals[] array. The signal handler
41 * function, e.g. _context_set_cursor_location_cb, simply invokes a D-Bus method by calling a function like bus_panel_proxy_set_cursor_location.
42 */
43
44 enum {
45 PAGE_UP,
46 PAGE_DOWN,
47 CURSOR_UP,
48 CURSOR_DOWN,
49 CANDIDATE_CLICKED,
50 PROPERTY_ACTIVATE,
51 PROPERTY_SHOW,
52 PROPERTY_HIDE,
53 COMMIT_TEXT,
54 PANEL_EXTENSION,
55 PANEL_EXTENSION_REGISTER_KEYS,
56 UPDATE_PREEDIT_TEXT_RECEIVED,
57 UPDATE_LOOKUP_TABLE_RECEIVED,
58 UPDATE_AUXILIARY_TEXT_RECEIVED,
59 LAST_SIGNAL,
60 };
61
62 struct _BusPanelProxy {
63 IBusProxy parent;
64
65 /* instance members */
66 BusInputContext *focused_context;
67 PanelType panel_type;
68 };
69
70 struct _BusPanelProxyClass {
71 IBusProxyClass parent;
72 /* class members */
73
74 void (* page_up) (BusPanelProxy *panel);
75 void (* page_down) (BusPanelProxy *panel);
76 void (* cursor_up) (BusPanelProxy *panel);
77 void (* cursor_down) (BusPanelProxy *panel);
78 void (* candidate_clicked) (BusPanelProxy *panel,
79 guint index,
80 guint button,
81 guint state);
82
83 void (* property_activate) (BusPanelProxy *panel,
84 const gchar *prop_name,
85 gint prop_state);
86 void (* commit_text) (BusPanelProxy *panel,
87 IBusText *text);
88 };
89
90 static guint panel_signals[LAST_SIGNAL] = { 0 };
91
92 /* functions prototype */
93 static void bus_panel_proxy_init (BusPanelProxy *panel);
94 static void bus_panel_proxy_real_destroy (IBusProxy *proxy);
95 static void bus_panel_proxy_g_signal (GDBusProxy *proxy,
96 const gchar *sender_name,
97 const gchar *signal_name,
98 GVariant *parameters);
99 static void bus_panel_proxy_page_up (BusPanelProxy *panel);
100 static void bus_panel_proxy_page_down (BusPanelProxy *panel);
101 static void bus_panel_proxy_cursor_up (BusPanelProxy *panel);
102 static void bus_panel_proxy_cursor_down (BusPanelProxy *panel);
103 static void bus_panel_proxy_candidate_clicked
104 (BusPanelProxy *panel,
105 guint index,
106 guint button,
107 guint state);
108 static void bus_panel_proxy_property_activate
109 (BusPanelProxy *panel,
110 const gchar *prop_name,
111 gint prop_state);
112 static void bus_panel_proxy_commit_text
113 (BusPanelProxy *panel,
114 IBusText *text);
115
G_DEFINE_TYPE(BusPanelProxy,bus_panel_proxy,IBUS_TYPE_PROXY)116 G_DEFINE_TYPE(BusPanelProxy, bus_panel_proxy, IBUS_TYPE_PROXY)
117
118 BusPanelProxy *
119 bus_panel_proxy_new (BusConnection *connection,
120 PanelType panel_type)
121 {
122 const gchar *path = NULL;
123 GObject *obj;
124 BusPanelProxy *panel;
125
126 g_assert (BUS_IS_CONNECTION (connection));
127
128 switch (panel_type) {
129 case PANEL_TYPE_PANEL:
130 path = IBUS_PATH_PANEL;
131 break;
132 case PANEL_TYPE_EXTENSION_EMOJI:
133 path = IBUS_PATH_PANEL_EXTENSION_EMOJI;
134 break;
135 default:
136 g_return_val_if_reached (NULL);
137 }
138
139 obj = g_initable_new (BUS_TYPE_PANEL_PROXY,
140 NULL,
141 NULL,
142 "g-object-path", path,
143 "g-interface-name", IBUS_INTERFACE_PANEL,
144 "g-connection", bus_connection_get_dbus_connection (connection),
145 "g-default-timeout", g_gdbus_timeout,
146 "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
147 NULL);
148
149 panel = BUS_PANEL_PROXY (obj);
150 panel->panel_type = panel_type;
151 return panel;
152 }
153
154 static void
bus_panel_proxy_class_init(BusPanelProxyClass * class)155 bus_panel_proxy_class_init (BusPanelProxyClass *class)
156 {
157 IBUS_PROXY_CLASS (class)->destroy = bus_panel_proxy_real_destroy;
158 G_DBUS_PROXY_CLASS (class)->g_signal = bus_panel_proxy_g_signal;
159
160 class->page_up = bus_panel_proxy_page_up;
161 class->page_down = bus_panel_proxy_page_down;
162 class->cursor_up = bus_panel_proxy_cursor_up;
163 class->cursor_down = bus_panel_proxy_cursor_down;
164 class->candidate_clicked = bus_panel_proxy_candidate_clicked;
165 class->property_activate = bus_panel_proxy_property_activate;
166 class->commit_text = bus_panel_proxy_commit_text;
167
168 /* install signals */
169 panel_signals[PAGE_UP] =
170 g_signal_new (I_("page-up"),
171 G_TYPE_FROM_CLASS (class),
172 G_SIGNAL_RUN_LAST,
173 G_STRUCT_OFFSET(BusPanelProxyClass, page_up),
174 NULL, NULL,
175 bus_marshal_VOID__VOID,
176 G_TYPE_NONE, 0);
177
178 panel_signals[PAGE_DOWN] =
179 g_signal_new (I_("page-down"),
180 G_TYPE_FROM_CLASS (class),
181 G_SIGNAL_RUN_LAST,
182 G_STRUCT_OFFSET(BusPanelProxyClass, page_down),
183 NULL, NULL,
184 bus_marshal_VOID__VOID,
185 G_TYPE_NONE, 0);
186
187 panel_signals[CURSOR_UP] =
188 g_signal_new (I_("cursor-up"),
189 G_TYPE_FROM_CLASS (class),
190 G_SIGNAL_RUN_LAST,
191 G_STRUCT_OFFSET(BusPanelProxyClass, cursor_up),
192 NULL, NULL,
193 bus_marshal_VOID__VOID,
194 G_TYPE_NONE, 0);
195
196 panel_signals[CURSOR_DOWN] =
197 g_signal_new (I_("cursor-down"),
198 G_TYPE_FROM_CLASS (class),
199 G_SIGNAL_RUN_LAST,
200 G_STRUCT_OFFSET(BusPanelProxyClass, cursor_down),
201 NULL, NULL,
202 bus_marshal_VOID__VOID,
203 G_TYPE_NONE, 0);
204
205 panel_signals[CANDIDATE_CLICKED] =
206 g_signal_new (I_("candidate-clicked"),
207 G_TYPE_FROM_CLASS (class),
208 G_SIGNAL_RUN_LAST,
209 G_STRUCT_OFFSET(BusPanelProxyClass, candidate_clicked),
210 NULL, NULL,
211 bus_marshal_VOID__UINT_UINT_UINT,
212 G_TYPE_NONE, 3,
213 G_TYPE_UINT,
214 G_TYPE_UINT,
215 G_TYPE_UINT);
216
217 panel_signals[PROPERTY_ACTIVATE] =
218 g_signal_new (I_("property-activate"),
219 G_TYPE_FROM_CLASS (class),
220 G_SIGNAL_RUN_LAST,
221 G_STRUCT_OFFSET(BusPanelProxyClass, property_activate),
222 NULL, NULL,
223 bus_marshal_VOID__STRING_INT,
224 G_TYPE_NONE, 2,
225 G_TYPE_STRING,
226 G_TYPE_INT);
227
228 panel_signals[PROPERTY_SHOW] =
229 g_signal_new (I_("property-show"),
230 G_TYPE_FROM_CLASS (class),
231 G_SIGNAL_RUN_LAST,
232 0,
233 NULL, NULL,
234 bus_marshal_VOID__STRING,
235 G_TYPE_NONE, 1,
236 G_TYPE_STRING);
237
238 panel_signals[PROPERTY_HIDE] =
239 g_signal_new (I_("property-hide"),
240 G_TYPE_FROM_CLASS (class),
241 G_SIGNAL_RUN_LAST,
242 0,
243 NULL, NULL,
244 bus_marshal_VOID__STRING,
245 G_TYPE_NONE, 1,
246 G_TYPE_STRING);
247
248 panel_signals[COMMIT_TEXT] =
249 g_signal_new (I_("commit-text"),
250 G_TYPE_FROM_CLASS (class),
251 G_SIGNAL_RUN_LAST,
252 G_STRUCT_OFFSET(BusPanelProxyClass, commit_text),
253 NULL, NULL,
254 bus_marshal_VOID__OBJECT,
255 G_TYPE_NONE, 1,
256 IBUS_TYPE_TEXT);
257
258 panel_signals[PANEL_EXTENSION] =
259 g_signal_new (I_("panel-extension"),
260 G_TYPE_FROM_CLASS (class),
261 G_SIGNAL_RUN_LAST,
262 0,
263 NULL, NULL,
264 bus_marshal_VOID__OBJECT,
265 G_TYPE_NONE, 1,
266 IBUS_TYPE_EXTENSION_EVENT);
267
268 panel_signals[PANEL_EXTENSION_REGISTER_KEYS] =
269 g_signal_new (I_("panel-extension-register-keys"),
270 G_TYPE_FROM_CLASS (class),
271 G_SIGNAL_RUN_LAST,
272 0,
273 NULL, NULL,
274 bus_marshal_VOID__VARIANT,
275 G_TYPE_NONE, 1,
276 G_TYPE_VARIANT);
277
278 panel_signals[UPDATE_PREEDIT_TEXT_RECEIVED] =
279 g_signal_new (I_("update-preedit-text-received"),
280 G_TYPE_FROM_CLASS (class),
281 G_SIGNAL_RUN_LAST,
282 0,
283 NULL, NULL,
284 bus_marshal_VOID__OBJECT_UINT_BOOLEAN,
285 G_TYPE_NONE, 3,
286 IBUS_TYPE_TEXT,
287 G_TYPE_UINT,
288 G_TYPE_BOOLEAN);
289
290 panel_signals[UPDATE_LOOKUP_TABLE_RECEIVED] =
291 g_signal_new (I_("update-lookup-table-received"),
292 G_TYPE_FROM_CLASS (class),
293 G_SIGNAL_RUN_LAST,
294 0,
295 NULL, NULL,
296 bus_marshal_VOID__OBJECT_BOOLEAN,
297 G_TYPE_NONE, 2,
298 IBUS_TYPE_LOOKUP_TABLE,
299 G_TYPE_BOOLEAN);
300
301 panel_signals[UPDATE_AUXILIARY_TEXT_RECEIVED] =
302 g_signal_new (I_("update-auxiliary-text-received"),
303 G_TYPE_FROM_CLASS (class),
304 G_SIGNAL_RUN_LAST,
305 0,
306 NULL, NULL,
307 bus_marshal_VOID__OBJECT_BOOLEAN,
308 G_TYPE_NONE, 2,
309 IBUS_TYPE_TEXT,
310 G_TYPE_BOOLEAN);
311 }
312
313 static void
_g_object_unref_if_floating(gpointer instance)314 _g_object_unref_if_floating (gpointer instance)
315 {
316 if (g_object_is_floating (instance))
317 g_object_unref (instance);
318 }
319
320 static void
bus_panel_proxy_init(BusPanelProxy * panel)321 bus_panel_proxy_init (BusPanelProxy *panel)
322 {
323 /* member variables will automatically be zero-cleared. */
324 }
325
326 static void
bus_panel_proxy_real_destroy(IBusProxy * proxy)327 bus_panel_proxy_real_destroy (IBusProxy *proxy)
328 {
329 BusPanelProxy *panel = (BusPanelProxy *)proxy;
330
331 if (panel->focused_context) {
332 bus_panel_proxy_focus_out (panel, panel->focused_context);
333 panel->focused_context = NULL;
334 }
335
336 IBUS_PROXY_CLASS(bus_panel_proxy_parent_class)->
337 destroy ((IBusProxy *)panel);
338 }
339
340 /**
341 * bus_panel_proxy_g_signal:
342 *
343 * Handle all D-Bus signals from the panel process. This function emits a corresponding glib signal for each D-Bus signal.
344 */
345 static void
bus_panel_proxy_g_signal(GDBusProxy * proxy,const gchar * sender_name,const gchar * signal_name,GVariant * parameters)346 bus_panel_proxy_g_signal (GDBusProxy *proxy,
347 const gchar *sender_name,
348 const gchar *signal_name,
349 GVariant *parameters)
350 {
351 BusPanelProxy *panel = (BusPanelProxy *)proxy;
352
353 /* The list of nullary D-Bus signals. */
354 static const struct {
355 const gchar *signal_name;
356 const guint signal_id;
357 } signals [] = {
358 { "PageUp", PAGE_UP },
359 { "PageDown", PAGE_DOWN },
360 { "CursorUp", CURSOR_UP },
361 { "CursorDown", CURSOR_DOWN },
362 };
363
364 gint i;
365 for (i = 0; i < G_N_ELEMENTS (signals); i++) {
366 if (g_strcmp0 (signal_name, signals[i].signal_name) == 0) {
367 g_signal_emit (panel, panel_signals[signals[i].signal_id], 0);
368 return;
369 }
370 }
371
372 /* Handle D-Bus signals with parameters. Deserialize them and emit a glib signal. */
373 if (g_strcmp0 ("CandidateClicked", signal_name) == 0) {
374 guint index = 0;
375 guint button = 0;
376 guint state = 0;
377 g_variant_get (parameters, "(uuu)", &index, &button, &state);
378 g_signal_emit (panel, panel_signals[CANDIDATE_CLICKED], 0, index, button, state);
379 return;
380 }
381
382 if (g_strcmp0 ("PropertyActivate", signal_name) == 0) {
383 gchar *prop_name = NULL;
384 gint prop_state = 0;
385 g_variant_get (parameters, "(&su)", &prop_name, &prop_state);
386 g_signal_emit (panel, panel_signals[PROPERTY_ACTIVATE], 0, prop_name, prop_state);
387 return;
388 }
389
390 if (g_strcmp0 ("PropertyShow", signal_name) == 0) {
391 gchar *prop_name = NULL;
392 g_variant_get (parameters, "(&s)", &prop_name);
393 g_signal_emit (panel, panel_signals[PROPERTY_SHOW], 0, prop_name);
394 return;
395 }
396
397 if (g_strcmp0 ("PropertyHide", signal_name) == 0) {
398 gchar *prop_name = NULL;
399 g_variant_get (parameters, "(&s)", &prop_name);
400 g_signal_emit (panel, panel_signals[PROPERTY_HIDE], 0, prop_name);
401 return;
402 }
403
404 if (g_strcmp0 ("CommitText", signal_name) == 0) {
405 GVariant *arg0 = NULL;
406
407 g_variant_get (parameters, "(v)", &arg0);
408 g_return_if_fail (arg0);
409 IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0));
410 g_variant_unref (arg0);
411 g_return_if_fail (text);
412 g_signal_emit (panel, panel_signals[COMMIT_TEXT], 0, text);
413 _g_object_unref_if_floating (text);
414 return;
415 }
416
417 if (g_strcmp0 ("PanelExtension", signal_name) == 0) {
418 GVariant *arg0 = NULL;
419
420 g_variant_get (parameters, "(v)", &arg0);
421 g_return_if_fail (arg0);
422 IBusExtensionEvent *event = IBUS_EXTENSION_EVENT (
423 ibus_serializable_deserialize (arg0));
424 g_variant_unref (arg0);
425 g_return_if_fail (event);
426 g_signal_emit (panel, panel_signals[PANEL_EXTENSION], 0, event);
427 _g_object_unref_if_floating (event);
428 return;
429 }
430
431 if (g_strcmp0 ("PanelExtensionRegisterKeys", signal_name) == 0) {
432 g_signal_emit (panel, panel_signals[PANEL_EXTENSION_REGISTER_KEYS], 0,
433 parameters);
434 return;
435 }
436
437 if (g_strcmp0 ("UpdatePreeditTextReceived", signal_name) == 0) {
438 GVariant *variant = NULL;
439 guint cursor_pos = 0;
440 gboolean visible = FALSE;
441 IBusText *text = NULL;
442
443 g_variant_get (parameters, "(vub)", &variant, &cursor_pos, &visible);
444 g_return_if_fail (variant);
445 text = (IBusText *) ibus_serializable_deserialize (variant);
446 g_variant_unref (variant);
447 g_return_if_fail (text);
448 g_signal_emit (panel, panel_signals[UPDATE_PREEDIT_TEXT_RECEIVED], 0,
449 text, cursor_pos, visible);
450 _g_object_unref_if_floating (text);
451 return;
452 }
453
454 if (g_strcmp0 ("UpdateLookupTableReceived", signal_name) == 0) {
455 GVariant *variant = NULL;
456 gboolean visible = FALSE;
457 IBusLookupTable *table = NULL;
458
459 g_variant_get (parameters, "(vb)", &variant, &visible);
460 g_return_if_fail (variant);
461 table = (IBusLookupTable *) ibus_serializable_deserialize (variant);
462 g_variant_unref (variant);
463 g_return_if_fail (table);
464 g_signal_emit (panel, panel_signals[UPDATE_LOOKUP_TABLE_RECEIVED], 0,
465 table, visible);
466 _g_object_unref_if_floating (table);
467 return;
468 }
469
470 if (g_strcmp0 ("UpdateAuxiliaryTextReceived", signal_name) == 0) {
471 GVariant *variant = NULL;
472 gboolean visible = FALSE;
473 IBusText *text = NULL;
474
475 g_variant_get (parameters, "(vb)", &variant, &visible);
476 g_return_if_fail (variant);
477 text = (IBusText *) ibus_serializable_deserialize (variant);
478 g_variant_unref (variant);
479 g_return_if_fail (text);
480 g_signal_emit (panel, panel_signals[UPDATE_AUXILIARY_TEXT_RECEIVED], 0,
481 text, visible);
482 _g_object_unref_if_floating (text);
483 return;
484 }
485
486 /* shound not be reached */
487 g_return_if_reached ();
488 }
489
490
491 void
bus_panel_proxy_set_cursor_location(BusPanelProxy * panel,gint x,gint y,gint w,gint h)492 bus_panel_proxy_set_cursor_location (BusPanelProxy *panel,
493 gint x,
494 gint y,
495 gint w,
496 gint h)
497 {
498 g_assert (BUS_IS_PANEL_PROXY (panel));
499 g_dbus_proxy_call ((GDBusProxy *)panel,
500 "SetCursorLocation",
501 g_variant_new ("(iiii)", x, y, w, h),
502 G_DBUS_CALL_FLAGS_NONE,
503 -1, NULL, NULL, NULL);
504 }
505
506 void
bus_panel_proxy_set_cursor_location_relative(BusPanelProxy * panel,gint x,gint y,gint w,gint h)507 bus_panel_proxy_set_cursor_location_relative (BusPanelProxy *panel,
508 gint x,
509 gint y,
510 gint w,
511 gint h)
512 {
513 g_assert (BUS_IS_PANEL_PROXY (panel));
514 g_dbus_proxy_call ((GDBusProxy *)panel,
515 "SetCursorLocationRelative",
516 g_variant_new ("(iiii)", x, y, w, h),
517 G_DBUS_CALL_FLAGS_NONE,
518 -1, NULL, NULL, NULL);
519 }
520
521 void
bus_panel_proxy_update_preedit_text(BusPanelProxy * panel,IBusText * text,guint cursor_pos,gboolean visible)522 bus_panel_proxy_update_preedit_text (BusPanelProxy *panel,
523 IBusText *text,
524 guint cursor_pos,
525 gboolean visible)
526 {
527 g_assert (BUS_IS_PANEL_PROXY (panel));
528 g_assert (IBUS_IS_TEXT (text));
529
530 GVariant *variant = ibus_serializable_serialize ((IBusSerializable* )text);
531 g_dbus_proxy_call ((GDBusProxy *)panel,
532 "UpdatePreeditText",
533 g_variant_new ("(vub)", variant, cursor_pos, visible),
534 G_DBUS_CALL_FLAGS_NONE,
535 -1, NULL, NULL, NULL);
536 }
537
538 void
bus_panel_proxy_update_auxiliary_text(BusPanelProxy * panel,IBusText * text,gboolean visible)539 bus_panel_proxy_update_auxiliary_text (BusPanelProxy *panel,
540 IBusText *text,
541 gboolean visible)
542 {
543 g_assert (BUS_IS_PANEL_PROXY (panel));
544 g_assert (IBUS_IS_TEXT (text));
545
546 GVariant *variant = ibus_serializable_serialize ((IBusSerializable* )text);
547 g_dbus_proxy_call ((GDBusProxy *)panel,
548 "UpdateAuxiliaryText",
549 g_variant_new ("(vb)", variant, visible),
550 G_DBUS_CALL_FLAGS_NONE,
551 -1, NULL, NULL, NULL);
552 }
553
554 void
bus_panel_proxy_update_lookup_table(BusPanelProxy * panel,IBusLookupTable * table,gboolean visible)555 bus_panel_proxy_update_lookup_table (BusPanelProxy *panel,
556 IBusLookupTable *table,
557 gboolean visible)
558 {
559 g_assert (BUS_IS_PANEL_PROXY (panel));
560 g_assert (IBUS_IS_LOOKUP_TABLE (table));
561
562 GVariant *variant = ibus_serializable_serialize ((IBusSerializable* )table);
563 g_dbus_proxy_call ((GDBusProxy *)panel,
564 "UpdateLookupTable",
565 g_variant_new ("(vb)", variant, visible),
566 G_DBUS_CALL_FLAGS_NONE,
567 -1, NULL, NULL, NULL);
568 }
569
570 void
bus_panel_proxy_register_properties(BusPanelProxy * panel,IBusPropList * prop_list)571 bus_panel_proxy_register_properties (BusPanelProxy *panel,
572 IBusPropList *prop_list)
573 {
574 g_assert (BUS_IS_PANEL_PROXY (panel));
575 g_assert (IBUS_IS_PROP_LIST (prop_list));
576
577 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop_list);
578 g_dbus_proxy_call ((GDBusProxy *)panel,
579 "RegisterProperties",
580 g_variant_new ("(v)", variant),
581 G_DBUS_CALL_FLAGS_NONE,
582 -1, NULL, NULL, NULL);
583 }
584
585 void
bus_panel_proxy_update_property(BusPanelProxy * panel,IBusProperty * prop)586 bus_panel_proxy_update_property (BusPanelProxy *panel,
587 IBusProperty *prop)
588 {
589 g_assert (BUS_IS_PANEL_PROXY (panel));
590 g_assert (IBUS_IS_PROPERTY (prop));
591
592 GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop);
593 g_dbus_proxy_call ((GDBusProxy *)panel,
594 "UpdateProperty",
595 g_variant_new ("(v)", variant),
596 G_DBUS_CALL_FLAGS_NONE,
597 -1, NULL, NULL, NULL);
598 }
599
600 void
bus_panel_proxy_set_content_type(BusPanelProxy * panel,guint purpose,guint hints)601 bus_panel_proxy_set_content_type (BusPanelProxy *panel,
602 guint purpose,
603 guint hints)
604 {
605 g_assert (BUS_IS_PANEL_PROXY (panel));
606
607 g_dbus_proxy_call ((GDBusProxy *)panel,
608 "ContentType",
609 g_variant_new ("(uu)", purpose, hints),
610 G_DBUS_CALL_FLAGS_NONE,
611 -1, NULL, NULL, NULL);
612 }
613
614 #define DEFINE_FUNC(name) \
615 static void \
616 bus_panel_proxy_##name (BusPanelProxy *panel) \
617 { \
618 g_assert (BUS_IS_PANEL_PROXY (panel)); \
619 \
620 if (panel->focused_context) { \
621 bus_input_context_##name (panel->focused_context); \
622 } \
623 }
624
625 DEFINE_FUNC(page_up)
DEFINE_FUNC(page_down)626 DEFINE_FUNC(page_down)
627 DEFINE_FUNC(cursor_up)
628 DEFINE_FUNC(cursor_down)
629 #undef DEFINE_FUNC
630
631 static void
632 bus_panel_proxy_candidate_clicked (BusPanelProxy *panel,
633 guint index,
634 guint button,
635 guint state)
636 {
637 g_assert (BUS_IS_PANEL_PROXY (panel));
638
639 if (panel->focused_context) {
640 bus_input_context_candidate_clicked (panel->focused_context,
641 index,
642 button,
643 state);
644 }
645 }
646
647 static void
bus_panel_proxy_property_activate(BusPanelProxy * panel,const gchar * prop_name,gint prop_state)648 bus_panel_proxy_property_activate (BusPanelProxy *panel,
649 const gchar *prop_name,
650 gint prop_state)
651 {
652 g_assert (BUS_IS_PANEL_PROXY (panel));
653
654 if (panel->focused_context) {
655 bus_input_context_property_activate (panel->focused_context, prop_name, prop_state);
656 }
657 }
658
659 static void
bus_panel_proxy_commit_text(BusPanelProxy * panel,IBusText * text)660 bus_panel_proxy_commit_text (BusPanelProxy *panel,
661 IBusText *text)
662 {
663 gboolean use_extension = TRUE;
664 g_assert (BUS_IS_PANEL_PROXY (panel));
665 g_assert (text != NULL);
666
667 if (!panel->focused_context)
668 return;
669 if (panel->panel_type != PANEL_TYPE_PANEL)
670 use_extension = FALSE;
671 bus_input_context_commit_text_use_extension (panel->focused_context,
672 text,
673 use_extension);
674 }
675
676 #define DEFINE_FUNCTION(Name, name) \
677 void bus_panel_proxy_##name (BusPanelProxy *panel) \
678 { \
679 g_assert (BUS_IS_PANEL_PROXY (panel)); \
680 g_dbus_proxy_call ((GDBusProxy *) panel, \
681 #Name, \
682 NULL, \
683 G_DBUS_CALL_FLAGS_NONE, \
684 -1, NULL, NULL, NULL); \
685 }
686
DEFINE_FUNCTION(ShowPreeditText,show_preedit_text)687 DEFINE_FUNCTION (ShowPreeditText, show_preedit_text)
688 DEFINE_FUNCTION (HidePreeditText, hide_preedit_text)
689 DEFINE_FUNCTION (ShowAuxiliaryText, show_auxiliary_text)
690 DEFINE_FUNCTION (HideAuxiliaryText, hide_auxiliary_text)
691 DEFINE_FUNCTION (ShowLookupTable, show_lookup_table)
692 DEFINE_FUNCTION (HideLookupTable, hide_lookup_table)
693 DEFINE_FUNCTION (PageUpLookupTable, page_up_lookup_table)
694 DEFINE_FUNCTION (PageDownLookupTable, page_down_lookup_table)
695 DEFINE_FUNCTION (CursorUpLookupTable, cursor_up_lookup_table)
696 DEFINE_FUNCTION (CursorDownLookupTable, cursor_down_lookup_table)
697 DEFINE_FUNCTION (StateChanged, state_changed)
698
699 #undef DEFINE_FUNCTION
700
701 static void
702 _context_set_cursor_location_cb (BusInputContext *context,
703 gint x,
704 gint y,
705 gint w,
706 gint h,
707 BusPanelProxy *panel)
708 {
709 g_assert (BUS_IS_INPUT_CONTEXT (context));
710 g_assert (BUS_IS_PANEL_PROXY (panel));
711
712 g_return_if_fail (panel->focused_context == context);
713
714 bus_panel_proxy_set_cursor_location (panel, x, y, w, h);
715 }
716
717 static void
_context_set_cursor_location_relative_cb(BusInputContext * context,gint x,gint y,gint w,gint h,BusPanelProxy * panel)718 _context_set_cursor_location_relative_cb (BusInputContext *context,
719 gint x,
720 gint y,
721 gint w,
722 gint h,
723 BusPanelProxy *panel)
724 {
725 g_assert (BUS_IS_INPUT_CONTEXT (context));
726 g_assert (BUS_IS_PANEL_PROXY (panel));
727
728 g_return_if_fail (panel->focused_context == context);
729
730 bus_panel_proxy_set_cursor_location_relative (panel, x, y, w, h);
731 }
732
733 static void
_context_update_preedit_text_cb(BusInputContext * context,IBusText * text,guint cursor_pos,gboolean visible,BusPanelProxy * panel)734 _context_update_preedit_text_cb (BusInputContext *context,
735 IBusText *text,
736 guint cursor_pos,
737 gboolean visible,
738 BusPanelProxy *panel)
739 {
740 g_assert (BUS_IS_INPUT_CONTEXT (context));
741 g_assert (text != NULL);
742 g_assert (BUS_IS_PANEL_PROXY (panel));
743
744 g_return_if_fail (panel->focused_context == context);
745
746 /* The callback is called with X11 applications but
747 * the callback is not called for extensions and panel
748 * extensions are always calls by
749 * bus_panel_proxy_update_preedit_text() directly
750 * because panel extensions forward UpdatePreeditText to
751 * UpdatePreeditTextReceived and it can be an infinite
752 * loop.
753 */
754 if (panel->panel_type != PANEL_TYPE_PANEL)
755 return;
756 bus_panel_proxy_update_preedit_text (panel,
757 text,
758 cursor_pos,
759 visible);
760 }
761
762 static void
_context_update_auxiliary_text_cb(BusInputContext * context,IBusText * text,gboolean visible,BusPanelProxy * panel)763 _context_update_auxiliary_text_cb (BusInputContext *context,
764 IBusText *text,
765 gboolean visible,
766 BusPanelProxy *panel)
767 {
768 g_assert (BUS_IS_INPUT_CONTEXT (context));
769 g_assert (BUS_IS_PANEL_PROXY (panel));
770
771 g_return_if_fail (panel->focused_context == context);
772
773 bus_panel_proxy_update_auxiliary_text (panel,
774 text,
775 visible);
776 }
777
778 static void
_context_update_lookup_table_cb(BusInputContext * context,IBusLookupTable * table,gboolean visible,BusPanelProxy * panel)779 _context_update_lookup_table_cb (BusInputContext *context,
780 IBusLookupTable *table,
781 gboolean visible,
782 BusPanelProxy *panel)
783 {
784 g_assert (BUS_IS_INPUT_CONTEXT (context));
785 g_assert (BUS_IS_PANEL_PROXY (panel));
786
787 g_return_if_fail (panel->focused_context == context);
788
789 bus_panel_proxy_update_lookup_table (panel,
790 table,
791 visible);
792 }
793
794 static void
_context_register_properties_cb(BusInputContext * context,IBusPropList * prop_list,BusPanelProxy * panel)795 _context_register_properties_cb (BusInputContext *context,
796 IBusPropList *prop_list,
797 BusPanelProxy *panel)
798 {
799 g_assert (BUS_IS_INPUT_CONTEXT (context));
800 g_assert (BUS_IS_PANEL_PROXY (panel));
801
802 g_return_if_fail (panel->focused_context == context);
803
804 bus_panel_proxy_register_properties (panel,
805 prop_list);
806 }
807
808 static void
_context_update_property_cb(BusInputContext * context,IBusProperty * prop,BusPanelProxy * panel)809 _context_update_property_cb (BusInputContext *context,
810 IBusProperty *prop,
811 BusPanelProxy *panel)
812 {
813 g_assert (BUS_IS_INPUT_CONTEXT (context));
814 g_assert (BUS_IS_PANEL_PROXY (panel));
815
816 g_return_if_fail (panel->focused_context == context);
817
818 bus_panel_proxy_update_property (panel,
819 prop);
820 }
821
822 static void
_context_destroy_cb(BusInputContext * context,BusPanelProxy * panel)823 _context_destroy_cb (BusInputContext *context,
824 BusPanelProxy *panel)
825 {
826 g_assert (BUS_IS_INPUT_CONTEXT (context));
827 g_assert (BUS_IS_PANEL_PROXY (panel));
828
829 g_assert (context == panel->focused_context);
830
831 bus_panel_proxy_focus_out (panel, context);
832 }
833
834 static void
_context_set_content_type_cb(BusInputContext * context,guint purpose,guint hints,BusPanelProxy * panel)835 _context_set_content_type_cb (BusInputContext *context,
836 guint purpose,
837 guint hints,
838 BusPanelProxy *panel)
839 {
840 g_assert (BUS_IS_INPUT_CONTEXT (context));
841 g_assert (BUS_IS_PANEL_PROXY (panel));
842
843 g_return_if_fail (panel->focused_context == context);
844
845 bus_panel_proxy_set_content_type (panel, purpose, hints);
846 }
847
848 #define DEFINE_FUNCTION(name) \
849 static void _context_##name##_cb (BusInputContext *context, \
850 BusPanelProxy *panel) \
851 { \
852 g_assert (BUS_IS_INPUT_CONTEXT (context)); \
853 g_assert (BUS_IS_PANEL_PROXY (panel)); \
854 \
855 g_return_if_fail (panel->focused_context == context); \
856 \
857 bus_panel_proxy_##name (panel); \
858 }
859
860 #define DEFINE_FUNCTION_NO_EXTENSION(name) \
861 static void _context_##name##_cb (BusInputContext *context, \
862 BusPanelProxy *panel) \
863 { \
864 g_assert (BUS_IS_INPUT_CONTEXT (context)); \
865 g_assert (BUS_IS_PANEL_PROXY (panel)); \
866 \
867 g_return_if_fail (panel->focused_context == context); \
868 \
869 /* The callback is called with X11 applications but \
870 * the callback is not called for extensions and panel \
871 * extensions are always calls by \
872 * bus_panel_proxy_update_preedit_text() directly \
873 * because panel extensions forward UpdatePreeditText to \
874 * UpdatePreeditTextReceived and it can be an infinite \
875 * loop. \
876 */ \
877 if (panel->panel_type != PANEL_TYPE_PANEL) \
878 return; \
879 bus_panel_proxy_##name (panel); \
880 }
881
882
883 DEFINE_FUNCTION_NO_EXTENSION (show_preedit_text)
884 DEFINE_FUNCTION_NO_EXTENSION (hide_preedit_text)
885 DEFINE_FUNCTION (show_auxiliary_text)
886 DEFINE_FUNCTION (hide_auxiliary_text)
887 DEFINE_FUNCTION (show_lookup_table)
888 DEFINE_FUNCTION (hide_lookup_table)
889 DEFINE_FUNCTION (page_up_lookup_table)
890 DEFINE_FUNCTION (page_down_lookup_table)
891 DEFINE_FUNCTION (cursor_up_lookup_table)
892 DEFINE_FUNCTION (cursor_down_lookup_table)
893 DEFINE_FUNCTION (state_changed)
894
895 #undef DEFINE_FUNCTION
896 #undef DEFINE_FUNCTION_NO_EXTENSION
897
898 static const struct {
899 gchar *name;
900 GCallback callback;
901 } input_context_signals[] = {
902 { "set-cursor-location", G_CALLBACK (_context_set_cursor_location_cb) },
903 { "set-cursor-location-relative", G_CALLBACK (_context_set_cursor_location_relative_cb) },
904
905 { "update-preedit-text", G_CALLBACK (_context_update_preedit_text_cb) },
906 { "show-preedit-text", G_CALLBACK (_context_show_preedit_text_cb) },
907 { "hide-preedit-text", G_CALLBACK (_context_hide_preedit_text_cb) },
908
909 { "update-auxiliary-text", G_CALLBACK (_context_update_auxiliary_text_cb) },
910 { "show-auxiliary-text", G_CALLBACK (_context_show_auxiliary_text_cb) },
911 { "hide-auxiliary-text", G_CALLBACK (_context_hide_auxiliary_text_cb) },
912
913 { "update-lookup-table", G_CALLBACK (_context_update_lookup_table_cb) },
914 { "show-lookup-table", G_CALLBACK (_context_show_lookup_table_cb) },
915 { "hide-lookup-table", G_CALLBACK (_context_hide_lookup_table_cb) },
916 { "page-up-lookup-table", G_CALLBACK (_context_page_up_lookup_table_cb) },
917 { "page-down-lookup-table", G_CALLBACK (_context_page_down_lookup_table_cb) },
918 { "cursor-up-lookup-table", G_CALLBACK (_context_cursor_up_lookup_table_cb) },
919 { "cursor-down-lookup-table", G_CALLBACK (_context_cursor_down_lookup_table_cb) },
920
921 { "register-properties", G_CALLBACK (_context_register_properties_cb) },
922 { "update-property", G_CALLBACK (_context_update_property_cb) },
923
924 { "engine-changed", G_CALLBACK (_context_state_changed_cb) },
925
926 { "destroy", G_CALLBACK (_context_destroy_cb) },
927
928 { "set-content-type", G_CALLBACK (_context_set_content_type_cb) },
929 };
930
931 void
bus_panel_proxy_focus_in(BusPanelProxy * panel,BusInputContext * context)932 bus_panel_proxy_focus_in (BusPanelProxy *panel,
933 BusInputContext *context)
934 {
935 const gchar *path;
936 guint purpose, hints;
937 gint i;
938
939 g_assert (BUS_IS_PANEL_PROXY (panel));
940 g_assert (BUS_IS_INPUT_CONTEXT (context));
941
942 if (panel->focused_context == context)
943 return;
944
945 if (panel->focused_context != NULL)
946 bus_panel_proxy_focus_out (panel, panel->focused_context);
947
948 g_object_ref_sink (context);
949 panel->focused_context = context;
950
951 path = ibus_service_get_object_path ((IBusService *)context);
952
953 g_dbus_proxy_call ((GDBusProxy *)panel,
954 "FocusIn",
955 g_variant_new ("(o)", path),
956 G_DBUS_CALL_FLAGS_NONE,
957 -1, NULL, NULL, NULL);
958
959 /* install signal handlers */
960 for (i = 0; i < G_N_ELEMENTS (input_context_signals); i++) {
961 g_signal_connect (context,
962 input_context_signals[i].name,
963 input_context_signals[i].callback,
964 panel);
965 }
966
967 bus_input_context_get_content_type (context, &purpose, &hints);
968 bus_panel_proxy_set_content_type (panel, purpose, hints);
969 }
970
971 void
bus_panel_proxy_focus_out(BusPanelProxy * panel,BusInputContext * context)972 bus_panel_proxy_focus_out (BusPanelProxy *panel,
973 BusInputContext *context)
974 {
975 g_assert (BUS_IS_PANEL_PROXY (panel));
976 g_assert (BUS_IS_INPUT_CONTEXT (context));
977
978 g_assert (panel->focused_context == context);
979
980 /* uninstall signal handlers */
981 gint i;
982 for (i = 0; i < G_N_ELEMENTS (input_context_signals); i++) {
983 g_signal_handlers_disconnect_by_func (context,
984 input_context_signals[i].callback,
985 panel);
986 }
987
988 const gchar *path = ibus_service_get_object_path ((IBusService *)context);
989
990 g_dbus_proxy_call ((GDBusProxy *)panel,
991 "FocusOut",
992 g_variant_new ("(o)", path),
993 G_DBUS_CALL_FLAGS_NONE,
994 -1, NULL, NULL, NULL);
995
996 g_object_unref (panel->focused_context);
997 panel->focused_context = NULL;
998 }
999
1000 void
bus_panel_proxy_destroy_context(BusPanelProxy * panel,BusInputContext * context)1001 bus_panel_proxy_destroy_context (BusPanelProxy *panel,
1002 BusInputContext *context)
1003 {
1004 const gchar *path;
1005
1006 g_assert (BUS_IS_PANEL_PROXY (panel));
1007 g_assert (BUS_IS_INPUT_CONTEXT (context));
1008
1009 g_object_ref_sink (context);
1010 path = ibus_service_get_object_path ((IBusService *)context);
1011
1012 g_dbus_proxy_call ((GDBusProxy *)panel,
1013 "DestroyContext",
1014 g_variant_new ("(o)", path),
1015 G_DBUS_CALL_FLAGS_NONE,
1016 -1, NULL, NULL, NULL);
1017
1018 g_object_unref (context);
1019 }
1020
1021 PanelType
bus_panel_proxy_get_panel_type(BusPanelProxy * panel)1022 bus_panel_proxy_get_panel_type (BusPanelProxy *panel)
1023 {
1024 g_assert (BUS_IS_PANEL_PROXY (panel));
1025 return panel->panel_type;
1026 }
1027
1028 void
bus_panel_proxy_panel_extension_received(BusPanelProxy * panel,IBusExtensionEvent * event)1029 bus_panel_proxy_panel_extension_received (BusPanelProxy *panel,
1030 IBusExtensionEvent *event)
1031 {
1032 GVariant *data;
1033
1034 g_assert (BUS_IS_PANEL_PROXY (panel));
1035 g_assert (event);
1036
1037 data = ibus_serializable_serialize (IBUS_SERIALIZABLE (event));
1038 g_return_if_fail (data);
1039 g_dbus_proxy_call ((GDBusProxy *)panel,
1040 "PanelExtensionReceived",
1041 g_variant_new ("(v)", data),
1042 G_DBUS_CALL_FLAGS_NONE,
1043 -1, NULL, NULL, NULL);
1044 }
1045
1046 void
bus_panel_proxy_process_key_event(BusPanelProxy * panel,guint keyval,guint keycode,guint state,GAsyncReadyCallback callback,gpointer user_data)1047 bus_panel_proxy_process_key_event (BusPanelProxy *panel,
1048 guint keyval,
1049 guint keycode,
1050 guint state,
1051 GAsyncReadyCallback callback,
1052 gpointer user_data)
1053 {
1054 g_assert (BUS_IS_PANEL_PROXY (panel));
1055
1056 g_dbus_proxy_call ((GDBusProxy *)panel,
1057 "ProcessKeyEvent",
1058 g_variant_new ("(uuu)", keyval, keycode, state),
1059 G_DBUS_CALL_FLAGS_NONE,
1060 -1,
1061 NULL,
1062 callback,
1063 user_data);
1064 }
1065
1066 void
bus_panel_proxy_commit_text_received(BusPanelProxy * panel,IBusText * text)1067 bus_panel_proxy_commit_text_received (BusPanelProxy *panel,
1068 IBusText *text)
1069 {
1070 GVariant *variant;
1071
1072 g_assert (BUS_IS_PANEL_PROXY (panel));
1073 g_assert (IBUS_IS_TEXT (text));
1074
1075 variant = ibus_serializable_serialize (IBUS_SERIALIZABLE (text));
1076 g_dbus_proxy_call ((GDBusProxy *)panel,
1077 "CommitTextReceived",
1078 g_variant_new ("(v)", variant),
1079 G_DBUS_CALL_FLAGS_NONE,
1080 -1, NULL, NULL, NULL);
1081 }
1082
1083 void
bus_panel_proxy_candidate_clicked_lookup_table(BusPanelProxy * panel,guint index,guint button,guint state)1084 bus_panel_proxy_candidate_clicked_lookup_table (BusPanelProxy *panel,
1085 guint index,
1086 guint button,
1087 guint state)
1088 {
1089 g_assert (BUS_IS_PANEL_PROXY (panel));
1090
1091 g_dbus_proxy_call ((GDBusProxy *)panel,
1092 "CandidateClickedLookupTable",
1093 g_variant_new ("(uuu)", index, button, state),
1094 G_DBUS_CALL_FLAGS_NONE,
1095 -1, NULL, NULL, NULL);
1096 }
1097