File indexing completed on 2024-11-24 05:00:24
0001 /* 0002 SPDX-FileCopyrightText: 2011-2012 Ni Hui <shuizhuyuanluo@126.com> 0003 SPDX-FileCopyrightText: 2013-2014 Weng Xuetian <wengxt@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "panel.h" 0009 #include "app.h" 0010 #include "enginemanager.h" 0011 #include "gtkaccelparse_p.h" 0012 #include "propertymanager.h" 0013 #include "xkblayoutmanager.h" 0014 #include <QByteArray> 0015 #include <QDebug> 0016 #include <QPair> 0017 #include <QStringList> 0018 #include <locale.h> 0019 #include <stdlib.h> 0020 #include <string.h> 0021 #include <string> 0022 0023 #ifndef DBUS_ERROR_FAILED 0024 #define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed" 0025 #endif /* DBUS_ERROR_FAILED */ 0026 0027 #define IBUS_SCHEMA_GENERAL "org.freedesktop.ibus.general" 0028 #define IBUS_SCHEMA_HOTKEY "org.freedesktop.ibus.general.hotkey" 0029 #define IBUS_SCHEMA_PANEL "org.freedesktop.ibus.panel" 0030 0031 typedef struct _IBusPanelImpanelClass IBusPanelImpanelClass; 0032 0033 struct _IBusPanelImpanel { 0034 IBusPanelService parent; 0035 IBusBus *bus; 0036 GDBusConnection *conn; 0037 PropertyManager *propManager; 0038 EngineManager *engineManager; 0039 XkbLayoutManager *xkbLayoutManager; 0040 App *app; 0041 gboolean useSystemKeyboardLayout; 0042 int selected; 0043 GSettings *settings_general; 0044 GSettings *settings_hotkey; 0045 }; 0046 0047 struct _IBusPanelImpanelClass { 0048 IBusPanelServiceClass parent; 0049 }; 0050 0051 /* functions prototype */ 0052 static void ibus_panel_impanel_class_init(IBusPanelImpanelClass *klass); 0053 static void ibus_panel_impanel_init(IBusPanelImpanel *impanel); 0054 static void ibus_panel_impanel_destroy(IBusPanelImpanel *impanel); 0055 0056 static void ibus_panel_impanel_focus_in(IBusPanelService *panel, const gchar *input_context_path); 0057 static void ibus_panel_impanel_focus_out(IBusPanelService *panel, const gchar *input_context_path); 0058 static void ibus_panel_impanel_register_properties(IBusPanelService *panel, IBusPropList *prop_list); 0059 static void ibus_panel_impanel_real_register_properties(IBusPanelImpanel *impanel); 0060 static void ibus_panel_impanel_set_cursor_location(IBusPanelService *panel, gint x, gint y, gint w, gint h); 0061 static void ibus_panel_impanel_update_auxiliary_text(IBusPanelService *panel, IBusText *text, gboolean visible); 0062 static void ibus_panel_impanel_update_lookup_table(IBusPanelService *panel, IBusLookupTable *lookup_table, gboolean visible); 0063 static void ibus_panel_impanel_update_preedit_text(IBusPanelService *panel, IBusText *text, guint cursor_pos, gboolean visible); 0064 static void ibus_panel_impanel_update_property(IBusPanelService *panel, IBusProperty *prop); 0065 static void ibus_panel_impanel_cursor_down_lookup_table(IBusPanelService *panel); 0066 static void ibus_panel_impanel_cursor_up_lookup_table(IBusPanelService *panel); 0067 static void ibus_panel_impanel_hide_auxiliary_text(IBusPanelService *panel); 0068 static void ibus_panel_impanel_hide_language_bar(IBusPanelService *panel); 0069 static void ibus_panel_impanel_hide_lookup_table(IBusPanelService *panel); 0070 static void ibus_panel_impanel_hide_preedit_text(IBusPanelService *panel); 0071 static void ibus_panel_impanel_page_down_lookup_table(IBusPanelService *panel); 0072 static void ibus_panel_impanel_page_up_lookup_table(IBusPanelService *panel); 0073 static void ibus_panel_impanel_reset(IBusPanelService *panel); 0074 static void ibus_panel_impanel_show_auxiliary_text(IBusPanelService *panel); 0075 static void ibus_panel_impanel_show_language_bar(IBusPanelService *panel); 0076 static void ibus_panel_impanel_show_lookup_table(IBusPanelService *panel); 0077 static void ibus_panel_impanel_show_preedit_text(IBusPanelService *panel); 0078 static void ibus_panel_impanel_start_setup(IBusPanelService *panel); 0079 static void ibus_panel_impanel_state_changed(IBusPanelService *panel); 0080 0081 /* impanel signal handler function */ 0082 static void ibus_panel_impanel_exec_im_menu(IBusPanelImpanel *impanel); 0083 static void ibus_panel_impanel_exec_menu(IBusPanelImpanel *impanel, IBusPropList *prop_list); 0084 0085 static void impanel_set_engine(IBusPanelImpanel *impanel, const char *name); 0086 0087 static QByteArray ibus_property_to_propstr(IBusProperty *property, gboolean useSymbol = FALSE); 0088 0089 static QByteArray ibus_engine_desc_to_logo_propstr(IBusEngineDesc *engine); 0090 0091 void impanel_update_logo_by_engine(IBusPanelImpanel *impanel, IBusEngineDesc *engine_desc) 0092 { 0093 if (!impanel->conn) { 0094 return; 0095 } 0096 0097 QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc); 0098 0099 g_dbus_connection_emit_signal(impanel->conn, 0100 nullptr, 0101 "/kimpanel", 0102 "org.kde.kimpanel.inputmethod", 0103 "UpdateProperty", 0104 (g_variant_new("(s)", propstr.constData())), 0105 nullptr); 0106 } 0107 0108 void ibus_panel_impanel_set_bus(IBusPanelImpanel *impanel, IBusBus *bus) 0109 { 0110 impanel->bus = bus; 0111 } 0112 0113 void ibus_panel_impanel_set_app(IBusPanelImpanel *impanel, App *app) 0114 { 0115 impanel->app = app; 0116 } 0117 0118 void ibus_panel_impanel_accept(IBusPanelImpanel *impanel) 0119 { 0120 if (impanel->selected >= 0 && static_cast<size_t>(impanel->selected) < impanel->engineManager->length()) { 0121 impanel_set_engine(impanel, ibus_engine_desc_get_name(impanel->engineManager->engines()[impanel->selected])); 0122 impanel->selected = -1; 0123 } 0124 } 0125 0126 void ibus_panel_impanel_navigate(IBusPanelImpanel *impanel, gboolean start, gboolean forward) 0127 { 0128 if (start) { 0129 impanel->selected = -1; 0130 } 0131 0132 if (impanel->engineManager->length() < 2) { 0133 return; 0134 } 0135 0136 IBusEngineDesc *engine_desc = nullptr; 0137 if (impanel->selected < 0) { 0138 engine_desc = ibus_bus_get_global_engine(impanel->bus); 0139 } else if (static_cast<size_t>(impanel->selected) < impanel->engineManager->length()) { 0140 engine_desc = impanel->engineManager->engines()[impanel->selected]; 0141 g_object_ref(engine_desc); 0142 } 0143 0144 if (!engine_desc) { 0145 engine_desc = impanel->engineManager->engines()[0]; 0146 g_object_ref(engine_desc); 0147 } 0148 0149 if (engine_desc) { 0150 const char *name = impanel->engineManager->navigate(engine_desc, forward); 0151 impanel->selected = impanel->engineManager->getIndexByName(name); 0152 g_object_unref(engine_desc); 0153 } else { 0154 return; 0155 } 0156 0157 if (impanel->selected >= 0 && static_cast<size_t>(impanel->selected) < impanel->engineManager->length()) { 0158 ibus_panel_impanel_real_register_properties(impanel); 0159 } 0160 } 0161 0162 void ibus_panel_impanel_move_next(IBusPanelImpanel *impanel) 0163 { 0164 if (impanel->engineManager->length() >= 2) { 0165 impanel_set_engine(impanel, ibus_engine_desc_get_name(impanel->engineManager->engines()[1])); 0166 } 0167 } 0168 0169 static GDBusNodeInfo *introspection_data = nullptr; 0170 0171 static guint owner_id; 0172 0173 static const gchar introspection_xml[] = 0174 "<node>" 0175 " <interface name='org.kde.kimpanel.inputmethod'>" 0176 " <signal name='Enable'>" 0177 " <arg type='b' name='enable'/>" 0178 " </signal>" 0179 " <signal name='RegisterProperties'>" 0180 " <arg type='as' name='prop'/>" 0181 " </signal>" 0182 " <signal name='UpdateProperty'>" 0183 " <arg type='s' name='prop'/>" 0184 " </signal>" 0185 " <signal name='RemoveProperty'>" 0186 " <arg type='s' name='prop'/>" 0187 " </signal>" 0188 " <signal name='ShowAux'>" 0189 " <arg type='b' name='toshow'/>" 0190 " </signal>" 0191 " <signal name='ShowLookupTable'>" 0192 " <arg type='b' name='toshow'/>" 0193 " </signal>" 0194 " <signal name='ShowPreedit'>" 0195 " <arg type='b' name='toshow'/>" 0196 " </signal>" 0197 " <signal name='UpdateAux'>" 0198 " <arg type='s' name='text'/>" 0199 " <arg type='s' name='attr'/>" 0200 " </signal>" 0201 " <signal name='UpdateLookupTableCursor'>" 0202 " <arg type='i' name='pos'/>" 0203 " </signal>" 0204 " <signal name='UpdateLookupTable'>" 0205 " <arg type='as' name='labels'/>" 0206 " <arg type='as' name='candidates'/>" 0207 " <arg type='as' name='attrs'/>" 0208 " <arg type='b' name='hasprev'/>" 0209 " <arg type='b' name='hasnext'/>" 0210 " </signal>" 0211 " <signal name='UpdatePreeditCaret'>" 0212 " <arg type='i' name='pos'/>" 0213 " </signal>" 0214 " <signal name='UpdatePreeditText'>" 0215 " <arg type='s' name='text'/>" 0216 " <arg type='s' name='attr'/>" 0217 " </signal>" 0218 " <signal name='UpdateSpotLocation'>" 0219 " <arg type='i' name='x'/>" 0220 " <arg type='i' name='y'/>" 0221 " </signal>" 0222 " <signal name='ExecMenu'>" 0223 " <arg type='as' name='actions'/>" 0224 " </signal>" 0225 " </interface>" 0226 "</node>"; 0227 0228 static const char prop_sep[] = ":"; 0229 0230 static QByteArray ibus_property_args_to_propstr(const char *key, const char *label, const char *icon, const char *tooltip, const char *hint = "") 0231 { 0232 QByteArray propstr("/IBus/"); 0233 QByteArray str(key); 0234 str.replace(':', '!'); 0235 0236 App *app = static_cast<App *>(qApp); 0237 0238 propstr += str; 0239 propstr += prop_sep; 0240 propstr += QByteArray(label).replace(':', '-').constData(); 0241 propstr += prop_sep; 0242 propstr += app->normalizeIconName(QByteArray(icon).replace(':', '-')); 0243 propstr += prop_sep; 0244 propstr += QByteArray(tooltip).replace(':', '-').constData(); 0245 propstr += prop_sep; 0246 propstr += QByteArray(hint).replace(':', '-').constData(); 0247 0248 return propstr; 0249 } 0250 0251 static QByteArray ibus_engine_desc_to_logo_propstr(IBusEngineDesc *engine) 0252 { 0253 const gchar *label = "IBus"; 0254 const gchar *tooltip = ""; 0255 const gchar *icon = "input-keyboard"; 0256 0257 gchar xkbLabel[3]; 0258 if (engine) { 0259 const gchar *iconname = ibus_engine_desc_get_icon(engine); 0260 if (iconname && iconname[0]) { 0261 icon = iconname; 0262 } 0263 0264 if (strncmp("xkb:", ibus_engine_desc_get_name(engine), 4) == 0) { 0265 strncpy(xkbLabel, ibus_engine_desc_get_name(engine) + 4, 2); 0266 xkbLabel[2] = 0; 0267 int i = 0; 0268 while (xkbLabel[i]) { 0269 if (xkbLabel[i] == ':') { 0270 xkbLabel[i] = 0; 0271 } 0272 i++; 0273 } 0274 label = xkbLabel; 0275 icon = ""; 0276 } 0277 0278 const gchar *longname = ibus_engine_desc_get_longname(engine); 0279 if (longname && longname[0]) { 0280 tooltip = longname; 0281 } 0282 } 0283 0284 return ibus_property_args_to_propstr("Logo", label, icon, tooltip); 0285 } 0286 0287 static QByteArray ibus_property_to_propstr(IBusProperty *property, gboolean useSymbol) 0288 { 0289 const gchar *label = nullptr; 0290 const gchar *tooltip = ibus_text_get_text(ibus_property_get_tooltip(property)); 0291 const gchar *icon = ibus_property_get_icon(property); 0292 0293 if (useSymbol) { 0294 label = ibus_text_get_text(ibus_property_get_symbol(property)); 0295 if (!label || label[0] == '\0') { 0296 label = ibus_text_get_text(ibus_property_get_label(property)); 0297 } 0298 } else { 0299 label = ibus_text_get_text(ibus_property_get_label(property)); 0300 } 0301 0302 const char *hint = ""; 0303 if (ibus_property_get_prop_type(property) == PROP_TYPE_TOGGLE) { 0304 if (ibus_property_get_state(property) != PROP_STATE_CHECKED) { 0305 hint = "disable"; 0306 } 0307 } else if (ibus_property_get_prop_type(property) == PROP_TYPE_RADIO) { 0308 if (ibus_property_get_state(property) == PROP_STATE_CHECKED) { 0309 hint = "checked"; 0310 } 0311 } 0312 0313 return ibus_property_args_to_propstr(ibus_property_get_key(property), label, icon, tooltip, hint); 0314 } 0315 0316 static QByteArray ibus_engine_desc_args_to_propstr(const char *name, const char *language, const char *longname, const char *icon, const char *description) 0317 { 0318 QByteArray propstr("/IBus/Engine/"); 0319 QByteArray data(name); 0320 data.replace(':', '!'); 0321 propstr += data; 0322 propstr += prop_sep; 0323 if (language) { 0324 propstr += language; 0325 propstr += " - "; 0326 } 0327 propstr += longname; 0328 propstr += prop_sep; 0329 propstr += icon; 0330 propstr += prop_sep; 0331 propstr += description; 0332 return propstr; 0333 } 0334 0335 static QByteArray ibus_engine_desc_to_propstr(IBusEngineDesc *engine_desc) 0336 { 0337 return ibus_engine_desc_args_to_propstr(ibus_engine_desc_get_name(engine_desc), 0338 ibus_engine_desc_get_language(engine_desc), 0339 ibus_engine_desc_get_longname(engine_desc), 0340 ibus_engine_desc_get_icon(engine_desc), 0341 ibus_engine_desc_get_description(engine_desc)); 0342 } 0343 0344 static void impanel_get_default_engine(IBusPanelImpanel *impanel, char ***pengine_names, gsize *plen) 0345 { 0346 GList *engines = ibus_bus_list_engines(impanel->bus); 0347 if (!engines) { 0348 *pengine_names = g_new0(gchar *, 2); 0349 *plen = 1; 0350 (*pengine_names)[0] = g_strdup("xkb:us::eng"); 0351 return; 0352 } 0353 0354 QList<QByteArray> engineList; 0355 impanel->xkbLayoutManager->getLayout(); 0356 QStringList layouts = impanel->xkbLayoutManager->defaultLayout().split(QLatin1Char{','}); 0357 QStringList variants = impanel->xkbLayoutManager->defaultVariant().split(QLatin1Char{','}); 0358 0359 for (int i = 0; i < layouts.size(); i++) { 0360 QString variant; 0361 if (i < variants.size()) { 0362 variant = variants[i]; 0363 } 0364 0365 for (GList *engine = g_list_first(engines); engine != nullptr; engine = g_list_next(engine)) { 0366 IBusEngineDesc *desc = IBUS_ENGINE_DESC(engine->data); 0367 QByteArray name = ibus_engine_desc_get_name(desc); 0368 if (!name.startsWith("xkb:")) { 0369 continue; 0370 } 0371 0372 if (QLatin1String(ibus_engine_desc_get_layout(desc)) == layouts[i] && QLatin1String(ibus_engine_desc_get_layout_variant(desc)) == variant) { 0373 engineList << name; 0374 } 0375 } 0376 } 0377 const char *locale = setlocale(LC_CTYPE, nullptr); 0378 if (!locale) { 0379 locale = "C"; 0380 } 0381 0382 QStringList localeList = QString::fromLocal8Bit(locale).split(QLatin1Char{'.'}); 0383 const QString lang = localeList.size() > 0 ? localeList.at(0) : QString{}; 0384 0385 bool added = false; 0386 for (GList *engine = g_list_first(engines); engine != nullptr; engine = g_list_next(engine)) { 0387 IBusEngineDesc *desc = IBUS_ENGINE_DESC(engine->data); 0388 QByteArray name = ibus_engine_desc_get_name(desc); 0389 if (name.startsWith("xkb:")) { 0390 continue; 0391 } 0392 0393 if (QLatin1String(ibus_engine_desc_get_language(desc)) == lang && ibus_engine_desc_get_rank(desc) > 0) { 0394 engineList << name; 0395 added = true; 0396 } 0397 } 0398 0399 if (!added) { 0400 localeList = QString(lang).split(QLatin1Char{'_'}); 0401 QString _lang = localeList.size() > 0 ? localeList.at(0) : QString{}; 0402 0403 for (GList *engine = g_list_first(engines); engine != nullptr; engine = g_list_next(engine)) { 0404 IBusEngineDesc *desc = IBUS_ENGINE_DESC(engine->data); 0405 QByteArray name = ibus_engine_desc_get_name(desc); 0406 if (name.startsWith("xkb:")) { 0407 continue; 0408 } 0409 0410 if (QLatin1String(ibus_engine_desc_get_language(desc)) == _lang && ibus_engine_desc_get_rank(desc) > 0) { 0411 engineList << name; 0412 } 0413 } 0414 } 0415 0416 for (GList *engine = g_list_first(engines); engine != nullptr; engine = g_list_next(engine)) { 0417 IBusEngineDesc *desc = IBUS_ENGINE_DESC(engine->data); 0418 g_object_unref(desc); 0419 } 0420 0421 g_list_free(engines); 0422 0423 if (engineList.size() == 0) { 0424 *pengine_names = g_new0(gchar *, 2); 0425 *plen = 1; 0426 (*pengine_names)[0] = g_strdup("xkb:us::eng"); 0427 return; 0428 } else { 0429 *pengine_names = g_new0(gchar *, engineList.size() + 1); 0430 *plen = engineList.size(); 0431 size_t i = 0; 0432 for (const QByteArray &name : std::as_const(engineList)) { 0433 (*pengine_names)[i] = g_strdup(name.constData()); 0434 i++; 0435 } 0436 } 0437 } 0438 0439 bool contains(gchar **strlist, const gchar *str) 0440 { 0441 for (; strlist; ++strlist) { 0442 if (g_strcmp0(*strlist, str) == 0) 0443 return true; 0444 } 0445 return false; 0446 } 0447 0448 static void impanel_update_engines(IBusPanelImpanel *impanel, GVariant *var_engines) 0449 { 0450 gchar **engine_names = nullptr; 0451 size_t len = 0; 0452 if (var_engines) { 0453 engine_names = g_variant_dup_strv(var_engines, &len); 0454 } 0455 if (len == 0) { 0456 g_strfreev(engine_names); 0457 engine_names = nullptr; 0458 } 0459 0460 if (!engine_names) { 0461 impanel_get_default_engine(impanel, &engine_names, &len); 0462 GVariant *var = g_variant_new_strv(engine_names, len); 0463 g_settings_set_value(impanel->settings_general, "preload-engines", var); 0464 } 0465 0466 IBusEngineDesc **engines = ibus_bus_get_engines_by_names(impanel->bus, engine_names); 0467 0468 impanel->engineManager->setEngines(engines); 0469 if (engines && engines[0] 0470 && (!ibus_bus_get_global_engine(impanel->bus) || !contains(engine_names, ibus_engine_desc_get_name(ibus_bus_get_global_engine(impanel->bus))))) { 0471 ibus_bus_set_global_engine(impanel->bus, ibus_engine_desc_get_name(engines[0])); 0472 } 0473 g_strfreev(engine_names); 0474 0475 impanel->app->setDoGrab(len > 1); 0476 } 0477 0478 static void impanel_update_engines_order(IBusPanelImpanel *impanel, GVariant *var_engines) 0479 { 0480 const gchar **engine_names = nullptr; 0481 size_t len = 0; 0482 engine_names = g_variant_get_strv(var_engines, &len); 0483 if (len) { 0484 impanel->engineManager->setOrder(engine_names, len); 0485 0486 if (impanel->engineManager->engines()) { 0487 ibus_bus_set_global_engine(impanel->bus, ibus_engine_desc_get_name(impanel->engineManager->engines()[0])); 0488 } 0489 } 0490 g_free(engine_names); 0491 } 0492 0493 static void impanel_update_triggers(IBusPanelImpanel *impanel, GVariant *variant) 0494 { 0495 gchar **triggers = nullptr; 0496 size_t len = 0; 0497 if (variant) { 0498 triggers = g_variant_dup_strv(variant, &len); 0499 } 0500 if (len == 0) { 0501 g_strfreev(triggers); 0502 triggers = nullptr; 0503 } 0504 if (!triggers) { 0505 triggers = g_new0(gchar *, 2); 0506 len = 1; 0507 triggers[0] = g_strdup("<Super>space"); 0508 } 0509 0510 QList<QPair<uint, uint>> triggersList; 0511 for (size_t i = 0; i < len; i++) { 0512 guint key = 0; 0513 GdkModifierType mod = (GdkModifierType)0; 0514 _gtk_accelerator_parse(triggers[i], &key, &mod); 0515 if (key) { 0516 triggersList << std::make_pair(key, (uint)mod); 0517 } 0518 } 0519 impanel->app->setTriggerKeys(triggersList); 0520 } 0521 0522 static void impanel_update_use_system_keyboard_layout(IBusPanelImpanel *impanel, GVariant *variant) 0523 { 0524 impanel->useSystemKeyboardLayout = g_variant_get_boolean(variant); 0525 } 0526 static void impanel_update_use_global_engine(IBusPanelImpanel *impanel, GVariant *variant) 0527 { 0528 impanel->engineManager->setUseGlobalEngine(g_variant_get_boolean(variant)); 0529 } 0530 0531 static void impanel_update_latin_layouts(IBusPanelImpanel *impanel, GVariant *variant) 0532 { 0533 if (!variant) { 0534 return; 0535 } 0536 gsize length; 0537 const gchar **variants = g_variant_get_strv(variant, &length); 0538 0539 impanel->xkbLayoutManager->setLatinLayouts(variants, length); 0540 g_free(variants); 0541 } 0542 0543 static void impanel_settings_changed_callback(GSettings *settings, const gchar *key, gpointer user_data) 0544 { 0545 IBusPanelImpanel *impanel = ((IBusPanelImpanel *)user_data); 0546 gchar *schema = nullptr; 0547 GVariant *value = g_settings_get_value(settings, key); 0548 0549 g_object_get(G_OBJECT(settings), "schema", &schema, NULL); 0550 0551 if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "preload-engines") == 0) { 0552 impanel_update_engines(impanel, value); 0553 } else if (g_strcmp0(schema, IBUS_SCHEMA_HOTKEY) == 0 && g_strcmp0(key, "triggers") == 0) { 0554 impanel_update_triggers(impanel, value); 0555 } else if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "use-system-keyboard-layout") == 0) { 0556 impanel_update_use_system_keyboard_layout(impanel, value); 0557 } else if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "use-global-engine") == 0) { 0558 impanel_update_use_global_engine(impanel, value); 0559 } 0560 g_free(schema); 0561 } 0562 0563 static void impanel_exit_callback(GDBusConnection *connection, 0564 const gchar *sender_name, 0565 const gchar *object_path, 0566 const gchar *interface_name, 0567 const gchar *signal_name, 0568 GVariant *parameters, 0569 gpointer user_data) 0570 { 0571 Q_UNUSED(connection); 0572 Q_UNUSED(sender_name); 0573 Q_UNUSED(object_path); 0574 Q_UNUSED(interface_name); 0575 Q_UNUSED(signal_name); 0576 Q_UNUSED(parameters); 0577 IBusPanelImpanel *impanel = ((IBusPanelImpanel *)user_data); 0578 if (impanel->bus) { 0579 ibus_bus_exit(impanel->bus, FALSE); 0580 } 0581 } 0582 0583 static void impanel_panel_created_callback(GDBusConnection *connection, 0584 const gchar *sender_name, 0585 const gchar *object_path, 0586 const gchar *interface_name, 0587 const gchar *signal_name, 0588 GVariant *parameters, 0589 gpointer user_data) 0590 { 0591 Q_UNUSED(connection); 0592 Q_UNUSED(sender_name); 0593 Q_UNUSED(object_path); 0594 Q_UNUSED(interface_name); 0595 Q_UNUSED(signal_name); 0596 Q_UNUSED(parameters); 0597 IBusPanelImpanel *impanel = ((IBusPanelImpanel *)user_data); 0598 ibus_panel_impanel_real_register_properties(impanel); 0599 } 0600 0601 static void impanel_set_engine(IBusPanelImpanel *impanel, const char *name) 0602 { 0603 if (!name || !name[0]) { 0604 return; 0605 } 0606 if (ibus_bus_set_global_engine(impanel->bus, name)) { 0607 if (!impanel->useSystemKeyboardLayout) { 0608 IBusEngineDesc *engine_desc = ibus_bus_get_global_engine(impanel->bus); 0609 if (engine_desc) { 0610 impanel->xkbLayoutManager->setLayout(engine_desc); 0611 } 0612 g_object_unref(engine_desc); 0613 } 0614 impanel->engineManager->setCurrentEngine(name); 0615 } else { 0616 qDebug() << "set engine failed."; 0617 } 0618 } 0619 0620 static void impanel_trigger_property_callback(GDBusConnection *connection, 0621 const gchar *sender_name, 0622 const gchar *object_path, 0623 const gchar *interface_name, 0624 const gchar *signal_name, 0625 GVariant *parameters, 0626 gpointer user_data) 0627 { 0628 Q_UNUSED(connection); 0629 Q_UNUSED(sender_name); 0630 Q_UNUSED(object_path); 0631 Q_UNUSED(interface_name); 0632 Q_UNUSED(signal_name); 0633 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(user_data); 0634 gchar *s0 = nullptr; 0635 g_variant_get(parameters, "(s)", &s0); 0636 if (!s0 || strlen(s0) <= 6) 0637 return; 0638 QByteArray prop_key(s0 + 6); // +6 to skip "/IBus/" 0639 prop_key.replace('!', ':'); 0640 if (g_ascii_strncasecmp(prop_key.constData(), "Logo", 4) == 0) 0641 ibus_panel_impanel_exec_im_menu(impanel); 0642 else if (g_ascii_strncasecmp(prop_key.constData(), "Engine/", 7) == 0) { 0643 impanel_set_engine(impanel, prop_key.constData() + 7); 0644 } else { 0645 IBusProperty *property = impanel->propManager->property(prop_key.constData()); 0646 if (property) { 0647 IBusPropState newstate = ibus_property_get_state(property); 0648 switch (ibus_property_get_prop_type(property)) { 0649 case PROP_TYPE_RADIO: 0650 case PROP_TYPE_TOGGLE: 0651 if (ibus_property_get_prop_type(property) == PROP_TYPE_TOGGLE) { 0652 if (newstate == PROP_STATE_CHECKED) 0653 newstate = PROP_STATE_UNCHECKED; 0654 else if (newstate == PROP_STATE_UNCHECKED) 0655 newstate = PROP_STATE_CHECKED; 0656 } else if (ibus_property_get_prop_type(property) == PROP_TYPE_RADIO) { 0657 newstate = PROP_STATE_CHECKED; 0658 } 0659 Q_FALLTHROUGH(); 0660 case PROP_TYPE_NORMAL: 0661 ibus_property_set_state(property, newstate); 0662 ibus_panel_service_property_activate((IBusPanelService *)impanel, prop_key.constData(), newstate); 0663 break; 0664 case PROP_TYPE_MENU: 0665 ibus_panel_impanel_exec_menu(impanel, ibus_property_get_sub_props(property)); 0666 case PROP_TYPE_SEPARATOR: 0667 break; 0668 default: 0669 break; 0670 } 0671 } else { 0672 ibus_panel_service_property_activate((IBusPanelService *)impanel, prop_key.constData(), PROP_STATE_CHECKED); 0673 } 0674 } 0675 g_free(s0); 0676 } 0677 0678 static void impanel_select_candidate_callback(GDBusConnection *connection, 0679 const gchar *sender_name, 0680 const gchar *object_path, 0681 const gchar *interface_name, 0682 const gchar *signal_name, 0683 GVariant *parameters, 0684 gpointer user_data) 0685 { 0686 Q_UNUSED(connection); 0687 Q_UNUSED(sender_name); 0688 Q_UNUSED(object_path); 0689 Q_UNUSED(interface_name); 0690 Q_UNUSED(signal_name); 0691 0692 gint i; 0693 g_variant_get(parameters, "(i)", &i); 0694 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(user_data); 0695 ibus_panel_service_candidate_clicked((IBusPanelService *)impanel, i, 0, 0); 0696 } 0697 0698 static void impanel_prev_page_callback(GDBusConnection *connection, 0699 const gchar *sender_name, 0700 const gchar *object_path, 0701 const gchar *interface_name, 0702 const gchar *signal_name, 0703 GVariant *parameters, 0704 gpointer user_data) 0705 { 0706 Q_UNUSED(connection); 0707 Q_UNUSED(sender_name); 0708 Q_UNUSED(object_path); 0709 Q_UNUSED(interface_name); 0710 Q_UNUSED(signal_name); 0711 Q_UNUSED(parameters); 0712 0713 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(user_data); 0714 ibus_panel_service_page_up((IBusPanelService *)impanel); 0715 } 0716 0717 static void impanel_next_page_callback(GDBusConnection *connection, 0718 const gchar *sender_name, 0719 const gchar *object_path, 0720 const gchar *interface_name, 0721 const gchar *signal_name, 0722 GVariant *parameters, 0723 gpointer user_data) 0724 { 0725 Q_UNUSED(connection); 0726 Q_UNUSED(sender_name); 0727 Q_UNUSED(object_path); 0728 Q_UNUSED(interface_name); 0729 Q_UNUSED(signal_name); 0730 Q_UNUSED(parameters); 0731 0732 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(user_data); 0733 ibus_panel_service_page_down((IBusPanelService *)impanel); 0734 } 0735 0736 static void impanel_configure_callback(GDBusConnection *connection, 0737 const gchar *sender_name, 0738 const gchar *object_path, 0739 const gchar *interface_name, 0740 const gchar *signal_name, 0741 GVariant *parameters, 0742 gpointer user_data) 0743 { 0744 Q_UNUSED(connection); 0745 Q_UNUSED(sender_name); 0746 Q_UNUSED(object_path); 0747 Q_UNUSED(interface_name); 0748 Q_UNUSED(signal_name); 0749 Q_UNUSED(parameters); 0750 Q_UNUSED(user_data); 0751 pid_t pid = fork(); 0752 if (pid == 0) { 0753 execlp("ibus-setup", "ibus-setup", (char *)nullptr); 0754 exit(0); 0755 } 0756 } 0757 0758 static void on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) 0759 { 0760 Q_UNUSED(name); 0761 IBusPanelImpanel *impanel = ((IBusPanelImpanel *)user_data); 0762 impanel->conn = connection; 0763 0764 g_dbus_connection_register_object(connection, 0765 "/kimpanel", 0766 introspection_data->interfaces[0], 0767 nullptr, /*&interface_vtable*/ 0768 nullptr, /* user_data */ 0769 nullptr, /* user_data_free_func */ 0770 nullptr); /* GError** */ 0771 0772 g_dbus_connection_signal_subscribe(connection, 0773 "org.kde.impanel", 0774 "org.kde.impanel", 0775 "TriggerProperty", 0776 "/org/kde/impanel", 0777 nullptr, 0778 G_DBUS_SIGNAL_FLAGS_NONE, 0779 impanel_trigger_property_callback, 0780 user_data, 0781 nullptr); 0782 g_dbus_connection_signal_subscribe(connection, 0783 "org.kde.impanel", 0784 "org.kde.impanel", 0785 "SelectCandidate", 0786 "/org/kde/impanel", 0787 nullptr, 0788 G_DBUS_SIGNAL_FLAGS_NONE, 0789 impanel_select_candidate_callback, 0790 user_data, 0791 nullptr); 0792 g_dbus_connection_signal_subscribe(connection, 0793 "org.kde.impanel", 0794 "org.kde.impanel", 0795 "LookupTablePageUp", 0796 "/org/kde/impanel", 0797 nullptr, 0798 G_DBUS_SIGNAL_FLAGS_NONE, 0799 impanel_prev_page_callback, 0800 user_data, 0801 nullptr); 0802 g_dbus_connection_signal_subscribe(connection, 0803 "org.kde.impanel", 0804 "org.kde.impanel", 0805 "LookupTablePageDown", 0806 "/org/kde/impanel", 0807 nullptr, 0808 G_DBUS_SIGNAL_FLAGS_NONE, 0809 impanel_next_page_callback, 0810 user_data, 0811 nullptr); 0812 g_dbus_connection_signal_subscribe(connection, 0813 "org.kde.impanel", 0814 "org.kde.impanel", 0815 "PanelCreated", 0816 "/org/kde/impanel", 0817 nullptr, 0818 G_DBUS_SIGNAL_FLAGS_NONE, 0819 impanel_panel_created_callback, 0820 user_data, 0821 nullptr); 0822 g_dbus_connection_signal_subscribe(connection, 0823 "org.kde.impanel", 0824 "org.kde.impanel", 0825 "Exit", 0826 "/org/kde/impanel", 0827 nullptr, 0828 G_DBUS_SIGNAL_FLAGS_NONE, 0829 impanel_exit_callback, 0830 user_data, 0831 nullptr); 0832 g_dbus_connection_signal_subscribe(connection, 0833 "org.kde.impanel", 0834 "org.kde.impanel", 0835 "Configure", 0836 "/org/kde/impanel", 0837 nullptr, 0838 G_DBUS_SIGNAL_FLAGS_NONE, 0839 impanel_configure_callback, 0840 user_data, 0841 nullptr); 0842 0843 GVariant *var_engines = g_settings_get_value(impanel->settings_general, "preload-engines"); 0844 impanel_update_engines(impanel, var_engines); 0845 if (var_engines) { 0846 g_variant_unref(var_engines); 0847 } 0848 0849 var_engines = g_settings_get_value(impanel->settings_general, "engines-order"); 0850 if (var_engines) { 0851 impanel_update_engines_order(impanel, var_engines); 0852 g_variant_unref(var_engines); 0853 } 0854 0855 GVariant *var_triggers = g_settings_get_value(impanel->settings_hotkey, "triggers"); 0856 impanel_update_triggers(impanel, var_triggers); 0857 if (var_triggers) { 0858 g_variant_unref(var_triggers); 0859 } 0860 0861 GVariant *var_layouts = g_settings_get_value(impanel->settings_general, "xkb-latin-layouts"); 0862 if (var_layouts) { 0863 impanel_update_latin_layouts(impanel, var_layouts); 0864 g_variant_unref(var_layouts); 0865 } 0866 0867 GVariant *var = g_settings_get_value(impanel->settings_general, "use-system-keyboard-layout"); 0868 if (var) { 0869 impanel_update_use_system_keyboard_layout(impanel, var); 0870 g_variant_unref(var); 0871 } 0872 0873 var = g_settings_get_value(impanel->settings_general, "use-global-engine"); 0874 if (var) { 0875 impanel_update_use_global_engine(impanel, var); 0876 g_variant_unref(var); 0877 } 0878 0879 ibus_panel_impanel_real_register_properties(impanel); 0880 } 0881 0882 static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) 0883 { 0884 Q_UNUSED(connection); 0885 Q_UNUSED(name); 0886 Q_UNUSED(user_data); 0887 } 0888 0889 static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) 0890 { 0891 Q_UNUSED(connection); 0892 Q_UNUSED(name); 0893 Q_UNUSED(user_data); 0894 exit(1); 0895 } 0896 0897 G_DEFINE_TYPE(IBusPanelImpanel, ibus_panel_impanel, IBUS_TYPE_PANEL_SERVICE) 0898 0899 static void ibus_panel_impanel_class_init(IBusPanelImpanelClass *klass) 0900 { 0901 GObjectClass *object_class = G_OBJECT_CLASS(klass); 0902 0903 // clang-format off 0904 IBUS_OBJECT_CLASS (object_class)->destroy = (IBusObjectDestroyFunc) ibus_panel_impanel_destroy; 0905 IBUS_PANEL_SERVICE_CLASS (object_class)->focus_in = ibus_panel_impanel_focus_in; 0906 IBUS_PANEL_SERVICE_CLASS (object_class)->focus_out = ibus_panel_impanel_focus_out; 0907 IBUS_PANEL_SERVICE_CLASS (object_class)->register_properties = ibus_panel_impanel_register_properties; 0908 IBUS_PANEL_SERVICE_CLASS (object_class)->set_cursor_location = ibus_panel_impanel_set_cursor_location; 0909 IBUS_PANEL_SERVICE_CLASS (object_class)->update_auxiliary_text = ibus_panel_impanel_update_auxiliary_text; 0910 IBUS_PANEL_SERVICE_CLASS (object_class)->update_lookup_table = ibus_panel_impanel_update_lookup_table; 0911 IBUS_PANEL_SERVICE_CLASS (object_class)->update_preedit_text = ibus_panel_impanel_update_preedit_text; 0912 IBUS_PANEL_SERVICE_CLASS (object_class)->update_property = ibus_panel_impanel_update_property; 0913 IBUS_PANEL_SERVICE_CLASS (object_class)->cursor_down_lookup_table = ibus_panel_impanel_cursor_down_lookup_table; 0914 IBUS_PANEL_SERVICE_CLASS (object_class)->cursor_up_lookup_table = ibus_panel_impanel_cursor_up_lookup_table; 0915 IBUS_PANEL_SERVICE_CLASS (object_class)->hide_auxiliary_text = ibus_panel_impanel_hide_auxiliary_text; 0916 IBUS_PANEL_SERVICE_CLASS (object_class)->hide_language_bar = ibus_panel_impanel_hide_language_bar; 0917 IBUS_PANEL_SERVICE_CLASS (object_class)->hide_lookup_table = ibus_panel_impanel_hide_lookup_table; 0918 IBUS_PANEL_SERVICE_CLASS (object_class)->hide_preedit_text = ibus_panel_impanel_hide_preedit_text; 0919 IBUS_PANEL_SERVICE_CLASS (object_class)->page_down_lookup_table = ibus_panel_impanel_page_down_lookup_table; 0920 IBUS_PANEL_SERVICE_CLASS (object_class)->page_up_lookup_table = ibus_panel_impanel_page_up_lookup_table; 0921 IBUS_PANEL_SERVICE_CLASS (object_class)->reset = ibus_panel_impanel_reset; 0922 IBUS_PANEL_SERVICE_CLASS (object_class)->show_auxiliary_text = ibus_panel_impanel_show_auxiliary_text; 0923 IBUS_PANEL_SERVICE_CLASS (object_class)->show_language_bar = ibus_panel_impanel_show_language_bar; 0924 IBUS_PANEL_SERVICE_CLASS (object_class)->show_lookup_table = ibus_panel_impanel_show_lookup_table; 0925 IBUS_PANEL_SERVICE_CLASS (object_class)->show_preedit_text = ibus_panel_impanel_show_preedit_text; 0926 IBUS_PANEL_SERVICE_CLASS (object_class)->start_setup = ibus_panel_impanel_start_setup; 0927 IBUS_PANEL_SERVICE_CLASS (object_class)->state_changed = ibus_panel_impanel_state_changed; 0928 // clang-format on 0929 } 0930 0931 static void ibus_panel_impanel_init(IBusPanelImpanel *impanel) 0932 { 0933 impanel->bus = nullptr; 0934 impanel->app = nullptr; 0935 impanel->useSystemKeyboardLayout = false; 0936 impanel->selected = -1; 0937 0938 introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, nullptr); 0939 owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, 0940 "org.kde.kimpanel.inputmethod", 0941 G_BUS_NAME_OWNER_FLAGS_REPLACE, 0942 on_bus_acquired, 0943 on_name_acquired, 0944 on_name_lost, 0945 impanel, 0946 nullptr); 0947 0948 impanel->propManager = new PropertyManager; 0949 impanel->engineManager = new EngineManager; 0950 impanel->xkbLayoutManager = new XkbLayoutManager; 0951 impanel->settings_general = g_settings_new(IBUS_SCHEMA_GENERAL); 0952 impanel->settings_hotkey = g_settings_new(IBUS_SCHEMA_HOTKEY); 0953 g_signal_connect(impanel->settings_general, "changed", G_CALLBACK(impanel_settings_changed_callback), impanel); 0954 g_signal_connect(impanel->settings_hotkey, "changed", G_CALLBACK(impanel_settings_changed_callback), impanel); 0955 } 0956 0957 static void ibus_panel_impanel_destroy(IBusPanelImpanel *impanel) 0958 { 0959 delete impanel->propManager; 0960 impanel->propManager = nullptr; 0961 delete impanel->engineManager; 0962 impanel->engineManager = nullptr; 0963 delete impanel->xkbLayoutManager; 0964 impanel->xkbLayoutManager = nullptr; 0965 0966 g_signal_handlers_disconnect_by_func(impanel->settings_general, (gpointer)impanel_settings_changed_callback, impanel); 0967 g_signal_handlers_disconnect_by_func(impanel->settings_hotkey, (gpointer)impanel_settings_changed_callback, impanel); 0968 g_clear_object(&impanel->settings_general); 0969 g_clear_object(&impanel->settings_hotkey); 0970 0971 g_bus_unown_name(owner_id); 0972 g_dbus_node_info_unref(introspection_data); 0973 0974 IBUS_OBJECT_CLASS(ibus_panel_impanel_parent_class)->destroy((IBusObject *)impanel); 0975 } 0976 0977 static void ibus_panel_impanel_focus_in(IBusPanelService *panel, const gchar *input_context_path) 0978 { 0979 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 0980 if (impanel->app->keyboardGrabbed()) { 0981 return; 0982 } 0983 0984 auto engine_desc = ibus_bus_get_global_engine(impanel->bus); 0985 if (engine_desc) { 0986 impanel_update_logo_by_engine(impanel, engine_desc); 0987 g_object_unref(engine_desc); 0988 } 0989 0990 impanel->engineManager->setCurrentContext(input_context_path); 0991 if (!impanel->engineManager->useGlobalEngine()) { 0992 impanel_set_engine(impanel, impanel->engineManager->currentEngine().toUtf8().constData()); 0993 } 0994 } 0995 0996 static void ibus_panel_impanel_focus_out(IBusPanelService *panel, const gchar *input_context_path) 0997 { 0998 Q_UNUSED(panel); 0999 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 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 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 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 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 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 1117 GVariantBuilder builder_labels; 1118 GVariantBuilder builder_candidates; 1119 GVariantBuilder builder_attrs; 1120 g_variant_builder_init(&builder_labels, G_VARIANT_TYPE("as")); 1121 g_variant_builder_init(&builder_candidates, G_VARIANT_TYPE("as")); 1122 g_variant_builder_init(&builder_attrs, G_VARIANT_TYPE("as")); 1123 1124 const gchar *attr = ""; 1125 for (i = start; i < end; i++) { 1126 g_snprintf(label[i - start], 4, "%d", (i - start + 1) % 10); 1127 // NOTE ibus always return NULL for ibus_lookup_table_get_label 1128 // label = ibus_lookup_table_get_label(lookup_table, i)->text; 1129 g_variant_builder_add(&builder_labels, "s", label[i - start]); 1130 1131 const gchar *candidate = ibus_text_get_text(ibus_lookup_table_get_candidate(lookup_table, i)); 1132 g_variant_builder_add(&builder_candidates, "s", candidate); 1133 1134 g_variant_builder_add(&builder_attrs, "s", attr); 1135 } 1136 1137 gboolean has_prev = 1; 1138 gboolean has_next = 1; 1139 1140 guint cursor_pos_in_page; 1141 if (ibus_lookup_table_is_cursor_visible(lookup_table)) 1142 cursor_pos_in_page = cursor_pos % page_size; 1143 else 1144 cursor_pos_in_page = -1; 1145 1146 gint orientation = ibus_lookup_table_get_orientation(lookup_table); 1147 if (orientation == IBUS_ORIENTATION_HORIZONTAL) { 1148 orientation = 2; 1149 } else if (orientation == IBUS_ORIENTATION_VERTICAL) { 1150 orientation = 1; 1151 } else { 1152 orientation = 0; 1153 } 1154 1155 g_dbus_connection_call( 1156 impanel->conn, 1157 "org.kde.impanel", 1158 "/org/kde/impanel", 1159 "org.kde.impanel2", 1160 "SetLookupTable", 1161 (g_variant_new("(asasasbbii)", &builder_labels, &builder_candidates, &builder_attrs, has_prev, has_next, cursor_pos_in_page, orientation)), 1162 nullptr, 1163 G_DBUS_CALL_FLAGS_NONE, 1164 -1, 1165 nullptr, 1166 nullptr, 1167 nullptr); 1168 1169 if (visible == 0) 1170 ibus_panel_impanel_hide_lookup_table(panel); 1171 else 1172 ibus_panel_impanel_show_lookup_table(panel); 1173 } 1174 1175 static void ibus_panel_impanel_update_preedit_text(IBusPanelService *panel, IBusText *text, guint cursor_pos, gboolean visible) 1176 { 1177 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1178 if (!impanel->conn) 1179 return; 1180 1181 const gchar *t = ibus_text_get_text(text); 1182 const gchar *attr = ""; 1183 1184 g_dbus_connection_emit_signal(impanel->conn, 1185 nullptr, 1186 "/kimpanel", 1187 "org.kde.kimpanel.inputmethod", 1188 "UpdatePreeditText", 1189 (g_variant_new("(ss)", t, attr)), 1190 nullptr); 1191 1192 g_dbus_connection_emit_signal(impanel->conn, 1193 nullptr, 1194 "/kimpanel", 1195 "org.kde.kimpanel.inputmethod", 1196 "UpdatePreeditCaret", 1197 (g_variant_new("(i)", cursor_pos)), 1198 nullptr); 1199 1200 if (visible == 0) 1201 ibus_panel_impanel_hide_preedit_text(panel); 1202 else 1203 ibus_panel_impanel_show_preedit_text(panel); 1204 } 1205 1206 static void ibus_panel_impanel_update_property(IBusPanelService *panel, IBusProperty *prop) 1207 { 1208 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1209 if (!impanel->conn) 1210 return; 1211 1212 impanel->propManager->updateProperty(prop); 1213 1214 QByteArray propstr = ibus_property_to_propstr(prop, TRUE); 1215 1216 g_dbus_connection_emit_signal(impanel->conn, 1217 nullptr, 1218 "/kimpanel", 1219 "org.kde.kimpanel.inputmethod", 1220 "UpdateProperty", 1221 (g_variant_new("(s)", propstr.constData())), 1222 nullptr); 1223 } 1224 1225 static void ibus_panel_impanel_cursor_down_lookup_table(IBusPanelService *panel) 1226 { 1227 Q_UNUSED(panel); 1228 } 1229 1230 static void ibus_panel_impanel_cursor_up_lookup_table(IBusPanelService *panel) 1231 { 1232 Q_UNUSED(panel); 1233 } 1234 1235 static void ibus_panel_impanel_hide_auxiliary_text(IBusPanelService *panel) 1236 { 1237 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1238 if (!impanel->conn) 1239 return; 1240 gboolean toShow = 0; 1241 1242 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new("(b)", toShow)), nullptr); 1243 } 1244 1245 static void ibus_panel_impanel_hide_language_bar(IBusPanelService *panel) 1246 { 1247 Q_UNUSED(panel); 1248 } 1249 1250 static void ibus_panel_impanel_hide_lookup_table(IBusPanelService *panel) 1251 { 1252 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1253 if (!impanel->conn) 1254 return; 1255 gboolean toShow = 0; 1256 1257 g_dbus_connection_emit_signal(impanel->conn, 1258 nullptr, 1259 "/kimpanel", 1260 "org.kde.kimpanel.inputmethod", 1261 "ShowLookupTable", 1262 (g_variant_new("(b)", toShow)), 1263 nullptr); 1264 } 1265 1266 static void ibus_panel_impanel_hide_preedit_text(IBusPanelService *panel) 1267 { 1268 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1269 if (!impanel->conn) 1270 return; 1271 gboolean toShow = 0; 1272 1273 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new("(b)", toShow)), nullptr); 1274 } 1275 1276 static void ibus_panel_impanel_page_down_lookup_table(IBusPanelService *panel) 1277 { 1278 Q_UNUSED(panel); 1279 } 1280 1281 static void ibus_panel_impanel_page_up_lookup_table(IBusPanelService *panel) 1282 { 1283 Q_UNUSED(panel); 1284 } 1285 1286 static void ibus_panel_impanel_reset(IBusPanelService *panel) 1287 { 1288 Q_UNUSED(panel); 1289 } 1290 1291 static void ibus_panel_impanel_show_auxiliary_text(IBusPanelService *panel) 1292 { 1293 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1294 if (!impanel->conn) 1295 return; 1296 gboolean toShow = 1; 1297 1298 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new("(b)", toShow)), nullptr); 1299 } 1300 1301 static void ibus_panel_impanel_show_language_bar(IBusPanelService *panel) 1302 { 1303 Q_UNUSED(panel); 1304 } 1305 1306 static void ibus_panel_impanel_show_lookup_table(IBusPanelService *panel) 1307 { 1308 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1309 if (!impanel->conn) 1310 return; 1311 gboolean toShow = 1; 1312 1313 g_dbus_connection_emit_signal(impanel->conn, 1314 nullptr, 1315 "/kimpanel", 1316 "org.kde.kimpanel.inputmethod", 1317 "ShowLookupTable", 1318 (g_variant_new("(b)", toShow)), 1319 nullptr); 1320 } 1321 1322 static void ibus_panel_impanel_show_preedit_text(IBusPanelService *panel) 1323 { 1324 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1325 if (!impanel->conn) 1326 return; 1327 gboolean toShow = 1; 1328 1329 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new("(b)", toShow)), nullptr); 1330 } 1331 1332 static void ibus_panel_impanel_start_setup(IBusPanelService *panel) 1333 { 1334 Q_UNUSED(panel); 1335 } 1336 1337 static void ibus_panel_impanel_state_changed(IBusPanelService *panel) 1338 { 1339 IBusPanelImpanel *impanel = IBUS_PANEL_IMPANEL(panel); 1340 if (!impanel->conn) 1341 return; 1342 1343 if (impanel->app->keyboardGrabbed()) { 1344 return; 1345 } 1346 1347 IBusEngineDesc *engine_desc = ibus_bus_get_global_engine(impanel->bus); 1348 if (!engine_desc) { 1349 return; 1350 } 1351 1352 impanel_update_logo_by_engine(impanel, engine_desc); 1353 1354 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "Enable", (g_variant_new("(b)", TRUE)), nullptr); 1355 1356 impanel->engineManager->moveToFirst(engine_desc); 1357 QStringList engineList = impanel->engineManager->engineOrder(); 1358 1359 gchar **engine_names = g_new0(gchar *, engineList.size() + 1); 1360 size_t i = 0; 1361 for (const QString &name : std::as_const(engineList)) { 1362 engine_names[i] = g_strdup(name.toUtf8().constData()); 1363 i++; 1364 } 1365 1366 GVariant *var = g_variant_new_strv(engine_names, engineList.size()); 1367 g_settings_set_value(impanel->settings_general, "engines-order", var); 1368 g_strfreev(engine_names); 1369 g_object_unref(engine_desc); 1370 } 1371 1372 static void ibus_panel_impanel_exec_menu(IBusPanelImpanel *impanel, IBusPropList *prop_list) 1373 { 1374 if (!impanel->conn) 1375 return; 1376 1377 GVariantBuilder builder; 1378 g_variant_builder_init(&builder, G_VARIANT_TYPE("as")); 1379 1380 int i = 0; 1381 while (true) { 1382 IBusProperty *prop = ibus_prop_list_get(prop_list, i); 1383 if (!prop) 1384 break; 1385 QByteArray propstr = ibus_property_to_propstr(prop); 1386 g_variant_builder_add(&builder, "s", propstr.constData()); 1387 i++; 1388 } 1389 1390 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new("(as)", &builder)), nullptr); 1391 } 1392 1393 static void ibus_panel_impanel_exec_im_menu(IBusPanelImpanel *impanel) 1394 { 1395 if (!impanel->conn) 1396 return; 1397 1398 GVariantBuilder builder; 1399 g_variant_builder_init(&builder, G_VARIANT_TYPE("as")); 1400 1401 IBusEngineDesc **engines = impanel->engineManager->engines(); 1402 if (engines) { 1403 int i = 0; 1404 while (engines[i]) { 1405 QByteArray propstr = ibus_engine_desc_to_propstr(engines[i]); 1406 g_variant_builder_add(&builder, "s", propstr.constData()); 1407 i++; 1408 } 1409 } 1410 1411 g_dbus_connection_emit_signal(impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new("(as)", &builder)), nullptr); 1412 } 1413 1414 IBusPanelImpanel *ibus_panel_impanel_new(GDBusConnection *connection) 1415 { 1416 IBusPanelImpanel *panel; 1417 panel = (IBusPanelImpanel *)g_object_new(IBUS_TYPE_PANEL_IMPANEL, "object-path", IBUS_PATH_PANEL, "connection", connection, NULL); 1418 return panel; 1419 }