diff --git a/applets/kimpanel/backend/ibus/ibus15/panel.cpp b/applets/kimpanel/backend/ibus/ibus15/panel.cpp index cd5466dab..5a7502a1c 100644 --- a/applets/kimpanel/backend/ibus/ibus15/panel.cpp +++ b/applets/kimpanel/backend/ibus/ibus15/panel.cpp @@ -1,1550 +1,1550 @@ /* * 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 */ typedef struct _IBusPanelImpanelClass IBusPanelImpanelClass; struct _IBusPanelImpanel { IBusPanelService parent; IBusBus *bus; GDBusConnection *conn; PropertyManager* propManager; EngineManager* engineManager; XkbLayoutManager* xkbLayoutManager; App* app; gboolean useSystemKeyboardLayout; int selected; }; 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty", (g_variant_new ("(s)", propstr.constData())), NULL); } 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 = NULL; 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 = NULL; 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 = NULL; 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 != NULL ; 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, NULL); 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 != NULL ; 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 != NULL ; 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 != NULL ; 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 = NULL; 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 = NULL; } if (!engine_names) { impanel_get_default_engine(impanel, &engine_names, &len); IBusConfig* config = ibus_bus_get_config(impanel->bus); GVariant* var = g_variant_new_strv(engine_names, len); ibus_config_set_value(config, "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 = NULL; 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 = NULL; size_t len = 0; if (variant) { triggers = g_variant_dup_strv(variant, &len); } if (len == 0) { g_strfreev(triggers); triggers = 0; } 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_config_value_changed_callback (IBusConfig* config, const gchar* section, const gchar* name, GVariant* value, gpointer user_data) { Q_UNUSED(config); IBusPanelImpanel* impanel = ((IBusPanelImpanel *)user_data); if (g_strcmp0(section, "general") == 0 && g_strcmp0(name, "preload_engines") == 0) { impanel_update_engines(impanel, value); } else if (g_strcmp0(section, "general/hotkey") == 0 && g_strcmp0(name, "triggers") == 0) { impanel_update_triggers(impanel, value); } else if (g_strcmp0(section, "general") == 0 && g_strcmp0(name, "use-system-keyboard-layout") == 0) { impanel_update_use_system_keyboard_layout(impanel, value); } else if (g_strcmp0(section, "general") == 0 && g_strcmp0(name, "use-global-engine") == 0) { impanel_update_use_global_engine(impanel, value); } } 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 = NULL; 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 *)0); 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], NULL, /*&interface_vtable*/ NULL, /* user_data */ NULL, /* user_data_free_func */ NULL); /* GError** */ g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "TriggerProperty", "/org/kde/impanel", NULL, G_DBUS_SIGNAL_FLAGS_NONE, impanel_trigger_property_callback, user_data, NULL); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "SelectCandidate", "/org/kde/impanel", NULL, G_DBUS_SIGNAL_FLAGS_NONE, impanel_select_candidate_callback, user_data, NULL); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "LookupTablePageUp", "/org/kde/impanel", NULL, G_DBUS_SIGNAL_FLAGS_NONE, impanel_prev_page_callback, user_data, NULL); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "LookupTablePageDown", "/org/kde/impanel", NULL, G_DBUS_SIGNAL_FLAGS_NONE, impanel_next_page_callback, user_data, NULL); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "PanelCreated", "/org/kde/impanel", NULL, G_DBUS_SIGNAL_FLAGS_NONE, impanel_panel_created_callback, user_data, NULL); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "Exit", "/org/kde/impanel", NULL, G_DBUS_SIGNAL_FLAGS_NONE, impanel_exit_callback, user_data, NULL); g_dbus_connection_signal_subscribe (connection, "org.kde.impanel", "org.kde.impanel", "Configure", "/org/kde/impanel", NULL, G_DBUS_SIGNAL_FLAGS_NONE, impanel_configure_callback, user_data, NULL); IBusConfig* config = ibus_bus_get_config(impanel->bus); if (config) { g_signal_connect_object(config, "value-changed", (GCallback) impanel_config_value_changed_callback, impanel, (GConnectFlags) 0); ibus_config_watch(config, "general", "preload_engines"); ibus_config_watch(config, "general", "use-system-keyboard-layout"); ibus_config_watch(config, "general/hotkey", "triggers"); GVariant* var_engines = ibus_config_get_value(config, "general", "preload_engines"); impanel_update_engines(impanel, var_engines); if (var_engines) g_variant_unref(var_engines); var_engines = ibus_config_get_value(config, "general", "engines-order"); if (var_engines) { impanel_update_engines_order(impanel, var_engines); g_variant_unref(var_engines); } GVariant* var_triggers = ibus_config_get_value(config, "general/hotkey", "triggers"); impanel_update_triggers(impanel, var_triggers); if (var_triggers) g_variant_unref(var_triggers); IBusConfig* config = ibus_bus_get_config(impanel->bus); GVariant* var_layouts = ibus_config_get_value(config, "general", "xkb-latin-layouts"); if (var_layouts) { impanel_update_latin_layouts(impanel, var_layouts); g_variant_unref(var_layouts); } GVariant* var = ibus_config_get_value(config, "general", "use-system-keyboard-layout"); if (var) { impanel_update_use_system_keyboard_layout(impanel, var); g_variant_unref(var); } var = ibus_config_get_value(config, "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 = NULL; impanel->app = NULL; impanel->useSystemKeyboardLayout = false; impanel->selected = -1; introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); 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, NULL); impanel->propManager = new PropertyManager; impanel->engineManager = new EngineManager; impanel->xkbLayoutManager = new XkbLayoutManager; } static void ibus_panel_impanel_destroy (IBusPanelImpanel *impanel) { delete impanel->propManager; impanel->propManager = NULL; delete impanel->engineManager; impanel->engineManager = NULL; delete impanel->xkbLayoutManager; impanel->xkbLayoutManager = NULL; 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); 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 = NULL; 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 { 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()); IBusPropList* prop_list = impanel->propManager->properties(); if (prop_list) { while ( ( property = ibus_prop_list_get( prop_list, i ) ) != NULL ) { 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "RegisterProperties", (g_variant_new ("(as)", &builder)), NULL); } 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)), NULL, G_DBUS_CALL_FLAGS_NONE, -1, /* timeout */ NULL, NULL, NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateAux", (g_variant_new ("(ss)", t, attr)), NULL); 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; + 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)), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditText", (g_variant_new ("(ss)", t, attr)), NULL); g_dbus_connection_emit_signal (impanel->conn, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditCaret", (g_variant_new ("(i)", cursor_pos)), NULL); 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty", (g_variant_new ("(s)", propstr.constData())), NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new ("(b)", toShow)), NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable", (g_variant_new ("(b)", toShow)), NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new ("(b)", toShow)), NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux", (g_variant_new ("(b)", toShow)), NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable", (g_variant_new ("(b)", toShow)), NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit", (g_variant_new ("(b)", toShow)), NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "Enable", (g_variant_new ("(b)", TRUE)), NULL); 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 ++; } IBusConfig* config = ibus_bus_get_config(impanel->bus); if (config) { GVariant* var = g_variant_new_strv(engine_names, engineList.size()); ibus_config_set_value(config, "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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new ("(as)", &builder)), NULL); } 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, NULL, "/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu", (g_variant_new ("(as)", &builder)), NULL); } 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; } diff --git a/applets/kimpanel/package/contents/ui/ActionMenu.qml b/applets/kimpanel/package/contents/ui/ActionMenu.qml index aa1ca7271..2fe064549 100644 --- a/applets/kimpanel/package/contents/ui/ActionMenu.qml +++ b/applets/kimpanel/package/contents/ui/ActionMenu.qml @@ -1,96 +1,110 @@ /*************************************************************************** * Copyright (C) 2013 by Aurélien Gâteau * * Copyright (C) 2014 by Eike Hein * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.plasmoid 2.0 Item { id: root property QtObject menu property Item visualParent property variant actionList signal actionClicked(string actionId) onActionListChanged: refreshMenu(); - function open(x, y) { - menu.open(); + function open() { + menu.openRelative(); } function refreshMenu() { if (menu) { menu.destroy(); } menu = contextMenuComponent.createObject(root); if (!actionList || actionList.length == 0) { var item = emptyMenuItemComponent.createObject(menu); menu.addMenuItem(item); return; } actionList.forEach(function(actionItem) { var item = contextMenuItemComponent.createObject(menu, { "actionItem": actionItem, }); menu.addMenuItem(item); }); } Component { id: contextMenuComponent PlasmaComponents.ContextMenu { visualParent: root.visualParent + + placement: { + if (plasmoid.location == PlasmaCore.Types.LeftEdge) { + return PlasmaCore.Types.RightPosedTopAlignedPopup; + } else if (plasmoid.location == PlasmaCore.Types.TopEdge) { + return PlasmaCore.Types.BottomPosedLeftAlignedPopup; + } else if (plasmoid.location == PlasmaCore.Types.RightEdge) { + return PlasmaCore.Types.LeftPosedTopAlignedPopup; + } else { + return PlasmaCore.Types.TopPosedLeftAlignedPopup; + } + } } } Component { id: contextMenuItemComponent PlasmaComponents.MenuItem { property variant actionItem text: actionItem.text ? actionItem.text : "" icon: actionItem.icon ? actionItem.icon : null checkable: actionItem.hint == "checked" checked: actionItem.hint == "checked" onClicked: { actionClicked(actionItem.actionId); } } } Component { id: emptyMenuItemComponent PlasmaComponents.MenuItem { text: i18n("(Empty)") enabled: false } } } diff --git a/applets/kimpanel/package/contents/ui/ContextMenu.qml b/applets/kimpanel/package/contents/ui/ContextMenu.qml index 86fbb7601..7e919c425 100644 --- a/applets/kimpanel/package/contents/ui/ContextMenu.qml +++ b/applets/kimpanel/package/contents/ui/ContextMenu.qml @@ -1,143 +1,157 @@ /*************************************************************************** * Copyright (C) 2013 by Aurélien Gâteau * * Copyright (C) 2014-2015 by Eike Hein * * * * 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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.plasmoid 2.0 Item { id: root property QtObject menu property Item visualParent property variant actionList function open(item, actionItem) { visualParent = item; refreshMenu(actionItem); - menu.open(); + menu.openRelative(); } function refreshMenu(actionItem) { if (menu) { menu.destroy(); } menu = contextMenuComponent.createObject(root, {"actionItem": actionItem}); if (actionList && actionList.length > 0) { menu.separator.visible = true; actionList.forEach(function(actionItem) { var item = contextMenuItemComponent.createObject(menu.showMenu, { "actionItem": actionItem, }); }); } } Component { id: contextMenuItemComponent PlasmaComponents.MenuItem { property variant actionItem text: actionItem.label icon: actionItem.icon onClicked: { kimpanel.showAction(actionItem.key); } } } Component { id: contextMenuComponent PlasmaComponents.ContextMenu { visualParent: root.visualParent property variant actionItem property Item separator: separatorItem property QtObject showMenu: subShowMenu + placement: { + if (plasmoid.location == PlasmaCore.Types.LeftEdge) { + return PlasmaCore.Types.RightPosedTopAlignedPopup; + } else if (plasmoid.location == PlasmaCore.Types.TopEdge) { + return PlasmaCore.Types.BottomPosedLeftAlignedPopup; + } else if (plasmoid.location == PlasmaCore.Types.RightEdge) { + return PlasmaCore.Types.LeftPosedTopAlignedPopup; + } else { + return PlasmaCore.Types.TopPosedLeftAlignedPopup; + } + } + PlasmaComponents.MenuItem { id: showItem visible: separatorItem.visible text: i18n("Show") PlasmaComponents.ContextMenu { id: subShowMenu visualParent: showItem.action } } PlasmaComponents.MenuItem { id: separatorItem separator: true visible: false } PlasmaComponents.MenuItem { text: i18n("Hide %1", actionItem.label); onClicked: { kimpanel.hideAction(actionItem.key); } enabled: kimpanel.visibleButtons > 1 visible: kimpanel.visibleButtons > 1 } PlasmaComponents.MenuItem { text: i18n("Configure Input Method") icon: "configure" onClicked: { kimpanel.action("Configure"); } } PlasmaComponents.MenuItem { text: i18n("Reload Config") icon: "view-refresh" onClicked: { kimpanel.action("ReloadConfig"); } } PlasmaComponents.MenuItem { text: i18n("Exit Input Method") icon: "application-exit" onClicked: { kimpanel.action("Exit"); } } PlasmaComponents.MenuItem { property QtObject configureAction: null enabled: configureAction && configureAction.enabled text: configureAction ? configureAction.text : "" icon: configureAction ? configureAction.icon : "" onClicked: configureAction.trigger() Component.onCompleted: configureAction = plasmoid.action("configure") } } } } diff --git a/applets/kimpanel/package/contents/ui/main.qml b/applets/kimpanel/package/contents/ui/main.qml index 8dea6033e..60154540b 100644 --- a/applets/kimpanel/package/contents/ui/main.qml +++ b/applets/kimpanel/package/contents/ui/main.qml @@ -1,211 +1,214 @@ /* * Copyright 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. */ import QtQuick 2.0 import QtQuick.Layouts 1.1 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.kquickcontrolsaddons 2.0 Item { id: kimpanel property int visibleButtons: 0 property bool vertical: plasmoid.formFactor == PlasmaCore.Types.Vertical LayoutMirroring.enabled: !vertical && Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true Layout.minimumWidth: vertical ? units.iconSizes.small : items.implicitWidth Layout.minimumHeight: !vertical ? units.iconSizes.small : items.implicitHeight Layout.preferredHeight: Layout.minimumHeight Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation InputPanel { } Flow { id: items width: parent.width height: parent.height x: (parent.width - childrenRect.width) / 2 y: (parent.height - childrenRect.height) / 2 flow: kimpanel.vertical ? Flow.LeftToRight : Flow.TopToBottom property int iconSize: Math.min(units.iconSizeHints.panel, units.roundToIconSize(Math.min(width, height))) Repeater { model: ListModel { id: list dynamicRoles: true } delegate: Item { id: iconDelegate width: items.iconSize height: items.iconSize StatusIcon { id: statusIcon anchors.centerIn: parent width: items.iconSize height: items.iconSize label: model.label tip: model.tip icon: model.icon hint: model.hint onTriggered : { if (button == Qt.LeftButton) { - clickHandler(model.key) + clickHandler(model.key); + // clickHandler will trigger the menu, but we have to wait for + // the menu data. So we have to set the visual parent ahead. + actionMenu.visualParent = statusIcon; } else { contextMenu.open(statusIcon, {key: model.key, label: model.label}); } } } } } } function clickHandler(key) { var service = dataEngine.serviceForSource("statusbar"); var operation = service.operationDescription("TriggerProperty"); operation.key = key; service.startOperationCall(operation); } function action(key) { var service = dataEngine.serviceForSource("statusbar"); var operation = service.operationDescription(key); service.startOperationCall(operation); } function hideAction(key) { // We must use assignment to change the configuration property, // otherwise it won't get notified. var hiddenList = plasmoid.configuration.hiddenList; if (hiddenList.indexOf(key) === -1) { hiddenList.push(key); plasmoid.configuration.hiddenList = hiddenList; } timer.restart(); } function showAction(key) { // We must use assignment to change the configuration property, // otherwise it won't get notified. var hiddenList = plasmoid.configuration.hiddenList; var index = hiddenList.indexOf(key); if (index !== -1) { hiddenList.splice(index, 1); plasmoid.configuration.hiddenList = hiddenList; } timer.restart(); } function showMenu(menu, menuData) { if (!menuData) { return; } if (menuData["timestamp"] > menu.timestamp) { menu.timestamp = menuData["timestamp"]; var actionList = []; for (var i = 0; i < menuData["props"].length; i++ ) { actionList.push({"actionId": menuData["props"][i].key, "icon": menuData["props"][i].icon, "text": menuData["props"][i].label, hint: menuData["props"][i].hint}); } if (actionList.length > 0) { menu.actionList = actionList; menu.open(); } } } ActionMenu { property var timestamp: 0; id: actionMenu onActionClicked: { clickHandler(actionId); } } ContextMenu { id: contextMenu } Timer { id: timer interval: 50 onTriggered: { var data = dataEngine.data["statusbar"]["Properties"]; if (!data) { return; } var count = list.count; var c = 0, i; var hiddenActions = []; for (i = 0; i < data.length; i ++) { if (plasmoid.configuration.hiddenList.indexOf(data[i].key) !== -1) { hiddenActions.push({'key': data[i].key, 'icon': data[i].icon, 'label': data[i].label}); } else { c = c + 1; } } if (c < count) { list.remove(c, count - c); } kimpanel.visibleButtons = c; c = 0; for (i = 0; i < data.length; i ++) { if (plasmoid.configuration.hiddenList.indexOf(data[i].key) !== -1) { continue; } var itemData = {'key': data[i].key, 'icon': data[i].icon, 'label': data[i].label, 'tip': data[i].tip, 'hint': data[i].hint }; if (c < count) { list.set(c, itemData); } else { list.append(itemData); } c = c + 1; } contextMenu.actionList = hiddenActions; } } PlasmaCore.DataSource { id: dataEngine engine: "kimpanel" connectedSources: ["statusbar"] onDataChanged: { showMenu(actionMenu, dataEngine.data["statusbar"]["Menu"]); var data = dataEngine.data["statusbar"]["Properties"]; if (!data) { kimpanel.visibleButtons = 0; return; } timer.restart(); } } }