diff --git a/applets/kimpanel/backend/ibus/ibus15/panel.cpp b/applets/kimpanel/backend/ibus/ibus15/panel.cpp index 798d1c11f..69a7c1349 100644 --- a/applets/kimpanel/backend/ibus/ibus15/panel.cpp +++ b/applets/kimpanel/backend/ibus/ibus15/panel.cpp @@ -1,1558 +1,1563 @@ /* * Copyright (C) 2011-2012 Ni Hui * Copyright (C) 2013-2014 Weng Xuetian * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "panel.h" #include "propertymanager.h" #include "enginemanager.h" #include "xkblayoutmanager.h" #include "app.h" #include "gtkaccelparse_p.h" #ifndef DBUS_ERROR_FAILED #define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed" #endif /* DBUS_ERROR_FAILED */ #define IBUS_SCHEMA_GENERAL "org.freedesktop.ibus.general" #define IBUS_SCHEMA_HOTKEY "org.freedesktop.ibus.general.hotkey" #define IBUS_SCHEMA_PANEL "org.freedesktop.ibus.panel" typedef struct _IBusPanelImpanelClass IBusPanelImpanelClass; struct _IBusPanelImpanel { IBusPanelService parent; IBusBus *bus; GDBusConnection *conn; PropertyManager* propManager; EngineManager* engineManager; XkbLayoutManager* xkbLayoutManager; App* app; gboolean useSystemKeyboardLayout; int selected; GSettings *settings_general; GSettings *settings_hotkey; }; struct _IBusPanelImpanelClass { IBusPanelServiceClass parent; }; /* functions prototype */ static void ibus_panel_impanel_class_init (IBusPanelImpanelClass *klass); static void ibus_panel_impanel_init (IBusPanelImpanel *impanel); static void ibus_panel_impanel_destroy (IBusPanelImpanel *impanel); static void ibus_panel_impanel_focus_in (IBusPanelService *panel, const gchar *input_context_path); static void ibus_panel_impanel_focus_out (IBusPanelService *panel, const gchar *input_context_path); static void ibus_panel_impanel_register_properties (IBusPanelService *panel, IBusPropList *prop_list); static void ibus_panel_impanel_real_register_properties (IBusPanelImpanel *impanel); static void ibus_panel_impanel_set_cursor_location (IBusPanelService *panel, gint x, gint y, gint w, gint h); static void ibus_panel_impanel_update_auxiliary_text (IBusPanelService *panel, IBusText *text, gboolean visible); static void ibus_panel_impanel_update_lookup_table (IBusPanelService *panel, IBusLookupTable *lookup_table, gboolean visible); static void ibus_panel_impanel_update_preedit_text (IBusPanelService *panel, IBusText *text, guint cursor_pos, gboolean visible); static void ibus_panel_impanel_update_property (IBusPanelService *panel, IBusProperty *prop); static void ibus_panel_impanel_cursor_down_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_cursor_up_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_hide_auxiliary_text (IBusPanelService *panel); static void ibus_panel_impanel_hide_language_bar (IBusPanelService *panel); static void ibus_panel_impanel_hide_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_hide_preedit_text (IBusPanelService *panel); static void ibus_panel_impanel_page_down_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_page_up_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_reset (IBusPanelService *panel); static void ibus_panel_impanel_show_auxiliary_text (IBusPanelService *panel); static void ibus_panel_impanel_show_language_bar (IBusPanelService *panel); static void ibus_panel_impanel_show_lookup_table (IBusPanelService *panel); static void ibus_panel_impanel_show_preedit_text (IBusPanelService *panel); static void ibus_panel_impanel_start_setup (IBusPanelService *panel); static void ibus_panel_impanel_state_changed (IBusPanelService *panel); /* impanel signal handler function */ static void ibus_panel_impanel_exec_im_menu (IBusPanelImpanel* impanel); static void ibus_panel_impanel_exec_menu (IBusPanelImpanel* impanel, IBusPropList* prop_list); static void impanel_set_engine(IBusPanelImpanel* impanel, const char* name); static QByteArray ibus_property_to_propstr (IBusProperty *property, gboolean useSymbol = FALSE); static QByteArray ibus_engine_desc_to_logo_propstr(IBusEngineDesc* engine); void impanel_update_logo_by_engine(IBusPanelImpanel* impanel, IBusEngineDesc* engine_desc) { if (!impanel->conn) { return; } QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc); g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty", (g_variant_new ("(s)", propstr.constData())), nullptr); } void ibus_panel_impanel_set_bus (IBusPanelImpanel *impanel, IBusBus *bus) { impanel->bus = bus; } void ibus_panel_impanel_set_app(IBusPanelImpanel* impanel, App* app) { impanel->app = app; } void ibus_panel_impanel_accept(IBusPanelImpanel* impanel) { if (impanel->selected >= 0 && static_cast(impanel->selected) < impanel->engineManager->length()) { impanel_set_engine(impanel, ibus_engine_desc_get_name(impanel->engineManager->engines()[impanel->selected])); impanel->selected = -1; } } void ibus_panel_impanel_navigate(IBusPanelImpanel* impanel, gboolean start, gboolean forward) { if (start) { impanel->selected = -1; } if (impanel->engineManager->length() < 2) { return; } IBusEngineDesc* engine_desc = nullptr; if (impanel->selected < 0) { engine_desc = ibus_bus_get_global_engine(impanel->bus); } else if (static_cast(impanel->selected) < impanel->engineManager->length()) { engine_desc = impanel->engineManager->engines()[impanel->selected]; g_object_ref(engine_desc); } if (!engine_desc) { engine_desc = impanel->engineManager->engines()[0]; g_object_ref(engine_desc); } if (engine_desc) { const char* name = impanel->engineManager->navigate(engine_desc, forward); impanel->selected = impanel->engineManager->getIndexByName(name); g_object_unref(engine_desc); } else { return; } if (impanel->selected >= 0 && static_cast(impanel->selected) < impanel->engineManager->length()) { ibus_panel_impanel_real_register_properties(impanel); } } void ibus_panel_impanel_move_next(IBusPanelImpanel* impanel) { if (impanel->engineManager->length() >= 2) { impanel_set_engine(impanel, ibus_engine_desc_get_name(impanel->engineManager->engines()[1])); } } static GDBusNodeInfo *introspection_data = nullptr; static guint owner_id; static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static const char prop_sep[] = ":"; static QByteArray ibus_property_args_to_propstr (const char *key, const char *label, const char *icon, const char *tooltip, const char *hint = "") { QByteArray propstr("/IBus/"); QByteArray str(key); str.replace(':', '!'); App* app = static_cast(qApp); propstr += str; propstr += prop_sep; propstr += QByteArray(label).replace(':', '-').constData(); propstr += prop_sep; propstr += app->normalizeIconName(QByteArray(icon).replace(':', '-')); propstr += prop_sep; propstr += QByteArray(tooltip).replace(':', '-').constData(); propstr += prop_sep; propstr += QByteArray(hint).replace(':', '-').constData(); return propstr; } static QByteArray ibus_engine_desc_to_logo_propstr(IBusEngineDesc* engine) { const gchar* label = "IBus"; const gchar* tooltip = ""; const gchar* icon = "input-keyboard"; gchar xkbLabel[3]; if (engine) { const gchar* iconname = ibus_engine_desc_get_icon(engine); if (iconname && iconname[0]) { icon = iconname; } if (strncmp("xkb:", ibus_engine_desc_get_name(engine), 4) == 0) { strncpy(xkbLabel, ibus_engine_desc_get_name(engine) + 4, 2); xkbLabel[2] = 0; int i = 0; while (xkbLabel[i]) { if (xkbLabel[i] == ':') { xkbLabel[i] = 0; } i++; } label = xkbLabel; icon = ""; } const gchar* longname = ibus_engine_desc_get_longname(engine); if (longname && longname[0]) { tooltip = longname; } } return ibus_property_args_to_propstr("Logo", label, icon, tooltip); } static QByteArray ibus_property_to_propstr (IBusProperty *property, gboolean useSymbol) { const gchar* label = nullptr; const gchar* tooltip = ibus_text_get_text (ibus_property_get_tooltip (property)); const gchar* icon = ibus_property_get_icon (property); if (useSymbol) { label = ibus_text_get_text(ibus_property_get_symbol (property)); if (!label || label[0] == '\0') { label = ibus_text_get_text(ibus_property_get_label(property)); } } else { label = ibus_text_get_text(ibus_property_get_label(property)); } const char* hint = ""; if (ibus_property_get_prop_type(property) == PROP_TYPE_TOGGLE) { if (ibus_property_get_state(property) != PROP_STATE_CHECKED) { hint = "disable"; } } else if (ibus_property_get_prop_type(property) == PROP_TYPE_RADIO) { if (ibus_property_get_state(property) == PROP_STATE_CHECKED) { hint = "checked"; } } return ibus_property_args_to_propstr(ibus_property_get_key (property), label, icon, tooltip, hint); } static QByteArray ibus_engine_desc_args_to_propstr (const char *name, const char *language, const char *longname, const char *icon, const char *description) { QByteArray propstr("/IBus/Engine/"); QByteArray data(name); data.replace(':', '!'); propstr += data; propstr += prop_sep; if (language) { propstr += language; propstr += " - "; } propstr += longname; propstr += prop_sep; propstr += icon; propstr += prop_sep; propstr += description; return propstr; } static QByteArray ibus_engine_desc_to_propstr (IBusEngineDesc *engine_desc) { return ibus_engine_desc_args_to_propstr(ibus_engine_desc_get_name(engine_desc), ibus_engine_desc_get_language(engine_desc), ibus_engine_desc_get_longname(engine_desc), ibus_engine_desc_get_icon(engine_desc), ibus_engine_desc_get_description(engine_desc)); } static void impanel_get_default_engine(IBusPanelImpanel* impanel, char*** pengine_names, gsize* plen) { GList* engines = ibus_bus_list_engines(impanel->bus); if (!engines) { *pengine_names = g_new0 (gchar*, 2); *plen = 1; (*pengine_names)[0] = g_strdup ("xkb:us::eng"); return; } QList engineList; impanel->xkbLayoutManager->getLayout(); QStringList layouts = impanel->xkbLayoutManager->defaultLayout().split(','); QStringList variants = impanel->xkbLayoutManager->defaultVariant().split(','); for (int i = 0; i < layouts.size(); i ++ ) { QString variant; if (i < variants.size()) { variant = variants[i]; } for (GList* engine = g_list_first(engines); engine != nullptr ; engine = g_list_next(engine)) { IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data); QByteArray name = ibus_engine_desc_get_name(desc); if (!name.startsWith("xkb:")) { continue; } if (QLatin1String(ibus_engine_desc_get_layout(desc)) == layouts[i] && QLatin1String(ibus_engine_desc_get_layout_variant(desc)) == variant) { engineList << name; } } } const char* locale = setlocale(LC_CTYPE, nullptr); if (!locale) { locale = "C"; } QStringList localeList = QString(locale).split('.'); QString lang = localeList.size() > 0 ? localeList[0] : ""; bool added = false; for (GList* engine = g_list_first(engines); engine != nullptr ; engine = g_list_next(engine)) { IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data); QByteArray name = ibus_engine_desc_get_name(desc); if (name.startsWith("xkb:")) { continue; } if (QLatin1String(ibus_engine_desc_get_language(desc)) == lang && ibus_engine_desc_get_rank(desc) > 0) { engineList << name; added = true; } } if (!added) { localeList = QString(lang).split('_'); QString lang = localeList.size() > 0 ? localeList[0] : ""; for (GList* engine = g_list_first(engines); engine != nullptr ; engine = g_list_next(engine)) { IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data); QByteArray name = ibus_engine_desc_get_name(desc); if (name.startsWith("xkb:")) { continue; } if (QLatin1String(ibus_engine_desc_get_language(desc)) == lang && ibus_engine_desc_get_rank(desc) > 0) { engineList << name; } } } for (GList* engine = g_list_first(engines); engine != nullptr ; engine = g_list_next(engine)) { IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data); g_object_unref(desc); } g_list_free(engines); if (engineList.size() == 0) { *pengine_names = g_new0 (gchar*, 2); *plen = 1; (*pengine_names)[0] = g_strdup ("xkb:us::eng"); return; } else { *pengine_names = g_new0 (gchar*, engineList.size() + 1); *plen = engineList.size(); size_t i = 0; Q_FOREACH(const QByteArray& name, engineList) { (*pengine_names)[i] = g_strdup (name.constData()); i ++; } } } static void impanel_update_engines(IBusPanelImpanel* impanel, GVariant* var_engines) { gchar** engine_names = nullptr; size_t len = 0; if (var_engines) { engine_names = g_variant_dup_strv(var_engines, &len); } if (len == 0) { g_strfreev(engine_names); engine_names = nullptr; } if (!engine_names) { impanel_get_default_engine(impanel, &engine_names, &len); GVariant* var = g_variant_new_strv(engine_names, len); g_settings_set_value(impanel->settings_general, "preload-engines", var); } IBusEngineDesc** engines = ibus_bus_get_engines_by_names(impanel->bus, engine_names); g_strfreev(engine_names); impanel->engineManager->setEngines(engines); if (engines && engines[0]) { ibus_bus_set_global_engine(impanel->bus, ibus_engine_desc_get_name(engines[0])); } impanel->app->setDoGrab(len > 1); } static void impanel_update_engines_order(IBusPanelImpanel* impanel, GVariant* var_engines) { const gchar** engine_names = nullptr; size_t len = 0; engine_names = g_variant_get_strv(var_engines, &len); if (len) { impanel->engineManager->setOrder(engine_names, len); if (impanel->engineManager->engines()) { ibus_bus_set_global_engine(impanel->bus, ibus_engine_desc_get_name(impanel->engineManager->engines()[0])); } } g_free(engine_names); } static void impanel_update_triggers(IBusPanelImpanel* impanel, GVariant* variant) { gchar** triggers = nullptr; size_t len = 0; if (variant) { triggers = g_variant_dup_strv(variant, &len); } if (len == 0) { g_strfreev(triggers); triggers = nullptr; } if (!triggers) { triggers = g_new0 (gchar*, 2); len = 1; triggers[0] = g_strdup ("space"); } QList > triggersList; for (size_t i = 0; i < len; i ++) { guint key = 0; GdkModifierType mod = (GdkModifierType) 0; _gtk_accelerator_parse(triggers[i], &key, &mod); if (key) { triggersList << qMakePair(key, (uint) mod); } } impanel->app->setTriggerKeys(triggersList); } static void impanel_update_use_system_keyboard_layout(IBusPanelImpanel* impanel, GVariant* variant) { impanel->useSystemKeyboardLayout = g_variant_get_boolean(variant); } static void impanel_update_use_global_engine(IBusPanelImpanel* impanel, GVariant* variant) { impanel->engineManager->setUseGlobalEngine(g_variant_get_boolean(variant)); } static void impanel_update_latin_layouts(IBusPanelImpanel* impanel, GVariant* variant) { if (!variant) { return; } gsize length; const gchar** variants = g_variant_get_strv(variant, &length); impanel->xkbLayoutManager->setLatinLayouts(variants, length); g_free(variants); } static void impanel_settings_changed_callback (GSettings* settings, const gchar* key, gpointer user_data) { IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); gchar *schema = nullptr; GVariant *value = g_settings_get_value (settings, key); g_object_get(G_OBJECT(settings), "schema", &schema, NULL); if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "preload-engines") == 0) { impanel_update_engines(impanel, value); } else if (g_strcmp0(schema, IBUS_SCHEMA_HOTKEY) == 0 && g_strcmp0(key, "triggers") == 0) { impanel_update_triggers(impanel, value); } else if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "use-system-keyboard-layout") == 0) { impanel_update_use_system_keyboard_layout(impanel, value); } else if (g_strcmp0(schema, IBUS_SCHEMA_GENERAL) == 0 && g_strcmp0(key, "use-global-engine") == 0) { impanel_update_use_global_engine(impanel, value); } g_free (schema); } static void 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) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); if (impanel->bus) { ibus_bus_exit(impanel->bus, FALSE); } } static void 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) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); ibus_panel_impanel_real_register_properties(impanel); } static void impanel_set_engine(IBusPanelImpanel* impanel, const char* name) { if (!name || !name[0]) { return; } if (ibus_bus_set_global_engine(impanel->bus, name)) { if (!impanel->useSystemKeyboardLayout) { IBusEngineDesc* engine_desc = ibus_bus_get_global_engine(impanel->bus); if (engine_desc) { impanel->xkbLayoutManager->setLayout(engine_desc); } g_object_unref(engine_desc); } impanel->engineManager->setCurrentEngine(name); } else { qDebug() << "set engine failed."; } } static void 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) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(user_data); gchar *s0 = nullptr; g_variant_get (parameters, "(s)", &s0); if (!s0 || strlen(s0) <= 6) return; QByteArray prop_key(s0 + 6);// +6 to skip "/IBus/" prop_key.replace('!', ':'); if (g_ascii_strncasecmp (prop_key.constData(), "Logo", 4) == 0) ibus_panel_impanel_exec_im_menu(impanel); else if (g_ascii_strncasecmp (prop_key.constData(), "Engine/", 7) == 0) { impanel_set_engine(impanel, prop_key.constData() + 7); } else { IBusProperty* property = impanel->propManager->property(prop_key.constData()); if (property) { IBusPropState newstate = ibus_property_get_state(property); switch (ibus_property_get_prop_type(property)) { case PROP_TYPE_RADIO: case PROP_TYPE_TOGGLE: if (ibus_property_get_prop_type(property) == PROP_TYPE_TOGGLE) { if (newstate == PROP_STATE_CHECKED) newstate = PROP_STATE_UNCHECKED; else if (newstate == PROP_STATE_UNCHECKED) newstate = PROP_STATE_CHECKED; } else if (ibus_property_get_prop_type(property) == PROP_TYPE_RADIO) { newstate = PROP_STATE_CHECKED; } case PROP_TYPE_NORMAL: ibus_property_set_state(property, newstate); ibus_panel_service_property_activate((IBusPanelService *)impanel, prop_key.constData(), newstate); break; case PROP_TYPE_MENU: ibus_panel_impanel_exec_menu(impanel, ibus_property_get_sub_props(property)); case PROP_TYPE_SEPARATOR: break; default: break; } } else { ibus_panel_service_property_activate((IBusPanelService *)impanel, prop_key.constData(), PROP_STATE_CHECKED); } } g_free(s0); } static void 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) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); gint i; g_variant_get (parameters, "(i)", &i); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(user_data); ibus_panel_service_candidate_clicked((IBusPanelService *)impanel, i, 0, 0); } static void 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) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(user_data); ibus_panel_service_page_up((IBusPanelService *)impanel); } static void 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) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(user_data); ibus_panel_service_page_down((IBusPanelService *)impanel); } static void 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) { Q_UNUSED(connection); Q_UNUSED(sender_name); Q_UNUSED(object_path); Q_UNUSED(interface_name); Q_UNUSED(signal_name); Q_UNUSED(parameters); Q_UNUSED(user_data); pid_t pid = fork(); if (pid == 0) { execlp ("ibus-setup", "ibus-setup", (char *)nullptr); exit (0); } } static void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { Q_UNUSED(name); IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); impanel->conn = connection; g_dbus_connection_register_object (connection, "/kimpanel", introspection_data->interfaces[0], nullptr, /*&interface_vtable*/ nullptr, /* user_data */ nullptr, /* user_data_free_func */ nullptr); /* GError** */ g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "TriggerProperty", "/org/kde/impanel", nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_trigger_property_callback, user_data, nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "SelectCandidate", "/org/kde/impanel", nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_select_candidate_callback, user_data, nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "LookupTablePageUp", "/org/kde/impanel", nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_prev_page_callback, user_data, nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "LookupTablePageDown", "/org/kde/impanel", nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_next_page_callback, user_data, nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "PanelCreated", "/org/kde/impanel", nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_panel_created_callback, user_data, nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "Exit", "/org/kde/impanel", nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_exit_callback, user_data, nullptr); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "Configure", "/org/kde/impanel", nullptr, G_DBUS_SIGNAL_FLAGS_NONE, impanel_configure_callback, user_data, nullptr); GVariant* var_engines = g_settings_get_value(impanel->settings_general, "preload-engines"); impanel_update_engines(impanel, var_engines); if (var_engines) { g_variant_unref(var_engines); } var_engines = g_settings_get_value(impanel->settings_general, "engines-order"); if (var_engines) { impanel_update_engines_order(impanel, var_engines); g_variant_unref(var_engines); } GVariant* var_triggers = g_settings_get_value(impanel->settings_hotkey, "triggers"); impanel_update_triggers(impanel, var_triggers); if (var_triggers) { g_variant_unref(var_triggers); } GVariant* var_layouts = g_settings_get_value(impanel->settings_general, "xkb-latin-layouts"); if (var_layouts) { impanel_update_latin_layouts(impanel, var_layouts); g_variant_unref(var_layouts); } GVariant* var = g_settings_get_value(impanel->settings_general, "use-system-keyboard-layout"); if (var) { impanel_update_use_system_keyboard_layout(impanel, var); g_variant_unref(var); } var = g_settings_get_value(impanel->settings_general, "use-global-engine"); if (var) { impanel_update_use_global_engine(impanel, var); g_variant_unref(var); } ibus_panel_impanel_real_register_properties(impanel); } static void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(name); Q_UNUSED(user_data); } static void on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data) { Q_UNUSED(connection); Q_UNUSED(name); Q_UNUSED(user_data); exit (1); } G_DEFINE_TYPE (IBusPanelImpanel, ibus_panel_impanel, IBUS_TYPE_PANEL_SERVICE) static void ibus_panel_impanel_class_init (IBusPanelImpanelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); IBUS_OBJECT_CLASS (object_class)->destroy = (IBusObjectDestroyFunc) ibus_panel_impanel_destroy; IBUS_PANEL_SERVICE_CLASS (object_class)->focus_in = ibus_panel_impanel_focus_in; IBUS_PANEL_SERVICE_CLASS (object_class)->focus_out = ibus_panel_impanel_focus_out; IBUS_PANEL_SERVICE_CLASS (object_class)->register_properties = ibus_panel_impanel_register_properties; IBUS_PANEL_SERVICE_CLASS (object_class)->set_cursor_location = ibus_panel_impanel_set_cursor_location; IBUS_PANEL_SERVICE_CLASS (object_class)->update_auxiliary_text = ibus_panel_impanel_update_auxiliary_text; IBUS_PANEL_SERVICE_CLASS (object_class)->update_lookup_table = ibus_panel_impanel_update_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->update_preedit_text = ibus_panel_impanel_update_preedit_text; IBUS_PANEL_SERVICE_CLASS (object_class)->update_property = ibus_panel_impanel_update_property; IBUS_PANEL_SERVICE_CLASS (object_class)->cursor_down_lookup_table = ibus_panel_impanel_cursor_down_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->cursor_up_lookup_table = ibus_panel_impanel_cursor_up_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->hide_auxiliary_text = ibus_panel_impanel_hide_auxiliary_text; IBUS_PANEL_SERVICE_CLASS (object_class)->hide_language_bar = ibus_panel_impanel_hide_language_bar; IBUS_PANEL_SERVICE_CLASS (object_class)->hide_lookup_table = ibus_panel_impanel_hide_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->hide_preedit_text = ibus_panel_impanel_hide_preedit_text; IBUS_PANEL_SERVICE_CLASS (object_class)->page_down_lookup_table = ibus_panel_impanel_page_down_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->page_up_lookup_table = ibus_panel_impanel_page_up_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->reset = ibus_panel_impanel_reset; IBUS_PANEL_SERVICE_CLASS (object_class)->show_auxiliary_text = ibus_panel_impanel_show_auxiliary_text; IBUS_PANEL_SERVICE_CLASS (object_class)->show_language_bar = ibus_panel_impanel_show_language_bar; IBUS_PANEL_SERVICE_CLASS (object_class)->show_lookup_table = ibus_panel_impanel_show_lookup_table; IBUS_PANEL_SERVICE_CLASS (object_class)->show_preedit_text = ibus_panel_impanel_show_preedit_text; IBUS_PANEL_SERVICE_CLASS (object_class)->start_setup = ibus_panel_impanel_start_setup; IBUS_PANEL_SERVICE_CLASS (object_class)->state_changed = ibus_panel_impanel_state_changed; } static void ibus_panel_impanel_init (IBusPanelImpanel *impanel) { impanel->bus = nullptr; impanel->app = nullptr; impanel->useSystemKeyboardLayout = false; impanel->selected = -1; introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, nullptr); owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, "org.kde.kimpanel.inputmethod", G_BUS_NAME_OWNER_FLAGS_REPLACE, on_bus_acquired, on_name_acquired, on_name_lost, impanel, nullptr); impanel->propManager = new PropertyManager; impanel->engineManager = new EngineManager; impanel->xkbLayoutManager = new XkbLayoutManager; impanel->settings_general = g_settings_new (IBUS_SCHEMA_GENERAL); impanel->settings_hotkey = g_settings_new (IBUS_SCHEMA_HOTKEY); g_signal_connect(impanel->settings_general, "changed", G_CALLBACK (impanel_settings_changed_callback), impanel); g_signal_connect(impanel->settings_hotkey, "changed", G_CALLBACK (impanel_settings_changed_callback), impanel); } static void ibus_panel_impanel_destroy (IBusPanelImpanel *impanel) { delete impanel->propManager; impanel->propManager = nullptr; delete impanel->engineManager; impanel->engineManager = nullptr; delete impanel->xkbLayoutManager; impanel->xkbLayoutManager = nullptr; g_signal_handlers_disconnect_by_func (impanel->settings_general, (gpointer)impanel_settings_changed_callback, impanel); g_signal_handlers_disconnect_by_func (impanel->settings_hotkey, (gpointer)impanel_settings_changed_callback, impanel); g_clear_object (&impanel->settings_general); g_clear_object (&impanel->settings_hotkey); g_bus_unown_name (owner_id); g_dbus_node_info_unref (introspection_data); IBUS_OBJECT_CLASS (ibus_panel_impanel_parent_class)->destroy ((IBusObject *)impanel); } static void ibus_panel_impanel_focus_in (IBusPanelService *panel, const gchar *input_context_path) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL (panel); if (impanel->app->keyboardGrabbed()) { return; } - IBusEngineDesc *engine_desc = ibus_bus_get_global_engine(impanel->bus); - impanel_update_logo_by_engine(impanel, engine_desc); - g_object_unref(engine_desc); + auto engine_desc = ibus_bus_get_global_engine(impanel->bus); + if (engine_desc) { + impanel_update_logo_by_engine(impanel, engine_desc); + g_object_unref(engine_desc); + } impanel->engineManager->setCurrentContext(input_context_path); if (!impanel->engineManager->useGlobalEngine()) { impanel_set_engine(impanel, impanel->engineManager->currentEngine().toUtf8().constData()); } } static void ibus_panel_impanel_focus_out (IBusPanelService *panel, const gchar *input_context_path) { Q_UNUSED(panel); Q_UNUSED(input_context_path); IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL (panel); if (impanel->app->keyboardGrabbed()) { return; } if (impanel->engineManager->useGlobalEngine()) { return; } impanel->engineManager->setCurrentContext(""); } static void ibus_panel_impanel_register_properties (IBusPanelService *panel, IBusPropList *prop_list) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL (panel); impanel->propManager->setProperties(prop_list); ibus_panel_impanel_real_register_properties(impanel); } static void ibus_panel_impanel_real_register_properties(IBusPanelImpanel* impanel) { if (!impanel->conn) return; IBusProperty* property = nullptr; guint i = 0; GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); if (impanel->selected >= 0 && static_cast(impanel->selected) < impanel->engineManager->length()) { auto engine_desc = impanel->engineManager->engines()[impanel->selected]; QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc); g_variant_builder_add (&builder, "s", propstr.constData()); } else { + QByteArray propstr; auto engine_desc = ibus_bus_get_global_engine(impanel->bus); - QByteArray propstr = ibus_engine_desc_to_logo_propstr(engine_desc); - g_variant_builder_add (&builder, "s", propstr.constData()); + if (engine_desc) { + propstr = ibus_engine_desc_to_logo_propstr(engine_desc); + g_variant_builder_add (&builder, "s", propstr.constData()); + g_object_unref(engine_desc); + } IBusPropList* prop_list = impanel->propManager->properties(); if (prop_list) { while ( ( property = ibus_prop_list_get( prop_list, i ) ) != nullptr ) { propstr = ibus_property_to_propstr(property, TRUE); g_variant_builder_add (&builder, "s", propstr.constData()); ++i; } } - g_object_unref(engine_desc); } g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "RegisterProperties", (g_variant_new ("(as)", &builder)), nullptr); } static void ibus_panel_impanel_set_cursor_location (IBusPanelService *panel, gint x, gint y, gint w, gint h) { g_dbus_connection_call(IBUS_PANEL_IMPANEL (panel)->conn, "org.kde.impanel", "/org/kde/impanel", "org.kde.impanel2", "SetSpotRect", (g_variant_new("(iiii)", x, y, w, h)), nullptr, G_DBUS_CALL_FLAGS_NONE, -1, /* timeout */ nullptr, nullptr, nullptr); } static void ibus_panel_impanel_update_auxiliary_text (IBusPanelService *panel, IBusText *text, gboolean visible) { const gchar* t = ibus_text_get_text (text); const gchar *attr = ""; IBusPanelImpanel* impanel = (IBusPanelImpanel*) panel; if (!impanel->conn) return; g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateAux", (g_variant_new ("(ss)", t, attr)), nullptr); if (visible == 0) ibus_panel_impanel_hide_auxiliary_text(panel); else ibus_panel_impanel_show_auxiliary_text(panel); } static void ibus_panel_impanel_update_lookup_table (IBusPanelService *panel, IBusLookupTable *lookup_table, gboolean visible) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; guint page_size = ibus_lookup_table_get_page_size(lookup_table); guint cursor_pos = ibus_lookup_table_get_cursor_pos(lookup_table); guint page = cursor_pos / page_size; guint start = page * page_size; guint end = start + page_size; guint num = ibus_lookup_table_get_number_of_candidates(lookup_table); if (end > num) { end = num; } // fprintf(stderr, "%d ~ %d pgsize %d num %d\n", start, end, page_size, num); guint i; gchar label[16][4];// WARNING large enough I think --- nihui const gchar *candidate; GVariantBuilder builder_labels; GVariantBuilder builder_candidates; GVariantBuilder builder_attrs; g_variant_builder_init (&builder_labels, G_VARIANT_TYPE ("as")); g_variant_builder_init (&builder_candidates, G_VARIANT_TYPE ("as")); g_variant_builder_init (&builder_attrs, G_VARIANT_TYPE ("as")); const gchar *attr = ""; for (i = start; i < end; i++) { g_snprintf (label[i-start], 4, "%d", (i-start+1) % 10); // NOTE ibus always return NULL for ibus_lookup_table_get_label // label = ibus_lookup_table_get_label(lookup_table, i)->text; g_variant_builder_add (&builder_labels, "s", label[i-start]); candidate = ibus_text_get_text (ibus_lookup_table_get_candidate (lookup_table, i)); g_variant_builder_add (&builder_candidates, "s", candidate); g_variant_builder_add (&builder_attrs, "s", attr); } gboolean has_prev = 1; gboolean has_next = 1; guint cursor_pos_in_page; if (ibus_lookup_table_is_cursor_visible(lookup_table)) cursor_pos_in_page = cursor_pos % page_size; else cursor_pos_in_page = -1; gint orientation = ibus_lookup_table_get_orientation(lookup_table); if (orientation == IBUS_ORIENTATION_HORIZONTAL) { orientation = 2; } else if (orientation == IBUS_ORIENTATION_VERTICAL) { orientation = 1; } else { orientation = 0; } g_dbus_connection_call(impanel->conn, "org.kde.impanel", "/org/kde/impanel", "org.kde.impanel2", "SetLookupTable", (g_variant_new ("(asasasbbii)", &builder_labels, &builder_candidates, &builder_attrs, has_prev, has_next, cursor_pos_in_page, orientation)), nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr, nullptr); if (visible == 0) ibus_panel_impanel_hide_lookup_table(panel); else ibus_panel_impanel_show_lookup_table(panel); } static void ibus_panel_impanel_update_preedit_text (IBusPanelService *panel, IBusText *text, guint cursor_pos, gboolean visible) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; const gchar* t = ibus_text_get_text (text); const gchar *attr = ""; g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditText", (g_variant_new ("(ss)", t, attr)), nullptr); g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditCaret", (g_variant_new ("(i)", cursor_pos)), nullptr); if (visible == 0) ibus_panel_impanel_hide_preedit_text(panel); else ibus_panel_impanel_show_preedit_text(panel); } static void ibus_panel_impanel_update_property (IBusPanelService *panel, IBusProperty *prop) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; impanel->propManager->updateProperty(prop); QByteArray propstr = ibus_property_to_propstr(prop, TRUE); g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty", (g_variant_new ("(s)", propstr.constData())), nullptr); } static void ibus_panel_impanel_cursor_down_lookup_table (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_cursor_up_lookup_table (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_hide_auxiliary_text (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 0; g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new ("(b)", toShow)), nullptr); } static void ibus_panel_impanel_hide_language_bar (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_hide_lookup_table (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 0; g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable", (g_variant_new ("(b)", toShow)), nullptr); } static void ibus_panel_impanel_hide_preedit_text (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 0; g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new ("(b)", toShow)), nullptr); } static void ibus_panel_impanel_page_down_lookup_table (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_page_up_lookup_table (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_reset (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_show_auxiliary_text (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 1; g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new ("(b)", toShow)), nullptr); } static void ibus_panel_impanel_show_language_bar (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_show_lookup_table (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 1; g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable", (g_variant_new ("(b)", toShow)), nullptr); } static void ibus_panel_impanel_show_preedit_text (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; gboolean toShow = 1; g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new ("(b)", toShow)), nullptr); } static void ibus_panel_impanel_start_setup (IBusPanelService *panel) { Q_UNUSED(panel); } static void ibus_panel_impanel_state_changed (IBusPanelService *panel) { IBusPanelImpanel* impanel = IBUS_PANEL_IMPANEL(panel); if (!impanel->conn) return; if (impanel->app->keyboardGrabbed()) { return; } IBusEngineDesc *engine_desc = ibus_bus_get_global_engine(impanel->bus); if (!engine_desc) { return; } impanel_update_logo_by_engine(impanel, engine_desc); g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "Enable", (g_variant_new ("(b)", TRUE)), nullptr); impanel->engineManager->moveToFirst(engine_desc); QStringList engineList = impanel->engineManager->engineOrder(); gchar** engine_names = g_new0 (gchar*, engineList.size() + 1); size_t i = 0; Q_FOREACH(const QString& name, engineList) { engine_names[i] = g_strdup (name.toUtf8().constData()); i ++; } GVariant* var = g_variant_new_strv(engine_names, engineList.size()); g_settings_set_value(impanel->settings_general, "engines-order", var); g_strfreev(engine_names); g_object_unref(engine_desc); } static void ibus_panel_impanel_exec_menu(IBusPanelImpanel* impanel, IBusPropList* prop_list) { if (!impanel->conn) return; GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); int i = 0; while (true) { IBusProperty* prop = ibus_prop_list_get(prop_list, i); if (!prop) break; QByteArray propstr = ibus_property_to_propstr(prop); g_variant_builder_add (&builder, "s", propstr.constData()); i ++; } g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new ("(as)", &builder)), nullptr); } static void ibus_panel_impanel_exec_im_menu (IBusPanelImpanel* impanel) { if (!impanel->conn) return; GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); IBusEngineDesc** engines = impanel->engineManager->engines(); if (engines) { int i = 0; while (engines[i]) { QByteArray propstr = ibus_engine_desc_to_propstr(engines[i]); g_variant_builder_add (&builder, "s", propstr.constData()); i ++; } } g_dbus_connection_emit_signal (impanel->conn, nullptr, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new ("(as)", &builder)), nullptr); } IBusPanelImpanel * ibus_panel_impanel_new (GDBusConnection *connection) { IBusPanelImpanel *panel; panel = (IBusPanelImpanel *) g_object_new (IBUS_TYPE_PANEL_IMPANEL, "object-path", IBUS_PATH_PANEL, "connection", connection, NULL); return panel; }