1 /*
2 SPDX-FileCopyrightText: 2011-2012 Ni Hui <shuizhuyuanluo@126.com>
3 SPDX-FileCopyrightText: 2013-2014 Weng Xuetian <wengxt@gmail.com>
4
5 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
6 */
7
8 #include "panel.h"
9 #include "app.h"
10 #include "enginemanager.h"
11 #include "gtkaccelparse_p.h"
12 #include "propertymanager.h"
13 #include "xkblayoutmanager.h"
14 #include <QByteArray>
15 #include <QDebug>
16 #include <QPair>
17 #include <QStringList>
18 #include <locale.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <string>
22
23 #ifndef DBUS_ERROR_FAILED
24 #define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed"
25 #endif /* DBUS_ERROR_FAILED */
26
27 #define IBUS_SCHEMA_GENERAL "org.freedesktop.ibus.general"
28 #define IBUS_SCHEMA_HOTKEY "org.freedesktop.ibus.general.hotkey"
29 #define IBUS_SCHEMA_PANEL "org.freedesktop.ibus.panel"
30
31 typedef struct _IBusPanelImpanelClass IBusPanelImpanelClass;
32
33 struct _IBusPanelImpanel {
34 IBusPanelService parent;
35 IBusBus *bus;
36 GDBusConnection *conn;
37 PropertyManager *propManager;
38 EngineManager *engineManager;
39 XkbLayoutManager *xkbLayoutManager;
40 App *app;
41 gboolean useSystemKeyboardLayout;
42 int selected;
43 GSettings *settings_general;
44 GSettings *settings_hotkey;
45 };
46
47 struct _IBusPanelImpanelClass {
48 IBusPanelServiceClass parent;
49 };
50
51 /* functions prototype */
52 static void ibus_panel_impanel_class_init(IBusPanelImpanelClass *klass);
53 static void ibus_panel_impanel_init(IBusPanelImpanel *impanel);
54 static void ibus_panel_impanel_destroy(IBusPanelImpanel *impanel);
55
56 static void ibus_panel_impanel_focus_in(IBusPanelService *panel, const gchar *input_context_path);
57 static void ibus_panel_impanel_focus_out(IBusPanelService *panel, const gchar *input_context_path);
58 static void ibus_panel_impanel_register_properties(IBusPanelService *panel, IBusPropList *prop_list);
59 static void ibus_panel_impanel_real_register_properties(IBusPanelImpanel *impanel);
60 static void ibus_panel_impanel_set_cursor_location(IBusPanelService *panel, gint x, gint y, gint w, gint h);
61 static void ibus_panel_impanel_update_auxiliary_text(IBusPanelService *panel, IBusText *text, gboolean visible);
62 static void ibus_panel_impanel_update_lookup_table(IBusPanelService *panel, IBusLookupTable *lookup_table, gboolean visible);
63 static void ibus_panel_impanel_update_preedit_text(IBusPanelService *panel, IBusText *text, guint cursor_pos, gboolean visible);
64 static void ibus_panel_impanel_update_property(IBusPanelService *panel, IBusProperty *prop);
65 static void ibus_panel_impanel_cursor_down_lookup_table(IBusPanelService *panel);
66 static void ibus_panel_impanel_cursor_up_lookup_table(IBusPanelService *panel);
67 static void ibus_panel_impanel_hide_auxiliary_text(IBusPanelService *panel);
68 static void ibus_panel_impanel_hide_language_bar(IBusPanelService *panel);
69 static void ibus_panel_impanel_hide_lookup_table(IBusPanelService *panel);
70 static void ibus_panel_impanel_hide_preedit_text(IBusPanelService *panel);
71 static void ibus_panel_impanel_page_down_lookup_table(IBusPanelService *panel);
72 static void ibus_panel_impanel_page_up_lookup_table(IBusPanelService *panel);
73 static void ibus_panel_impanel_reset(IBusPanelService *panel);
74 static void ibus_panel_impanel_show_auxiliary_text(IBusPanelService *panel);
75 static void ibus_panel_impanel_show_language_bar(IBusPanelService *panel);
76 static void ibus_panel_impanel_show_lookup_table(IBusPanelService *panel);
77 static void ibus_panel_impanel_show_preedit_text(IBusPanelService *panel);
78 static void ibus_panel_impanel_start_setup(IBusPanelService *panel);
79 static void ibus_panel_impanel_state_changed(IBusPanelService *panel);
80
81 /* impanel signal handler function */
82 static void ibus_panel_impanel_exec_im_menu(IBusPanelImpanel *impanel);
83 static void ibus_panel_impanel_exec_menu(IBusPanelImpanel *impanel, IBusPropList *prop_list);
84
85 static void impanel_set_engine(IBusPanelImpanel *impanel, const char *name);
86
87 static QByteArray ibus_property_to_propstr(IBusProperty *property, gboolean useSymbol = FALSE);
88
89 static QByteArray ibus_engine_desc_to_logo_propstr(IBusEngineDesc *engine);
90
impanel_update_logo_by_engine(IBusPanelImpanel * impanel,IBusEngineDesc * engine_desc)91 void impanel_update_logo_by_engine(IBusPanelImpanel *impanel, IBusEngineDesc *engine_desc)
92 {
93 if (!impanel->conn) {
94 return;
95 }
96
97 QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc);
98
99 g_dbus_connection_emit_signal(impanel->conn,
100 nullptr,
101 "/kimpanel",
102 "org.kde.kimpanel.inputmethod",
103 "UpdateProperty",
104 (g_variant_new("(s)", propstr.constData())),
105 nullptr);
106 }
107
ibus_panel_impanel_set_bus(IBusPanelImpanel * impanel,IBusBus * bus)108 void ibus_panel_impanel_set_bus(IBusPanelImpanel *impanel, IBusBus *bus)
109 {
110 impanel->bus = bus;
111 }
112
ibus_panel_impanel_set_app(IBusPanelImpanel * impanel,App * app)113 void ibus_panel_impanel_set_app(IBusPanelImpanel *impanel, App *app)
114 {
115 impanel->app = app;
116 }
117
ibus_panel_impanel_accept(IBusPanelImpanel * impanel)118 void ibus_panel_impanel_accept(IBusPanelImpanel *impanel)
119 {
120 if (impanel->selected >= 0 && static_cast<size_t>(impanel->selected) < impanel->engineManager->length()) {
121 impanel_set_engine(impanel, ibus_engine_desc_get_name(impanel->engineManager->engines()[impanel->selected]));
122 impanel->selected = -1;
123 }
124 }
125
ibus_panel_impanel_navigate(IBusPanelImpanel * impanel,gboolean start,gboolean forward)126 void ibus_panel_impanel_navigate(IBusPanelImpanel *impanel, gboolean start, gboolean forward)
127 {
128 if (start) {
129 impanel->selected = -1;
130 }
131
132 if (impanel->engineManager->length() < 2) {
133 return;
134 }
135
136 IBusEngineDesc *engine_desc = nullptr;
137 if (impanel->selected < 0) {
138 engine_desc = ibus_bus_get_global_engine(impanel->bus);
139 } else if (static_cast<size_t>(impanel->selected) < impanel->engineManager->length()) {
140 engine_desc = impanel->engineManager->engines()[impanel->selected];
141 g_object_ref(engine_desc);
142 }
143
144 if (!engine_desc) {
145 engine_desc = impanel->engineManager->engines()[0];
146 g_object_ref(engine_desc);
147 }
148
149 if (engine_desc) {
150 const char *name = impanel->engineManager->navigate(engine_desc, forward);
151 impanel->selected = impanel->engineManager->getIndexByName(name);
152 g_object_unref(engine_desc);
153 } else {
154 return;
155 }
156
157 if (impanel->selected >= 0 && static_cast<size_t>(impanel->selected) < impanel->engineManager->length()) {
158 ibus_panel_impanel_real_register_properties(impanel);
159 }
160 }
161
ibus_panel_impanel_move_next(IBusPanelImpanel * impanel)162 void ibus_panel_impanel_move_next(IBusPanelImpanel *impanel)
163 {
164 if (impanel->engineManager->length() >= 2) {
165 impanel_set_engine(impanel, ibus_engine_desc_get_name(impanel->engineManager->engines()[1]));
166 }
167 }
168
169 static GDBusNodeInfo *introspection_data = nullptr;
170
171 static guint owner_id;
172
173 static const gchar introspection_xml[] =
174 "<node>"
175 " <interface name='org.kde.kimpanel.inputmethod'>"
176 " <signal name='Enable'>"
177 " <arg type='b' name='enable'/>"
178 " </signal>"
179 " <signal name='RegisterProperties'>"
180 " <arg type='as' name='prop'/>"
181 " </signal>"
182 " <signal name='UpdateProperty'>"
183 " <arg type='s' name='prop'/>"
184 " </signal>"
185 " <signal name='RemoveProperty'>"
186 " <arg type='s' name='prop'/>"
187 " </signal>"
188 " <signal name='ShowAux'>"
189 " <arg type='b' name='toshow'/>"
190 " </signal>"
191 " <signal name='ShowLookupTable'>"
192 " <arg type='b' name='toshow'/>"
193 " </signal>"
194 " <signal name='ShowPreedit'>"
195 " <arg type='b' name='toshow'/>"
196 " </signal>"
197 " <signal name='UpdateAux'>"
198 " <arg type='s' name='text'/>"
199 " <arg type='s' name='attr'/>"
200 " </signal>"
201 " <signal name='UpdateLookupTableCursor'>"
202 " <arg type='i' name='pos'/>"
203 " </signal>"
204 " <signal name='UpdateLookupTable'>"
205 " <arg type='as' name='labels'/>"
206 " <arg type='as' name='candidates'/>"
207 " <arg type='as' name='attrs'/>"
208 " <arg type='b' name='hasprev'/>"
209 " <arg type='b' name='hasnext'/>"
210 " </signal>"
211 " <signal name='UpdatePreeditCaret'>"
212 " <arg type='i' name='pos'/>"
213 " </signal>"
214 " <signal name='UpdatePreeditText'>"
215 " <arg type='s' name='text'/>"
216 " <arg type='s' name='attr'/>"
217 " </signal>"
218 " <signal name='UpdateSpotLocation'>"
219 " <arg type='i' name='x'/>"
220 " <arg type='i' name='y'/>"
221 " </signal>"
222 " <signal name='ExecMenu'>"
223 " <arg type='as' name='actions'/>"
224 " </signal>"
225 " </interface>"
226 "</node>";
227
228 static const char prop_sep[] = ":";
229
ibus_property_args_to_propstr(const char * key,const char * label,const char * icon,const char * tooltip,const char * hint="")230 static QByteArray ibus_property_args_to_propstr(const char *key, const char *label, const char *icon, const char *tooltip, const char *hint = "")
231 {
232 QByteArray propstr("/IBus/");
233 QByteArray str(key);
234 str.replace(':', '!');
235
236 App *app = static_cast<App *>(qApp);
237
238 propstr += str;
239 propstr += prop_sep;
240 propstr += QByteArray(label).replace(':', '-').constData();
241 propstr += prop_sep;
242 propstr += app->normalizeIconName(QByteArray(icon).replace(':', '-'));
243 propstr += prop_sep;
244 propstr += QByteArray(tooltip).replace(':', '-').constData();
245 propstr += prop_sep;
246 propstr += QByteArray(hint).replace(':', '-').constData();
247
248 return propstr;
249 }
250
ibus_engine_desc_to_logo_propstr(IBusEngineDesc * engine)251 static QByteArray ibus_engine_desc_to_logo_propstr(IBusEngineDesc *engine)
252 {
253 const gchar *label = "IBus";
254 const gchar *tooltip = "";
255 const gchar *icon = "input-keyboard";
256
257 gchar xkbLabel[3];
258 if (engine) {
259 const gchar *iconname = ibus_engine_desc_get_icon(engine);
260 if (iconname && iconname[0]) {
261 icon = iconname;
262 }
263
264 if (strncmp("xkb:", ibus_engine_desc_get_name(engine), 4) == 0) {
265 strncpy(xkbLabel, ibus_engine_desc_get_name(engine) + 4, 2);
266 xkbLabel[2] = 0;
267 int i = 0;
268 while (xkbLabel[i]) {
269 if (xkbLabel[i] == ':') {
270 xkbLabel[i] = 0;
271 }
272 i++;
273 }
274 label = xkbLabel;
275 icon = "";
276 }
277
278 const gchar *longname = ibus_engine_desc_get_longname(engine);
279 if (longname && longname[0]) {
280 tooltip = longname;
281 }
282 }
283
284 return ibus_property_args_to_propstr("Logo", label, icon, tooltip);
285 }
286
ibus_property_to_propstr(IBusProperty * property,gboolean useSymbol)287 static QByteArray ibus_property_to_propstr(IBusProperty *property, gboolean useSymbol)
288 {
289 const gchar *label = nullptr;
290 const gchar *tooltip = ibus_text_get_text(ibus_property_get_tooltip(property));
291 const gchar *icon = ibus_property_get_icon(property);
292
293 if (useSymbol) {
294 label = ibus_text_get_text(ibus_property_get_symbol(property));
295 if (!label || label[0] == '\0') {
296 label = ibus_text_get_text(ibus_property_get_label(property));
297 }
298 } else {
299 label = ibus_text_get_text(ibus_property_get_label(property));
300 }
301
302 const char *hint = "";
303 if (ibus_property_get_prop_type(property) == PROP_TYPE_TOGGLE) {
304 if (ibus_property_get_state(property) != PROP_STATE_CHECKED) {
305 hint = "disable";
306 }
307 } else if (ibus_property_get_prop_type(property) == PROP_TYPE_RADIO) {
308 if (ibus_property_get_state(property) == PROP_STATE_CHECKED) {
309 hint = "checked";
310 }
311 }
312
313 return ibus_property_args_to_propstr(ibus_property_get_key(property), label, icon, tooltip, hint);
314 }
315
ibus_engine_desc_args_to_propstr(const char * name,const char * language,const char * longname,const char * icon,const char * description)316 static QByteArray ibus_engine_desc_args_to_propstr(const char *name, const char *language, const char *longname, const char *icon, const char *description)
317 {
318 QByteArray propstr("/IBus/Engine/");
319 QByteArray data(name);
320 data.replace(':', '!');
321 propstr += data;
322 propstr += prop_sep;
323 if (language) {
324 propstr += language;
325 propstr += " - ";
326 }
327 propstr += longname;
328 propstr += prop_sep;
329 propstr += icon;
330 propstr += prop_sep;
331 propstr += description;
332 return propstr;
333 }
334
ibus_engine_desc_to_propstr(IBusEngineDesc * engine_desc)335 static QByteArray ibus_engine_desc_to_propstr(IBusEngineDesc *engine_desc)
336 {
337 return ibus_engine_desc_args_to_propstr(ibus_engine_desc_get_name(engine_desc),
338 ibus_engine_desc_get_language(engine_desc),
339 ibus_engine_desc_get_longname(engine_desc),
340 ibus_engine_desc_get_icon(engine_desc),
341 ibus_engine_desc_get_description(engine_desc));
342 }
343
impanel_get_default_engine(IBusPanelImpanel * impanel,char *** pengine_names,gsize * plen)344 static void impanel_get_default_engine(IBusPanelImpanel *impanel, char ***pengine_names, gsize *plen)
345 {
346 GList *engines = ibus_bus_list_engines(impanel->bus);
347 if (!engines) {
348 *pengine_names = g_new0(gchar *, 2);
349 *plen = 1;
350 (*pengine_names)[0] = g_strdup("xkb:us::eng");
351 return;
352 }
353
354 QList<QByteArray> engineList;
355 impanel->xkbLayoutManager->getLayout();
356 QStringList layouts = impanel->xkbLayoutManager->defaultLayout().split(QLatin1Char{','});
357 QStringList variants = impanel->xkbLayoutManager->defaultVariant().split(QLatin1Char{','});
358
359 for (int i = 0; i < layouts.size(); i++) {
360 QString variant;
361 if (i < variants.size()) {
362 variant = variants[i];
363 }
364
365 for (GList *engine = g_list_first(engines); engine != nullptr; engine = g_list_next(engine)) {
366 IBusEngineDesc *desc = IBUS_ENGINE_DESC(engine->data);
367 QByteArray name = ibus_engine_desc_get_name(desc);
368 if (!name.startsWith("xkb:")) {
369 continue;
370 }
371
372 if (QLatin1String(ibus_engine_desc_get_layout(desc)) == layouts[i] && QLatin1String(ibus_engine_desc_get_layout_variant(desc)) == variant) {
373 engineList << name;
374 }
375 }
376 }
377 const char *locale = setlocale(LC_CTYPE, nullptr);
378 if (!locale) {
379 locale = "C";
380 }
381
382 QStringList localeList = QString::fromLocal8Bit(locale).split(QLatin1Char{'.'});
383 const QString lang = localeList.size() > 0 ? localeList.at(0) : QString{};
384
385 bool added = false;
386 for (GList *engine = g_list_first(engines); engine != nullptr; engine = g_list_next(engine)) {
387 IBusEngineDesc *desc = IBUS_ENGINE_DESC(engine->data);
388 QByteArray name = ibus_engine_desc_get_name(desc);
389 if (name.startsWith("xkb:")) {
390 continue;
391 }
392
393 if (QLatin1String(ibus_engine_desc_get_language(desc)) == lang && ibus_engine_desc_get_rank(desc) > 0) {
394 engineList << name;
395 added = true;
396 }
397 }
398
399 if (!added) {
400 localeList = QString(lang).split(QLatin1Char{'_'});
401 QString _lang = localeList.size() > 0 ? localeList.at(0) : QString{};
402
403 for (GList *engine = g_list_first(engines); engine != nullptr; engine = g_list_next(engine)) {
404 IBusEngineDesc *desc = IBUS_ENGINE_DESC(engine->data);
405 QByteArray name = ibus_engine_desc_get_name(desc);
406 if (name.startsWith("xkb:")) {
407 continue;
408 }
409
410 if (QLatin1String(ibus_engine_desc_get_language(desc)) == _lang && ibus_engine_desc_get_rank(desc) > 0) {
411 engineList << name;
412 }
413 }
414 }
415
416 for (GList *engine = g_list_first(engines); engine != nullptr; engine = g_list_next(engine)) {
417 IBusEngineDesc *desc = IBUS_ENGINE_DESC(engine->data);
418 g_object_unref(desc);
419 }
420
421 g_list_free(engines);
422
423 if (engineList.size() == 0) {
424 *pengine_names = g_new0(gchar *, 2);
425 *plen = 1;
426 (*pengine_names)[0] = g_strdup("xkb:us::eng");
427 return;
428 } else {
429 *pengine_names = g_new0(gchar *, engineList.size() + 1);
430 *plen = engineList.size();
431 size_t i = 0;
432 Q_FOREACH (const QByteArray &name, engineList) {
433 (*pengine_names)[i] = g_strdup(name.constData());
434 i++;
435 }
436 }
437 }
438
contains(gchar ** strlist,const gchar * str)439 bool contains(gchar **strlist, const gchar *str)
440 {
441 for (; strlist; ++strlist) {
442 if (g_strcmp0(*strlist, str) == 0)
443 return true;
444 }
445 return false;
446 }
447
impanel_update_engines(IBusPanelImpanel * impanel,GVariant * var_engines)448 static void impanel_update_engines(IBusPanelImpanel *impanel, GVariant *var_engines)
449 {
450 gchar **engine_names = nullptr;
451 size_t len = 0;
452 if (var_engines) {
453 engine_names = g_variant_dup_strv(var_engines, &len);
454 }
455 if (len == 0) {
456 g_strfreev(engine_names);
457 engine_names = nullptr;
458 }
459
460 if (!engine_names) {
461 impanel_get_default_engine(impanel, &engine_names, &len);
462 GVariant *var = g_variant_new_strv(engine_names, len);
463 g_settings_set_value(impanel->settings_general, "preload-engines", var);
464 }
465
466 IBusEngineDesc **engines = ibus_bus_get_engines_by_names(impanel->bus, engine_names);
467
468 impanel->engineManager->setEngines(engines);
469 if (engines && engines[0]
470 && (!ibus_bus_get_global_engine(impanel->bus) || !contains(engine_names, ibus_engine_desc_get_name(ibus_bus_get_global_engine(impanel->bus))))) {
471 ibus_bus_set_global_engine(impanel->bus, ibus_engine_desc_get_name(engines[0]));
472 }
473 g_strfreev(engine_names);
474
475 impanel->app->setDoGrab(len > 1);
476 }
477
impanel_update_engines_order(IBusPanelImpanel * impanel,GVariant * var_engines)478 static void impanel_update_engines_order(IBusPanelImpanel *impanel, GVariant *var_engines)
479 {
480 const gchar **engine_names = nullptr;
481 size_t len = 0;
482 engine_names = g_variant_get_strv(var_engines, &len);
483 if (len) {
484 impanel->engineManager->setOrder(engine_names, len);
485
486 if (impanel->engineManager->engines()) {
487 ibus_bus_set_global_engine(impanel->bus, ibus_engine_desc_get_name(impanel->engineManager->engines()[0]));
488 }
489 }
490 g_free(engine_names);
491 }
492
impanel_update_triggers(IBusPanelImpanel * impanel,GVariant * variant)493 static void impanel_update_triggers(IBusPanelImpanel *impanel, GVariant *variant)
494 {
495 gchar **triggers = nullptr;
496 size_t len = 0;
497 if (variant) {
498 triggers = g_variant_dup_strv(variant, &len);
499 }
500 if (len == 0) {
501 g_strfreev(triggers);
502 triggers = nullptr;
503 }
504 if (!triggers) {
505 triggers = g_new0(gchar *, 2);
506 len = 1;
507 triggers[0] = g_strdup("<Super>space");
508 }
509
510 QList<QPair<uint, uint>> triggersList;
511 for (size_t i = 0; i < len; i++) {
512 guint key = 0;
513 GdkModifierType mod = (GdkModifierType)0;
514 _gtk_accelerator_parse(triggers[i], &key, &mod);
515 if (key) {
516 triggersList << qMakePair<uint, uint>(key, (uint)mod);
517 }
518 }
519 impanel->app->setTriggerKeys(triggersList);
520 }
521
impanel_update_use_system_keyboard_layout(IBusPanelImpanel * impanel,GVariant * variant)522 static void impanel_update_use_system_keyboard_layout(IBusPanelImpanel *impanel, GVariant *variant)
523 {
524 impanel->useSystemKeyboardLayout = g_variant_get_boolean(variant);
525 }
impanel_update_use_global_engine(IBusPanelImpanel * impanel,GVariant * variant)526 static void impanel_update_use_global_engine(IBusPanelImpanel *impanel, GVariant *variant)
527 {
528 impanel->engineManager->setUseGlobalEngine(g_variant_get_boolean(variant));
529 }
530
impanel_update_latin_layouts(IBusPanelImpanel * impanel,GVariant * variant)531 static void impanel_update_latin_layouts(IBusPanelImpanel *impanel, GVariant *variant)
532 {
533 if (!variant) {
534 return;
535 }
536 gsize length;
537 const gchar **variants = g_variant_get_strv(variant, &length);
538
539 impanel->xkbLayoutManager->setLatinLayouts(variants, length);
540 g_free(variants);
541 }
542
impanel_settings_changed_callback(GSettings * settings,const gchar * key,gpointer user_data)543 static void impanel_settings_changed_callback(GSettings *settings, const gchar *key, gpointer user_data)
544 {
545 IBusPanelImpanel *impanel = ((IBusPanelImpanel *)user_data);
546 gchar *schema = nullptr;
547 GVariant *value = g_settings_get_value(settings, key);
548
549 g_object_get(G_OBJECT(settings), "schema", &schema, NULL);
550
551 if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "preload-engines") == 0) {
552 impanel_update_engines(impanel, value);
553 } else if (g_strcmp0(schema, IBUS_SCHEMA_HOTKEY) == 0 && g_strcmp0(key, "triggers") == 0) {
554 impanel_update_triggers(impanel, value);
555 } else if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "use-system-keyboard-layout") == 0) {
556 impanel_update_use_system_keyboard_layout(impanel, value);
557 } else if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "use-global-engine") == 0) {
558 impanel_update_use_global_engine(impanel, value);
559 }
560 g_free(schema);
561 }
562
impanel_exit_callback(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)563 static void impanel_exit_callback(GDBusConnection *connection,
564 const gchar *sender_name,
565 const gchar *object_path,
566 const gchar *interface_name,
567 const gchar *signal_name,
568 GVariant *parameters,
569 gpointer user_data)
570 {
571 Q_UNUSED(connection);
572 Q_UNUSED(sender_name);
573 Q_UNUSED(object_path);
574 Q_UNUSED(interface_name);
575 Q_UNUSED(signal_name);
576 Q_UNUSED(parameters);
577 IBusPanelImpanel *impanel = ((IBusPanelImpanel *)user_data);
578 if (impanel->bus) {
579 ibus_bus_exit(impanel->bus, FALSE);
580 }
581 }
582
impanel_panel_created_callback(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)583 static void impanel_panel_created_callback(GDBusConnection *connection,
584 const gchar *sender_name,
585 const gchar *object_path,
586 const gchar *interface_name,
587 const gchar *signal_name,
588 GVariant *parameters,
589 gpointer user_data)
590 {
591 Q_UNUSED(connection);
592 Q_UNUSED(sender_name);
593 Q_UNUSED(object_path);
594 Q_UNUSED(interface_name);
595 Q_UNUSED(signal_name);
596 Q_UNUSED(parameters);
597 IBusPanelImpanel *impanel = ((IBusPanelImpanel *)user_data);
598 ibus_panel_impanel_real_register_properties(impanel);
599 }
600
impanel_set_engine(IBusPanelImpanel * impanel,const char * name)601 static void impanel_set_engine(IBusPanelImpanel *impanel, const char *name)
602 {
603 if (!name || !name[0]) {
604 return;
605 }
606 if (ibus_bus_set_global_engine(impanel->bus, name)) {
607 if (!impanel->useSystemKeyboardLayout) {
608 IBusEngineDesc *engine_desc = ibus_bus_get_global_engine(impanel->bus);
609 if (engine_desc) {
610 impanel->xkbLayoutManager->setLayout(engine_desc);
611 }
612 g_object_unref(engine_desc);
613 }
614 impanel->engineManager->setCurrentEngine(name);
615 } else {
616 qDebug() << "set engine failed.";
617 }
618 }
619
impanel_trigger_property_callback(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)620 static void impanel_trigger_property_callback(GDBusConnection *connection,
621 const gchar *sender_name,
622 const gchar *object_path,
623 const gchar *interface_name,
624 const gchar *signal_name,
625 GVariant *parameters,
626 gpointer user_data)
627 {
628 Q_UNUSED(connection);
629 Q_UNUSED(sender_name);
630 Q_UNUSED(object_path);
631 Q_UNUSED(interface_name);
632 Q_UNUSED(signal_name);
633 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(user_data);
634 gchar *s0 = nullptr;
635 g_variant_get(parameters, "(s)", &s0);
636 if (!s0 || strlen(s0) <= 6)
637 return;
638 QByteArray prop_key(s0 + 6); // +6 to skip "/IBus/"
639 prop_key.replace('!', ':');
640 if (g_ascii_strncasecmp(prop_key.constData(), "Logo", 4) == 0)
641 ibus_panel_impanel_exec_im_menu(impanel);
642 else if (g_ascii_strncasecmp(prop_key.constData(), "Engine/", 7) == 0) {
643 impanel_set_engine(impanel, prop_key.constData() + 7);
644 } else {
645 IBusProperty *property = impanel->propManager->property(prop_key.constData());
646 if (property) {
647 IBusPropState newstate = ibus_property_get_state(property);
648 switch (ibus_property_get_prop_type(property)) {
649 case PROP_TYPE_RADIO:
650 case PROP_TYPE_TOGGLE:
651 if (ibus_property_get_prop_type(property) == PROP_TYPE_TOGGLE) {
652 if (newstate == PROP_STATE_CHECKED)
653 newstate = PROP_STATE_UNCHECKED;
654 else if (newstate == PROP_STATE_UNCHECKED)
655 newstate = PROP_STATE_CHECKED;
656 } else if (ibus_property_get_prop_type(property) == PROP_TYPE_RADIO) {
657 newstate = PROP_STATE_CHECKED;
658 }
659 Q_FALLTHROUGH();
660 case PROP_TYPE_NORMAL:
661 ibus_property_set_state(property, newstate);
662 ibus_panel_service_property_activate((IBusPanelService *)impanel, prop_key.constData(), newstate);
663 break;
664 case PROP_TYPE_MENU:
665 ibus_panel_impanel_exec_menu(impanel, ibus_property_get_sub_props(property));
666 case PROP_TYPE_SEPARATOR:
667 break;
668 default:
669 break;
670 }
671 } else {
672 ibus_panel_service_property_activate((IBusPanelService *)impanel, prop_key.constData(), PROP_STATE_CHECKED);
673 }
674 }
675 g_free(s0);
676 }
677
impanel_select_candidate_callback(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)678 static void impanel_select_candidate_callback(GDBusConnection *connection,
679 const gchar *sender_name,
680 const gchar *object_path,
681 const gchar *interface_name,
682 const gchar *signal_name,
683 GVariant *parameters,
684 gpointer user_data)
685 {
686 Q_UNUSED(connection);
687 Q_UNUSED(sender_name);
688 Q_UNUSED(object_path);
689 Q_UNUSED(interface_name);
690 Q_UNUSED(signal_name);
691
692 gint i;
693 g_variant_get(parameters, "(i)", &i);
694 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(user_data);
695 ibus_panel_service_candidate_clicked((IBusPanelService *)impanel, i, 0, 0);
696 }
697
impanel_prev_page_callback(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)698 static void impanel_prev_page_callback(GDBusConnection *connection,
699 const gchar *sender_name,
700 const gchar *object_path,
701 const gchar *interface_name,
702 const gchar *signal_name,
703 GVariant *parameters,
704 gpointer user_data)
705 {
706 Q_UNUSED(connection);
707 Q_UNUSED(sender_name);
708 Q_UNUSED(object_path);
709 Q_UNUSED(interface_name);
710 Q_UNUSED(signal_name);
711 Q_UNUSED(parameters);
712
713 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(user_data);
714 ibus_panel_service_page_up((IBusPanelService *)impanel);
715 }
716
impanel_next_page_callback(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)717 static void impanel_next_page_callback(GDBusConnection *connection,
718 const gchar *sender_name,
719 const gchar *object_path,
720 const gchar *interface_name,
721 const gchar *signal_name,
722 GVariant *parameters,
723 gpointer user_data)
724 {
725 Q_UNUSED(connection);
726 Q_UNUSED(sender_name);
727 Q_UNUSED(object_path);
728 Q_UNUSED(interface_name);
729 Q_UNUSED(signal_name);
730 Q_UNUSED(parameters);
731
732 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(user_data);
733 ibus_panel_service_page_down((IBusPanelService *)impanel);
734 }
735
impanel_configure_callback(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)736 static void impanel_configure_callback(GDBusConnection *connection,
737 const gchar *sender_name,
738 const gchar *object_path,
739 const gchar *interface_name,
740 const gchar *signal_name,
741 GVariant *parameters,
742 gpointer user_data)
743 {
744 Q_UNUSED(connection);
745 Q_UNUSED(sender_name);
746 Q_UNUSED(object_path);
747 Q_UNUSED(interface_name);
748 Q_UNUSED(signal_name);
749 Q_UNUSED(parameters);
750 Q_UNUSED(user_data);
751 pid_t pid = fork();
752 if (pid == 0) {
753 execlp("ibus-setup", "ibus-setup", (char *)nullptr);
754 exit(0);
755 }
756 }
757
on_bus_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)758 static void on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
759 {
760 Q_UNUSED(name);
761 IBusPanelImpanel *impanel = ((IBusPanelImpanel *)user_data);
762 impanel->conn = connection;
763
764 g_dbus_connection_register_object(connection,
765 "/kimpanel",
766 introspection_data->interfaces[0],
767 nullptr, /*&interface_vtable*/
768 nullptr, /* user_data */
769 nullptr, /* user_data_free_func */
770 nullptr); /* GError** */
771
772 g_dbus_connection_signal_subscribe(connection,
773 "org.kde.impanel",
774 "org.kde.impanel",
775 "TriggerProperty",
776 "/org/kde/impanel",
777 nullptr,
778 G_DBUS_SIGNAL_FLAGS_NONE,
779 impanel_trigger_property_callback,
780 user_data,
781 nullptr);
782 g_dbus_connection_signal_subscribe(connection,
783 "org.kde.impanel",
784 "org.kde.impanel",
785 "SelectCandidate",
786 "/org/kde/impanel",
787 nullptr,
788 G_DBUS_SIGNAL_FLAGS_NONE,
789 impanel_select_candidate_callback,
790 user_data,
791 nullptr);
792 g_dbus_connection_signal_subscribe(connection,
793 "org.kde.impanel",
794 "org.kde.impanel",
795 "LookupTablePageUp",
796 "/org/kde/impanel",
797 nullptr,
798 G_DBUS_SIGNAL_FLAGS_NONE,
799 impanel_prev_page_callback,
800 user_data,
801 nullptr);
802 g_dbus_connection_signal_subscribe(connection,
803 "org.kde.impanel",
804 "org.kde.impanel",
805 "LookupTablePageDown",
806 "/org/kde/impanel",
807 nullptr,
808 G_DBUS_SIGNAL_FLAGS_NONE,
809 impanel_next_page_callback,
810 user_data,
811 nullptr);
812 g_dbus_connection_signal_subscribe(connection,
813 "org.kde.impanel",
814 "org.kde.impanel",
815 "PanelCreated",
816 "/org/kde/impanel",
817 nullptr,
818 G_DBUS_SIGNAL_FLAGS_NONE,
819 impanel_panel_created_callback,
820 user_data,
821 nullptr);
822 g_dbus_connection_signal_subscribe(connection,
823 "org.kde.impanel",
824 "org.kde.impanel",
825 "Exit",
826 "/org/kde/impanel",
827 nullptr,
828 G_DBUS_SIGNAL_FLAGS_NONE,
829 impanel_exit_callback,
830 user_data,
831 nullptr);
832 g_dbus_connection_signal_subscribe(connection,
833 "org.kde.impanel",
834 "org.kde.impanel",
835 "Configure",
836 "/org/kde/impanel",
837 nullptr,
838 G_DBUS_SIGNAL_FLAGS_NONE,
839 impanel_configure_callback,
840 user_data,
841 nullptr);
842
843 GVariant *var_engines = g_settings_get_value(impanel->settings_general, "preload-engines");
844 impanel_update_engines(impanel, var_engines);
845 if (var_engines) {
846 g_variant_unref(var_engines);
847 }
848
849 var_engines = g_settings_get_value(impanel->settings_general, "engines-order");
850 if (var_engines) {
851 impanel_update_engines_order(impanel, var_engines);
852 g_variant_unref(var_engines);
853 }
854
855 GVariant *var_triggers = g_settings_get_value(impanel->settings_hotkey, "triggers");
856 impanel_update_triggers(impanel, var_triggers);
857 if (var_triggers) {
858 g_variant_unref(var_triggers);
859 }
860
861 GVariant *var_layouts = g_settings_get_value(impanel->settings_general, "xkb-latin-layouts");
862 if (var_layouts) {
863 impanel_update_latin_layouts(impanel, var_layouts);
864 g_variant_unref(var_layouts);
865 }
866
867 GVariant *var = g_settings_get_value(impanel->settings_general, "use-system-keyboard-layout");
868 if (var) {
869 impanel_update_use_system_keyboard_layout(impanel, var);
870 g_variant_unref(var);
871 }
872
873 var = g_settings_get_value(impanel->settings_general, "use-global-engine");
874 if (var) {
875 impanel_update_use_global_engine(impanel, var);
876 g_variant_unref(var);
877 }
878
879 ibus_panel_impanel_real_register_properties(impanel);
880 }
881
on_name_acquired(GDBusConnection * connection,const gchar * name,gpointer user_data)882 static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
883 {
884 Q_UNUSED(connection);
885 Q_UNUSED(name);
886 Q_UNUSED(user_data);
887 }
888
on_name_lost(GDBusConnection * connection,const gchar * name,gpointer user_data)889 static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data)
890 {
891 Q_UNUSED(connection);
892 Q_UNUSED(name);
893 Q_UNUSED(user_data);
894 exit(1);
895 }
896
G_DEFINE_TYPE(IBusPanelImpanel,ibus_panel_impanel,IBUS_TYPE_PANEL_SERVICE)897 G_DEFINE_TYPE(IBusPanelImpanel, ibus_panel_impanel, IBUS_TYPE_PANEL_SERVICE)
898
899 static void ibus_panel_impanel_class_init(IBusPanelImpanelClass *klass)
900 {
901 GObjectClass *object_class = G_OBJECT_CLASS(klass);
902
903 // clang-format off
904 IBUS_OBJECT_CLASS (object_class)->destroy = (IBusObjectDestroyFunc) ibus_panel_impanel_destroy;
905 IBUS_PANEL_SERVICE_CLASS (object_class)->focus_in = ibus_panel_impanel_focus_in;
906 IBUS_PANEL_SERVICE_CLASS (object_class)->focus_out = ibus_panel_impanel_focus_out;
907 IBUS_PANEL_SERVICE_CLASS (object_class)->register_properties = ibus_panel_impanel_register_properties;
908 IBUS_PANEL_SERVICE_CLASS (object_class)->set_cursor_location = ibus_panel_impanel_set_cursor_location;
909 IBUS_PANEL_SERVICE_CLASS (object_class)->update_auxiliary_text = ibus_panel_impanel_update_auxiliary_text;
910 IBUS_PANEL_SERVICE_CLASS (object_class)->update_lookup_table = ibus_panel_impanel_update_lookup_table;
911 IBUS_PANEL_SERVICE_CLASS (object_class)->update_preedit_text = ibus_panel_impanel_update_preedit_text;
912 IBUS_PANEL_SERVICE_CLASS (object_class)->update_property = ibus_panel_impanel_update_property;
913 IBUS_PANEL_SERVICE_CLASS (object_class)->cursor_down_lookup_table = ibus_panel_impanel_cursor_down_lookup_table;
914 IBUS_PANEL_SERVICE_CLASS (object_class)->cursor_up_lookup_table = ibus_panel_impanel_cursor_up_lookup_table;
915 IBUS_PANEL_SERVICE_CLASS (object_class)->hide_auxiliary_text = ibus_panel_impanel_hide_auxiliary_text;
916 IBUS_PANEL_SERVICE_CLASS (object_class)->hide_language_bar = ibus_panel_impanel_hide_language_bar;
917 IBUS_PANEL_SERVICE_CLASS (object_class)->hide_lookup_table = ibus_panel_impanel_hide_lookup_table;
918 IBUS_PANEL_SERVICE_CLASS (object_class)->hide_preedit_text = ibus_panel_impanel_hide_preedit_text;
919 IBUS_PANEL_SERVICE_CLASS (object_class)->page_down_lookup_table = ibus_panel_impanel_page_down_lookup_table;
920 IBUS_PANEL_SERVICE_CLASS (object_class)->page_up_lookup_table = ibus_panel_impanel_page_up_lookup_table;
921 IBUS_PANEL_SERVICE_CLASS (object_class)->reset = ibus_panel_impanel_reset;
922 IBUS_PANEL_SERVICE_CLASS (object_class)->show_auxiliary_text = ibus_panel_impanel_show_auxiliary_text;
923 IBUS_PANEL_SERVICE_CLASS (object_class)->show_language_bar = ibus_panel_impanel_show_language_bar;
924 IBUS_PANEL_SERVICE_CLASS (object_class)->show_lookup_table = ibus_panel_impanel_show_lookup_table;
925 IBUS_PANEL_SERVICE_CLASS (object_class)->show_preedit_text = ibus_panel_impanel_show_preedit_text;
926 IBUS_PANEL_SERVICE_CLASS (object_class)->start_setup = ibus_panel_impanel_start_setup;
927 IBUS_PANEL_SERVICE_CLASS (object_class)->state_changed = ibus_panel_impanel_state_changed;
928 // clang-format on
929 }
930
ibus_panel_impanel_init(IBusPanelImpanel * impanel)931 static void ibus_panel_impanel_init(IBusPanelImpanel *impanel)
932 {
933 impanel->bus = nullptr;
934 impanel->app = nullptr;
935 impanel->useSystemKeyboardLayout = false;
936 impanel->selected = -1;
937
938 introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, nullptr);
939 owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
940 "org.kde.kimpanel.inputmethod",
941 G_BUS_NAME_OWNER_FLAGS_REPLACE,
942 on_bus_acquired,
943 on_name_acquired,
944 on_name_lost,
945 impanel,
946 nullptr);
947
948 impanel->propManager = new PropertyManager;
949 impanel->engineManager = new EngineManager;
950 impanel->xkbLayoutManager = new XkbLayoutManager;
951 impanel->settings_general = g_settings_new(IBUS_SCHEMA_GENERAL);
952 impanel->settings_hotkey = g_settings_new(IBUS_SCHEMA_HOTKEY);
953 g_signal_connect(impanel->settings_general, "changed", G_CALLBACK(impanel_settings_changed_callback), impanel);
954 g_signal_connect(impanel->settings_hotkey, "changed", G_CALLBACK(impanel_settings_changed_callback), impanel);
955 }
956
ibus_panel_impanel_destroy(IBusPanelImpanel * impanel)957 static void ibus_panel_impanel_destroy(IBusPanelImpanel *impanel)
958 {
959 delete impanel->propManager;
960 impanel->propManager = nullptr;
961 delete impanel->engineManager;
962 impanel->engineManager = nullptr;
963 delete impanel->xkbLayoutManager;
964 impanel->xkbLayoutManager = nullptr;
965
966 g_signal_handlers_disconnect_by_func(impanel->settings_general, (gpointer)impanel_settings_changed_callback, impanel);
967 g_signal_handlers_disconnect_by_func(impanel->settings_hotkey, (gpointer)impanel_settings_changed_callback, impanel);
968 g_clear_object(&impanel->settings_general);
969 g_clear_object(&impanel->settings_hotkey);
970
971 g_bus_unown_name(owner_id);
972 g_dbus_node_info_unref(introspection_data);
973
974 IBUS_OBJECT_CLASS(ibus_panel_impanel_parent_class)->destroy((IBusObject *)impanel);
975 }
976
ibus_panel_impanel_focus_in(IBusPanelService * panel,const gchar * input_context_path)977 static void ibus_panel_impanel_focus_in(IBusPanelService *panel, const gchar *input_context_path)
978 {
979 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
980 if (impanel->app->keyboardGrabbed()) {
981 return;
982 }
983
984 auto engine_desc = ibus_bus_get_global_engine(impanel->bus);
985 if (engine_desc) {
986 impanel_update_logo_by_engine(impanel, engine_desc);
987 g_object_unref(engine_desc);
988 }
989
990 impanel->engineManager->setCurrentContext(input_context_path);
991 if (!impanel->engineManager->useGlobalEngine()) {
992 impanel_set_engine(impanel, impanel->engineManager->currentEngine().toUtf8().constData());
993 }
994 }
995
ibus_panel_impanel_focus_out(IBusPanelService * panel,const gchar * input_context_path)996 static void ibus_panel_impanel_focus_out(IBusPanelService *panel, const gchar *input_context_path)
997 {
998 Q_UNUSED(panel);
999 Q_UNUSED(input_context_path);
1000 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1001
1002 if (impanel->app->keyboardGrabbed()) {
1003 return;
1004 }
1005
1006 if (impanel->engineManager->useGlobalEngine()) {
1007 return;
1008 }
1009 impanel->engineManager->setCurrentContext("");
1010 }
1011
ibus_panel_impanel_register_properties(IBusPanelService * panel,IBusPropList * prop_list)1012 static void ibus_panel_impanel_register_properties(IBusPanelService *panel, IBusPropList *prop_list)
1013 {
1014 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1015 impanel->propManager->setProperties(prop_list);
1016 ibus_panel_impanel_real_register_properties(impanel);
1017 }
1018
ibus_panel_impanel_real_register_properties(IBusPanelImpanel * impanel)1019 static void ibus_panel_impanel_real_register_properties(IBusPanelImpanel *impanel)
1020 {
1021 if (!impanel->conn)
1022 return;
1023
1024 IBusProperty *property = nullptr;
1025 guint i = 0;
1026
1027 GVariantBuilder builder;
1028 g_variant_builder_init(&builder, G_VARIANT_TYPE("as"));
1029
1030 if (impanel->selected >= 0 && static_cast<size_t>(impanel->selected) < impanel->engineManager->length()) {
1031 auto engine_desc = impanel->engineManager->engines()[impanel->selected];
1032 QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc);
1033 g_variant_builder_add(&builder, "s", propstr.constData());
1034 } else {
1035 QByteArray propstr;
1036 auto engine_desc = ibus_bus_get_global_engine(impanel->bus);
1037 if (engine_desc) {
1038 propstr = ibus_engine_desc_to_logo_propstr(engine_desc);
1039 g_variant_builder_add(&builder, "s", propstr.constData());
1040 g_object_unref(engine_desc);
1041 }
1042
1043 IBusPropList *prop_list = impanel->propManager->properties();
1044 if (prop_list) {
1045 while ((property = ibus_prop_list_get(prop_list, i)) != nullptr) {
1046 propstr = ibus_property_to_propstr(property, TRUE);
1047 g_variant_builder_add(&builder, "s", propstr.constData());
1048 ++i;
1049 }
1050 }
1051 }
1052
1053 g_dbus_connection_emit_signal(impanel->conn,
1054 nullptr,
1055 "/kimpanel",
1056 "org.kde.kimpanel.inputmethod",
1057 "RegisterProperties",
1058 (g_variant_new("(as)", &builder)),
1059 nullptr);
1060 }
1061
ibus_panel_impanel_set_cursor_location(IBusPanelService * panel,gint x,gint y,gint w,gint h)1062 static void ibus_panel_impanel_set_cursor_location(IBusPanelService *panel, gint x, gint y, gint w, gint h)
1063 {
1064 g_dbus_connection_call(IBUS_PANEL_IMPANEL(panel)->conn,
1065 "org.kde.impanel",
1066 "/org/kde/impanel",
1067 "org.kde.impanel2",
1068 "SetSpotRect",
1069 (g_variant_new("(iiii)", x, y, w, h)),
1070 nullptr,
1071 G_DBUS_CALL_FLAGS_NONE,
1072 -1, /* timeout */
1073 nullptr,
1074 nullptr,
1075 nullptr);
1076 }
1077
ibus_panel_impanel_update_auxiliary_text(IBusPanelService * panel,IBusText * text,gboolean visible)1078 static void ibus_panel_impanel_update_auxiliary_text(IBusPanelService *panel, IBusText *text, gboolean visible)
1079 {
1080 const gchar *t = ibus_text_get_text(text);
1081 const gchar *attr = "";
1082 IBusPanelImpanel *impanel = (IBusPanelImpanel *)panel;
1083
1084 if (!impanel->conn)
1085 return;
1086
1087 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateAux", (g_variant_new("(ss)", t, attr)), nullptr);
1088
1089 if (visible == 0)
1090 ibus_panel_impanel_hide_auxiliary_text(panel);
1091 else
1092 ibus_panel_impanel_show_auxiliary_text(panel);
1093 }
1094
ibus_panel_impanel_update_lookup_table(IBusPanelService * panel,IBusLookupTable * lookup_table,gboolean visible)1095 static void ibus_panel_impanel_update_lookup_table(IBusPanelService *panel, IBusLookupTable *lookup_table, gboolean visible)
1096 {
1097 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1098 if (!impanel->conn)
1099 return;
1100
1101 guint page_size = ibus_lookup_table_get_page_size(lookup_table);
1102 guint cursor_pos = ibus_lookup_table_get_cursor_pos(lookup_table);
1103 guint page = cursor_pos / page_size;
1104 guint start = page * page_size;
1105 guint end = start + page_size;
1106 guint num = ibus_lookup_table_get_number_of_candidates(lookup_table);
1107 if (end > num) {
1108 end = num;
1109 }
1110
1111 // fprintf(stderr, "%d ~ %d pgsize %d num %d\n", start, end, page_size, num);
1112
1113 guint i;
1114
1115 gchar label[16][4]; // WARNING large enough I think --- nihui
1116 const gchar *candidate;
1117
1118 GVariantBuilder builder_labels;
1119 GVariantBuilder builder_candidates;
1120 GVariantBuilder builder_attrs;
1121 g_variant_builder_init(&builder_labels, G_VARIANT_TYPE("as"));
1122 g_variant_builder_init(&builder_candidates, G_VARIANT_TYPE("as"));
1123 g_variant_builder_init(&builder_attrs, G_VARIANT_TYPE("as"));
1124
1125 const gchar *attr = "";
1126 for (i = start; i < end; i++) {
1127 g_snprintf(label[i - start], 4, "%d", (i - start + 1) % 10);
1128 // NOTE ibus always return NULL for ibus_lookup_table_get_label
1129 // label = ibus_lookup_table_get_label(lookup_table, i)->text;
1130 g_variant_builder_add(&builder_labels, "s", label[i - start]);
1131
1132 candidate = ibus_text_get_text(ibus_lookup_table_get_candidate(lookup_table, i));
1133 g_variant_builder_add(&builder_candidates, "s", candidate);
1134
1135 g_variant_builder_add(&builder_attrs, "s", attr);
1136 }
1137
1138 gboolean has_prev = 1;
1139 gboolean has_next = 1;
1140
1141 guint cursor_pos_in_page;
1142 if (ibus_lookup_table_is_cursor_visible(lookup_table))
1143 cursor_pos_in_page = cursor_pos % page_size;
1144 else
1145 cursor_pos_in_page = -1;
1146
1147 gint orientation = ibus_lookup_table_get_orientation(lookup_table);
1148 if (orientation == IBUS_ORIENTATION_HORIZONTAL) {
1149 orientation = 2;
1150 } else if (orientation == IBUS_ORIENTATION_VERTICAL) {
1151 orientation = 1;
1152 } else {
1153 orientation = 0;
1154 }
1155
1156 g_dbus_connection_call(
1157 impanel->conn,
1158 "org.kde.impanel",
1159 "/org/kde/impanel",
1160 "org.kde.impanel2",
1161 "SetLookupTable",
1162 (g_variant_new("(asasasbbii)", &builder_labels, &builder_candidates, &builder_attrs, has_prev, has_next, cursor_pos_in_page, orientation)),
1163 nullptr,
1164 G_DBUS_CALL_FLAGS_NONE,
1165 -1,
1166 nullptr,
1167 nullptr,
1168 nullptr);
1169
1170 if (visible == 0)
1171 ibus_panel_impanel_hide_lookup_table(panel);
1172 else
1173 ibus_panel_impanel_show_lookup_table(panel);
1174 }
1175
ibus_panel_impanel_update_preedit_text(IBusPanelService * panel,IBusText * text,guint cursor_pos,gboolean visible)1176 static void ibus_panel_impanel_update_preedit_text(IBusPanelService *panel, IBusText *text, guint cursor_pos, gboolean visible)
1177 {
1178 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1179 if (!impanel->conn)
1180 return;
1181
1182 const gchar *t = ibus_text_get_text(text);
1183 const gchar *attr = "";
1184
1185 g_dbus_connection_emit_signal(impanel->conn,
1186 nullptr,
1187 "/kimpanel",
1188 "org.kde.kimpanel.inputmethod",
1189 "UpdatePreeditText",
1190 (g_variant_new("(ss)", t, attr)),
1191 nullptr);
1192
1193 g_dbus_connection_emit_signal(impanel->conn,
1194 nullptr,
1195 "/kimpanel",
1196 "org.kde.kimpanel.inputmethod",
1197 "UpdatePreeditCaret",
1198 (g_variant_new("(i)", cursor_pos)),
1199 nullptr);
1200
1201 if (visible == 0)
1202 ibus_panel_impanel_hide_preedit_text(panel);
1203 else
1204 ibus_panel_impanel_show_preedit_text(panel);
1205 }
1206
ibus_panel_impanel_update_property(IBusPanelService * panel,IBusProperty * prop)1207 static void ibus_panel_impanel_update_property(IBusPanelService *panel, IBusProperty *prop)
1208 {
1209 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1210 if (!impanel->conn)
1211 return;
1212
1213 impanel->propManager->updateProperty(prop);
1214
1215 QByteArray propstr = ibus_property_to_propstr(prop, TRUE);
1216
1217 g_dbus_connection_emit_signal(impanel->conn,
1218 nullptr,
1219 "/kimpanel",
1220 "org.kde.kimpanel.inputmethod",
1221 "UpdateProperty",
1222 (g_variant_new("(s)", propstr.constData())),
1223 nullptr);
1224 }
1225
ibus_panel_impanel_cursor_down_lookup_table(IBusPanelService * panel)1226 static void ibus_panel_impanel_cursor_down_lookup_table(IBusPanelService *panel)
1227 {
1228 Q_UNUSED(panel);
1229 }
1230
ibus_panel_impanel_cursor_up_lookup_table(IBusPanelService * panel)1231 static void ibus_panel_impanel_cursor_up_lookup_table(IBusPanelService *panel)
1232 {
1233 Q_UNUSED(panel);
1234 }
1235
ibus_panel_impanel_hide_auxiliary_text(IBusPanelService * panel)1236 static void ibus_panel_impanel_hide_auxiliary_text(IBusPanelService *panel)
1237 {
1238 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1239 if (!impanel->conn)
1240 return;
1241 gboolean toShow = 0;
1242
1243 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new("(b)", toShow)), nullptr);
1244 }
1245
ibus_panel_impanel_hide_language_bar(IBusPanelService * panel)1246 static void ibus_panel_impanel_hide_language_bar(IBusPanelService *panel)
1247 {
1248 Q_UNUSED(panel);
1249 }
1250
ibus_panel_impanel_hide_lookup_table(IBusPanelService * panel)1251 static void ibus_panel_impanel_hide_lookup_table(IBusPanelService *panel)
1252 {
1253 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1254 if (!impanel->conn)
1255 return;
1256 gboolean toShow = 0;
1257
1258 g_dbus_connection_emit_signal(impanel->conn,
1259 nullptr,
1260 "/kimpanel",
1261 "org.kde.kimpanel.inputmethod",
1262 "ShowLookupTable",
1263 (g_variant_new("(b)", toShow)),
1264 nullptr);
1265 }
1266
ibus_panel_impanel_hide_preedit_text(IBusPanelService * panel)1267 static void ibus_panel_impanel_hide_preedit_text(IBusPanelService *panel)
1268 {
1269 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1270 if (!impanel->conn)
1271 return;
1272 gboolean toShow = 0;
1273
1274 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new("(b)", toShow)), nullptr);
1275 }
1276
ibus_panel_impanel_page_down_lookup_table(IBusPanelService * panel)1277 static void ibus_panel_impanel_page_down_lookup_table(IBusPanelService *panel)
1278 {
1279 Q_UNUSED(panel);
1280 }
1281
ibus_panel_impanel_page_up_lookup_table(IBusPanelService * panel)1282 static void ibus_panel_impanel_page_up_lookup_table(IBusPanelService *panel)
1283 {
1284 Q_UNUSED(panel);
1285 }
1286
ibus_panel_impanel_reset(IBusPanelService * panel)1287 static void ibus_panel_impanel_reset(IBusPanelService *panel)
1288 {
1289 Q_UNUSED(panel);
1290 }
1291
ibus_panel_impanel_show_auxiliary_text(IBusPanelService * panel)1292 static void ibus_panel_impanel_show_auxiliary_text(IBusPanelService *panel)
1293 {
1294 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1295 if (!impanel->conn)
1296 return;
1297 gboolean toShow = 1;
1298
1299 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new("(b)", toShow)), nullptr);
1300 }
1301
ibus_panel_impanel_show_language_bar(IBusPanelService * panel)1302 static void ibus_panel_impanel_show_language_bar(IBusPanelService *panel)
1303 {
1304 Q_UNUSED(panel);
1305 }
1306
ibus_panel_impanel_show_lookup_table(IBusPanelService * panel)1307 static void ibus_panel_impanel_show_lookup_table(IBusPanelService *panel)
1308 {
1309 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1310 if (!impanel->conn)
1311 return;
1312 gboolean toShow = 1;
1313
1314 g_dbus_connection_emit_signal(impanel->conn,
1315 nullptr,
1316 "/kimpanel",
1317 "org.kde.kimpanel.inputmethod",
1318 "ShowLookupTable",
1319 (g_variant_new("(b)", toShow)),
1320 nullptr);
1321 }
1322
ibus_panel_impanel_show_preedit_text(IBusPanelService * panel)1323 static void ibus_panel_impanel_show_preedit_text(IBusPanelService *panel)
1324 {
1325 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1326 if (!impanel->conn)
1327 return;
1328 gboolean toShow = 1;
1329
1330 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new("(b)", toShow)), nullptr);
1331 }
1332
ibus_panel_impanel_start_setup(IBusPanelService * panel)1333 static void ibus_panel_impanel_start_setup(IBusPanelService *panel)
1334 {
1335 Q_UNUSED(panel);
1336 }
1337
ibus_panel_impanel_state_changed(IBusPanelService * panel)1338 static void ibus_panel_impanel_state_changed(IBusPanelService *panel)
1339 {
1340 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel);
1341 if (!impanel->conn)
1342 return;
1343
1344 if (impanel->app->keyboardGrabbed()) {
1345 return;
1346 }
1347
1348 IBusEngineDesc *engine_desc = ibus_bus_get_global_engine(impanel->bus);
1349 if (!engine_desc) {
1350 return;
1351 }
1352
1353 impanel_update_logo_by_engine(impanel, engine_desc);
1354
1355 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "Enable", (g_variant_new("(b)", TRUE)), nullptr);
1356
1357 impanel->engineManager->moveToFirst(engine_desc);
1358 QStringList engineList = impanel->engineManager->engineOrder();
1359
1360 gchar **engine_names = g_new0(gchar *, engineList.size() + 1);
1361 size_t i = 0;
1362 Q_FOREACH (const QString &name, engineList) {
1363 engine_names[i] = g_strdup(name.toUtf8().constData());
1364 i++;
1365 }
1366
1367 GVariant *var = g_variant_new_strv(engine_names, engineList.size());
1368 g_settings_set_value(impanel->settings_general, "engines-order", var);
1369 g_strfreev(engine_names);
1370 g_object_unref(engine_desc);
1371 }
1372
ibus_panel_impanel_exec_menu(IBusPanelImpanel * impanel,IBusPropList * prop_list)1373 static void ibus_panel_impanel_exec_menu(IBusPanelImpanel *impanel, IBusPropList *prop_list)
1374 {
1375 if (!impanel->conn)
1376 return;
1377
1378 GVariantBuilder builder;
1379 g_variant_builder_init(&builder, G_VARIANT_TYPE("as"));
1380
1381 int i = 0;
1382 while (true) {
1383 IBusProperty *prop = ibus_prop_list_get(prop_list, i);
1384 if (!prop)
1385 break;
1386 QByteArray propstr = ibus_property_to_propstr(prop);
1387 g_variant_builder_add(&builder, "s", propstr.constData());
1388 i++;
1389 }
1390
1391 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new("(as)", &builder)), nullptr);
1392 }
1393
ibus_panel_impanel_exec_im_menu(IBusPanelImpanel * impanel)1394 static void ibus_panel_impanel_exec_im_menu(IBusPanelImpanel *impanel)
1395 {
1396 if (!impanel->conn)
1397 return;
1398
1399 GVariantBuilder builder;
1400 g_variant_builder_init(&builder, G_VARIANT_TYPE("as"));
1401
1402 IBusEngineDesc **engines = impanel->engineManager->engines();
1403 if (engines) {
1404 int i = 0;
1405 while (engines[i]) {
1406 QByteArray propstr = ibus_engine_desc_to_propstr(engines[i]);
1407 g_variant_builder_add(&builder, "s", propstr.constData());
1408 i++;
1409 }
1410 }
1411
1412 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new("(as)", &builder)), nullptr);
1413 }
1414
ibus_panel_impanel_new(GDBusConnection * connection)1415 IBusPanelImpanel *ibus_panel_impanel_new(GDBusConnection *connection)
1416 {
1417 IBusPanelImpanel *panel;
1418 panel = (IBusPanelImpanel *)g_object_new(IBUS_TYPE_PANEL_IMPANEL, "object-path", IBUS_PATH_PANEL, "connection", connection, NULL);
1419 return panel;
1420 }
1421