File indexing completed on 2024-11-24 05:00:25

0001 /*
0002     SPDX-FileCopyrightText: 2009 Wang Hoi <zealot.hoi@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 /** @file scim_panel_dbus.cpp
0008  */
0009 
0010 #define KDE_signal signal
0011 
0012 #undef QT_NO_STL
0013 #define QT_STL
0014 
0015 #include <config-scim.h>
0016 #include <errno.h>
0017 #include <list>
0018 #include <signal.h>
0019 #include <stdlib.h>
0020 #include <sys/time.h>
0021 #include <sys/types.h>
0022 #include <sys/wait.h>
0023 #include <unistd.h>
0024 
0025 #include <QCoreApplication>
0026 #include <QDBusConnection>
0027 #include <QDBusMessage>
0028 #include <QMutex>
0029 #include <QObject>
0030 #include <QProcess>
0031 #include <QString>
0032 #include <QStringList>
0033 #include <QThread>
0034 
0035 #define Uses_C_STDIO
0036 #define Uses_C_STDLIB
0037 #define Uses_SCIM_LOOKUP_TABLE
0038 #define Uses_SCIM_SOCKET
0039 #define Uses_SCIM_TRANSACTION
0040 #define Uses_SCIM_TRANS_COMMANDS
0041 #define Uses_SCIM_CONFIG
0042 #define Uses_SCIM_CONFIG_MODULE
0043 // #define Uses_SCIM_DEBUG
0044 #define Uses_SCIM_HELPER
0045 #define Uses_SCIM_HELPER_MODULE
0046 #define Uses_SCIM_PANEL_AGENT
0047 #define Uses_STL_MAP
0048 
0049 #define ENABLE_DEBUG 9
0050 // scim use exceptions and template, so it doesn't work in hidden visibility
0051 #pragma GCC visibility push(default)
0052 #include <scim.h>
0053 #pragma GCC visibility pop
0054 
0055 Q_DECLARE_METATYPE(scim::Property)
0056 Q_DECLARE_METATYPE(scim::PanelFactoryInfo)
0057 Q_DECLARE_METATYPE(scim::HelperInfo)
0058 
0059 using namespace Qt::StringLiterals;
0060 using namespace scim;
0061 
0062 // PanelAgent related functions
0063 static bool initialize_panel_agent(const String &config, const String &display, bool resident);
0064 static bool run_panel_agent(void);
0065 static void start_auto_start_helpers(void);
0066 
0067 static void slot_transaction_start(void);
0068 static void slot_transaction_end(void);
0069 static void slot_reload_config(void);
0070 static void slot_turn_on(void);
0071 static void slot_turn_off(void);
0072 static void slot_update_screen(int screen);
0073 static void slot_update_spot_location(int x, int y);
0074 static void slot_update_factory_info(const PanelFactoryInfo &info);
0075 static void slot_show_help(const String &help);
0076 static void slot_show_factory_menu(const std::vector<PanelFactoryInfo> &menu);
0077 
0078 static void slot_show_preedit_string(void);
0079 static void slot_show_aux_string(void);
0080 static void slot_show_lookup_table(void);
0081 static void slot_hide_preedit_string(void);
0082 static void slot_hide_aux_string(void);
0083 static void slot_hide_lookup_table(void);
0084 static void slot_update_preedit_string(const String &str, const AttributeList &attrs);
0085 static void slot_update_preedit_caret(int caret);
0086 static void slot_update_aux_string(const String &str, const AttributeList &attrs);
0087 static void slot_update_lookup_table(const LookupTable &table);
0088 static void slot_register_properties(const PropertyList &props);
0089 static void slot_update_property(const Property &prop);
0090 
0091 static void slot_register_helper_properties(int id, const PropertyList &props);
0092 static void slot_update_helper_property(int id, const Property &prop);
0093 static void slot_register_helper(int id, const HelperInfo &helper);
0094 static void slot_remove_helper(int id);
0095 static void slot_lock(void);
0096 static void slot_unlock(void);
0097 
0098 /////////////////////////////////////////////////////////////////////////////
0099 // Declaration of internal variables.
0100 /////////////////////////////////////////////////////////////////////////////
0101 // static bool               _ui_initialized              = false;
0102 
0103 static ConfigModule *_config_module = nullptr;
0104 static ConfigPointer _config;
0105 
0106 static std::vector<HelperInfo> _helper_list;
0107 
0108 static bool _should_exit = false;
0109 
0110 // static bool               _panel_is_on                 = false;
0111 
0112 static PanelAgent *_panel_agent = nullptr;
0113 
0114 static QList<PanelFactoryInfo> _factory_list;
0115 
0116 class PanelAgentThread;
0117 PanelAgentThread *_panel_agent_thread;
0118 
0119 class DBusHandler;
0120 DBusHandler *_dbus_handler;
0121 
0122 static QMutex _panel_agent_lock;
0123 static QMutex _global_resource_lock;
0124 static QMutex _transaction_lock;
0125 
0126 /////////////////////////////////////////////////////////////////////////////
0127 // Implementation of internal functions.
0128 /////////////////////////////////////////////////////////////////////////////
0129 
0130 static void ui_config_reload_callback(const ConfigPointer &config)
0131 {
0132     _config = config;
0133 }
0134 
0135 static QString AttrList2String(const AttributeList &attr_list)
0136 {
0137     QString result;
0138     for (const Attribute &attr : attr_list) {
0139         int type = (int)attr.get_type();
0140         unsigned int start = attr.get_start();
0141         unsigned int length = attr.get_length();
0142         unsigned int value = attr.get_value();
0143         result += QString::fromLatin1("%1:%2:%3:%4;").arg(type).arg(start).arg(length).arg(value);
0144     }
0145     return result;
0146 }
0147 
0148 static QVariantList LookupTable2VariantList(const LookupTable &lookup_table)
0149 {
0150     QVariantList result;
0151     QStringList labels;
0152     QStringList candidates;
0153     QStringList attrlist_list;
0154     int current_page_size = lookup_table.get_current_page_size();
0155 
0156     for (int i = 0; i < current_page_size; ++i) {
0157         labels << QString::fromStdWString(lookup_table.get_candidate_label(i));
0158     }
0159     for (int i = 0; i < current_page_size; ++i) {
0160         candidates << QString::fromStdWString(lookup_table.get_candidate_in_current_page(i));
0161         attrlist_list << AttrList2String(lookup_table.get_attributes_in_current_page(i));
0162     }
0163 
0164     result << labels << candidates << attrlist_list << lookup_table.get_current_page_start()
0165            << (lookup_table.get_current_page_start() + lookup_table.get_current_page_size() < ((int)lookup_table.number_of_candidates()));
0166 
0167     // result << labels << candidates << attrlist_list;
0168     return result;
0169 }
0170 
0171 static QString Property2String(const Property &prop)
0172 {
0173     QString result;
0174     int state = 0;
0175     if (prop.active())
0176         state |= SCIM_PROPERTY_ACTIVE;
0177     if (prop.visible())
0178         state |= SCIM_PROPERTY_VISIBLE;
0179     result = QString::fromLatin1("%1:%2:%3:%4:%5")
0180                  .arg(QString::fromUtf8(prop.get_key().c_str()))
0181                  .arg(QString::fromUtf8(prop.get_label().c_str()))
0182                  .arg(QString::fromUtf8(prop.get_icon().c_str()))
0183                  .arg(QString::fromUtf8(prop.get_tip().c_str()))
0184                  .arg(state);
0185     return result;
0186 }
0187 
0188 #if 0
0189 static QString
0190 PanelFactoryInfo2String(const PanelFactoryInfo &info)
0191 {
0192     QString result = QString("%1:%2:%3:%4")
0193                      .arg(QString::fromUtf8(info.uuid.c_str()))
0194                      .arg(QString::fromUtf8(info.name.c_str()))
0195                      .arg(QString::fromUtf8(info.icon.c_str()))
0196                      .arg(QString::fromUtf8(info.lang.c_str()));
0197     return result;
0198 }
0199 #endif
0200 
0201 static QStringList PropertyList2LeafOnlyStringList(const QList<Property> &props)
0202 {
0203     QStringList list;
0204     list.clear();
0205     for (int i = 0; i < props.size(); ++i) {
0206         bool ok = true;
0207         for (int j = 0; j < props.size(); ++j) {
0208             if (props.at(i).is_a_leaf_of(props.at(j))) {
0209                 SCIM_DEBUG_MAIN(1) << "Leaf" << props.at(i).get_key() << " " << props.at(j).get_key() << "\n";
0210                 ok = false;
0211             }
0212         }
0213         if (ok)
0214             list << Property2String(props.at(i));
0215     }
0216     return list;
0217 }
0218 
0219 static int dbus_event_type = QEvent::registerEventType(1988);
0220 class DBusEvent : public QEvent
0221 {
0222 public:
0223     enum SCIM_EVENT_TYPE {
0224         TURN_ON,
0225         TURN_OFF,
0226         UP_SCREEN,
0227         UP_SPOT_LOC,
0228         UP_AUX,
0229         UP_PREEDIT_STR,
0230         UP_PREEDIT_CARET,
0231         UP_LOOKUPTABLE,
0232         UP_LOOKUPTABLE_CURSOR,
0233         UP_FACTORY_INFO,
0234         UP_PROPERTY,
0235         UP_HELPER_PROPERTY,
0236         REG_PROPERTIES,
0237         REG_HELPER_PROPERTIES,
0238         REG_HELPER,
0239         RM_HELPER,
0240         RM_PROPERTY,
0241         SHOW_LOOKUPTABLE,
0242         HIDE_LOOKUPTABLE,
0243         SHOW_PREEDIT,
0244         HIDE_PREEDIT,
0245         SHOW_AUX,
0246         HIDE_AUX,
0247         SHOW_HELP,
0248         SHOW_FACTORY_MENU,
0249     };
0250     DBusEvent(SCIM_EVENT_TYPE t, const QVariantList &arglist = QVariantList())
0251         : QEvent((QEvent::Type)dbus_event_type)
0252         , m_evtype(t)
0253         , m_data(arglist)
0254     {
0255     }
0256     SCIM_EVENT_TYPE scim_event_type() const
0257     {
0258         return m_evtype;
0259     }
0260     const QVariantList &data() const
0261     {
0262         return m_data;
0263     }
0264 
0265 private:
0266     SCIM_EVENT_TYPE m_evtype;
0267     QVariantList m_data;
0268 };
0269 class DBusHandler : public QObject
0270 {
0271     Q_OBJECT
0272 public:
0273     explicit DBusHandler(QObject *parent = nullptr)
0274         : QObject(parent)
0275     {
0276         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "MovePreeditCaret"_L1, this, SLOT(MovePreeditCaret(int)));
0277         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "SelectCandidate"_L1, this, SLOT(SelectCandidate(int)));
0278         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "LookupTablePageUp"_L1, this, SLOT(LookupTablePageUp()));
0279         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "LookupTablePageDown"_L1, this, SLOT(LookupTablePageDown()));
0280         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "TriggerProperty"_L1, this, SLOT(TriggerProperty(QString)));
0281         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "PanelCreated"_L1, this, SLOT(PanelCreated()));
0282         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "Exit"_L1, this, SLOT(Exit()));
0283         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "ReloadConfig"_L1, this, SLOT(ReloadConfig()));
0284         QDBusConnection("scim_panel"_L1).connect(""_L1, ""_L1, "org.kde.impanel"_L1, "Configure"_L1, this, SLOT(Configure()));
0285 
0286         logo_prop = Property("/Logo", "SCIM", String(SCIM_ICON_DIR) + "/trademark.png", "SCIM Input Method");
0287         show_help_prop = Property("/StartHelp", "Help", "help-about", "About SCIM…");
0288         factory_prop_prefix = QString::fromUtf8("/Factory/");
0289         helper_prop_prefix = QString::fromUtf8("/Helper/");
0290     }
0291     ~DBusHandler()
0292     {
0293     }
0294 
0295     void setInitialHelpers(const std::vector<HelperInfo> &_helper_list)
0296     {
0297         QList<Property> props;
0298         for (const HelperInfo &info : _helper_list) {
0299             if (((info.option & SCIM_HELPER_STAND_ALONE) != 0) && ((info.option & SCIM_HELPER_AUTO_START) == 0)) {
0300                 props << Property(String(helper_prop_prefix.toUtf8().constData()) + info.uuid, info.name, info.icon, info.description);
0301             }
0302         }
0303         if (!props.isEmpty()) {
0304             helper_props_map.insert(0, props);
0305         }
0306     }
0307 public Q_SLOTS:
0308     void MovePreeditCaret(int pos)
0309     {
0310         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << pos << "\n";
0311         _panel_agent->move_preedit_caret(pos);
0312     }
0313     void SelectCandidate(int idx)
0314     {
0315         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << idx << "\n";
0316         _panel_agent->select_candidate(idx);
0317     }
0318     void LookupTablePageUp()
0319     {
0320         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
0321         _panel_agent->lookup_table_page_up();
0322     }
0323     void LookupTablePageDown()
0324     {
0325         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
0326         _panel_agent->lookup_table_page_down();
0327     }
0328     void TriggerProperty(const QString &key)
0329     {
0330         SCIM_DEBUG_MAIN(1) << qPrintable(key) << "\n";
0331         if (key == QString::fromUtf8(show_help_prop.get_key().c_str())) {
0332             SCIM_DEBUG_MAIN(1) << "about_to_show_help"
0333                                << "\n";
0334             _panel_agent->request_help();
0335             return;
0336         }
0337         if (key == QString::fromUtf8(logo_prop.get_key().c_str())) {
0338             SCIM_DEBUG_MAIN(1) << "about_to_show_factory_menu"
0339                                << "\n";
0340             _panel_agent->request_factory_menu();
0341             return;
0342         }
0343         if (key.startsWith(factory_prop_prefix)) {
0344             QString factory_uuid = key;
0345             factory_uuid.remove(0, factory_prop_prefix.size());
0346             SCIM_DEBUG_MAIN(1) << "about_to_change_factory" << qPrintable(factory_uuid) << "\n";
0347             _panel_agent->change_factory(factory_uuid.toUtf8().constData());
0348             return;
0349         }
0350         if (key.startsWith(helper_prop_prefix)) {
0351             QString helper_uuid = key;
0352             helper_uuid.remove(0, helper_prop_prefix.size());
0353             SCIM_DEBUG_MAIN(1) << "about_to_start_helper" << qPrintable(helper_uuid) << "\n";
0354             _panel_agent->start_helper(helper_uuid.toUtf8().constData());
0355             return;
0356         }
0357         int i = 0;
0358         for (i = 0; i < panel_props.size(); ++i) {
0359             if (panel_props.at(i).get_key() == String(key.toUtf8().constData())) {
0360                 break;
0361             }
0362         }
0363         // found one
0364         QStringList list_result;
0365         list_result.clear();
0366         if (i < panel_props.size()) {
0367             for (int j = 0; j < panel_props.size(); ++j) {
0368                 if (panel_props.at(j).is_a_leaf_of(panel_props.at(i))) {
0369                     list_result << Property2String(panel_props.at(j));
0370                 }
0371             }
0372             if (list_result.isEmpty()) {
0373                 _panel_agent->trigger_property(key.toUtf8().constData());
0374             } else {
0375                 SCIM_DEBUG_MAIN(1) << "ExecMenu" << qPrintable(key) << "\n";
0376                 QDBusMessage message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ExecMenu"_L1);
0377                 message << list_result;
0378                 QDBusConnection("scim_panel"_L1).send(message);
0379             }
0380         }
0381     }
0382     void PanelCreated()
0383     {
0384         QDBusMessage message;
0385         QStringList list_result;
0386 
0387         list_result.clear();
0388         list_result << Property2String(logo_prop);
0389         list_result << PropertyList2LeafOnlyStringList(panel_props);
0390 
0391         for (const QList<Property> &props : std::as_const(helper_props_map)) {
0392             list_result << PropertyList2LeafOnlyStringList(props);
0393         }
0394 
0395         list_result << Property2String(show_help_prop);
0396 
0397         message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "RegisterProperties"_L1);
0398 
0399         message << list_result;
0400         QDBusConnection("scim_panel"_L1).send(message);
0401     }
0402     void Exit()
0403     {
0404         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
0405         _panel_agent->exit();
0406         _panel_agent->stop();
0407         exit(1);
0408     }
0409     void ReloadConfig()
0410     {
0411         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
0412         _panel_agent->reload_config();
0413         if (!_config.null())
0414             _config->reload();
0415     }
0416     void Configure()
0417     {
0418         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
0419         QProcess::startDetached("scim-setup"_L1, QStringList());
0420     }
0421 
0422 protected:
0423     bool event(QEvent *e) override
0424     {
0425         QStringList list_result;
0426         QList<Property> prop_list;
0427         if (e->type() == dbus_event_type) {
0428             DBusEvent *ev = (DBusEvent *)e;
0429 
0430             QDBusMessage message;
0431             QVariantList data;
0432 
0433             switch (ev->scim_event_type()) {
0434             case DBusEvent::TURN_ON:
0435                 /*
0436                 list_result.clear();
0437                 list_result << Property2String(logo_prop);
0438                 list_result << PropertyList2LeafOnlyStringList(panel_props);
0439                 for(const QList<Property> &props : std::as_const(helper_props_map)) {
0440                     list_result << PropertyList2LeafOnlyStringList(props);
0441                 }
0442                 list_result << Property2String(show_help_prop);
0443 
0444                 message = QDBusMessage::createSignal("/kimpanel"_L1,
0445                     "org.kde.kimpanel.inputmethod",
0446                     "RegisterProperties");
0447 
0448                 message << list_result;
0449                 QDBusConnection("scim_panel").send(message);
0450                 */
0451                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "Enable"_L1);
0452                 message << true;
0453                 QDBusConnection("scim_panel"_L1).send(message);
0454                 break;
0455             case DBusEvent::TURN_OFF:
0456                 logo_prop.set_icon(String(SCIM_ICON_DIR) + "/trademark.png");
0457 
0458                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdateProperty"_L1);
0459                 message << Property2String(logo_prop);
0460                 QDBusConnection("scim_panel"_L1).send(message);
0461                 /*
0462                 list_result.clear();
0463                 list_result << Property2String(logo_prop);
0464                 for (const QList<Property> &prop_list : std::as_const(helper_props_map)) {
0465                     list_result << PropertyList2LeafOnlyStringList(prop_list);
0466                 }
0467                 list_result << Property2String(show_help_prop);
0468 
0469                 message = QDBusMessage::createSignal("/kimpanel",
0470                     "org.kde.kimpanel.inputmethod",
0471                     "RegisterProperties");
0472 
0473                 message << list_result;
0474 
0475                 QDBusConnection("scim_panel").send(message);
0476                 */
0477                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "Enable"_L1);
0478                 message << false;
0479                 QDBusConnection("scim_panel"_L1).send(message);
0480                 break;
0481             case DBusEvent::SHOW_HELP:
0482                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ExecDialog"_L1);
0483                 message << Property2String(Property("/Help", "Help", "", ev->data().at(0).toString().toUtf8().constData()));
0484                 QDBusConnection("scim_panel"_L1).send(message);
0485                 break;
0486             case DBusEvent::SHOW_FACTORY_MENU:
0487                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ExecMenu"_L1);
0488                 // X                 _factory_list.clear();
0489                 list_result.clear();
0490                 data = ev->data();
0491                 for (const QVariant &v : std::as_const(data)) {
0492                     PanelFactoryInfo factory_info = v.value<PanelFactoryInfo>();
0493                     // X                     _factory_list << factory_info;
0494                     list_result << Property2String(Property(String(factory_prop_prefix.toUtf8().constData()) + factory_info.uuid,
0495                                                             factory_info.name,
0496                                                             factory_info.icon,
0497                                                             factory_info.lang));
0498                 }
0499                 message << list_result;
0500                 SCIM_DEBUG_MAIN(1) << qPrintable(list_result.join(QLatin1Char(';'))) << "\n";
0501                 QDBusConnection("scim_panel"_L1).send(message);
0502                 break;
0503             case DBusEvent::SHOW_PREEDIT:
0504                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ShowPreedit"_L1);
0505                 message << true;
0506                 QDBusConnection("scim_panel"_L1).send(message);
0507                 break;
0508             case DBusEvent::SHOW_AUX:
0509                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ShowAux"_L1);
0510                 message << true;
0511                 QDBusConnection("scim_panel"_L1).send(message);
0512                 break;
0513             case DBusEvent::SHOW_LOOKUPTABLE:
0514                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ShowLookupTable"_L1);
0515                 message << true;
0516                 QDBusConnection("scim_panel"_L1).send(message);
0517                 break;
0518             case DBusEvent::HIDE_PREEDIT:
0519                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ShowPreedit"_L1);
0520                 message << false;
0521                 QDBusConnection("scim_panel"_L1).send(message);
0522                 break;
0523             case DBusEvent::HIDE_AUX:
0524                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ShowAux"_L1);
0525                 message << false;
0526                 QDBusConnection("scim_panel"_L1).send(message);
0527                 break;
0528             case DBusEvent::HIDE_LOOKUPTABLE:
0529                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ShowLookupTable"_L1);
0530                 message << false;
0531                 QDBusConnection("scim_panel"_L1).send(message);
0532                 break;
0533             case DBusEvent::UP_PROPERTY:
0534                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdateProperty"_L1);
0535                 message << Property2String(ev->data().at(0).value<Property>());
0536                 QDBusConnection("scim_panel"_L1).send(message);
0537                 break;
0538             case DBusEvent::UP_LOOKUPTABLE:
0539                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdateLookupTable"_L1);
0540                 message << ev->data().at(0).toStringList();
0541                 message << ev->data().at(1).toStringList();
0542                 message << ev->data().at(2).toStringList();
0543                 message << ev->data().at(3).toBool();
0544                 message << ev->data().at(4).toBool();
0545                 QDBusConnection("scim_panel"_L1).send(message);
0546                 break;
0547             case DBusEvent::UP_LOOKUPTABLE_CURSOR:
0548                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdateLookupTableCursor"_L1);
0549                 message << ev->data().at(0).toInt();
0550                 QDBusConnection("scim_panel"_L1).send(message);
0551                 break;
0552             case DBusEvent::UP_PREEDIT_CARET:
0553                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdatePreeditCaret"_L1);
0554                 message << ev->data().at(0).toInt();
0555                 QDBusConnection("scim_panel"_L1).send(message);
0556                 break;
0557             case DBusEvent::UP_PREEDIT_STR:
0558                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdatePreeditText"_L1);
0559                 message << ev->data().at(0).toString();
0560                 message << ev->data().at(1).toString();
0561                 QDBusConnection("scim_panel"_L1).send(message);
0562                 break;
0563             case DBusEvent::UP_AUX:
0564                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdateAux"_L1);
0565                 message << ev->data().at(0).toString();
0566                 message << ev->data().at(1).toString();
0567                 QDBusConnection("scim_panel"_L1).send(message);
0568                 break;
0569             case DBusEvent::UP_SPOT_LOC:
0570                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdateSpotLocation"_L1);
0571                 message << ev->data().at(0).toInt();
0572                 message << ev->data().at(1).toInt();
0573                 QDBusConnection("scim_panel"_L1).send(message);
0574                 break;
0575             case DBusEvent::UP_SCREEN:
0576                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdateScreen"_L1);
0577                 message << ev->data().at(0).toInt();
0578                 QDBusConnection("scim_panel"_L1).send(message);
0579                 break;
0580             case DBusEvent::UP_FACTORY_INFO:
0581                 SCIM_DEBUG_MAIN(1) << "update factory info\n";
0582 
0583                 logo_prop.set_icon(ev->data().at(0).value<PanelFactoryInfo>().icon);
0584                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "UpdateProperty"_L1);
0585                 message << Property2String(logo_prop);
0586                 QDBusConnection("scim_panel"_L1).send(message);
0587                 break;
0588             case DBusEvent::REG_HELPER:
0589                 break;
0590             case DBusEvent::REG_HELPER_PROPERTIES:
0591                 helper_props_map.clear();
0592                 prop_list.clear();
0593                 data = ev->data().at(1).toList();
0594                 for (const QVariant &v : std::as_const(data)) {
0595                     Property prop = v.value<Property>();
0596                     prop_list << prop;
0597                 }
0598                 helper_props_map.insert(ev->data().at(0).toInt(), prop_list);
0599 
0600                 list_result.clear();
0601                 list_result << Property2String(logo_prop);
0602                 list_result << PropertyList2LeafOnlyStringList(panel_props);
0603                 for (const QList<Property> &props : std::as_const(helper_props_map)) {
0604                     list_result << PropertyList2LeafOnlyStringList(props);
0605                 }
0606                 list_result << Property2String(show_help_prop);
0607 
0608                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "RegisterProperties"_L1);
0609 
0610                 message << list_result;
0611                 QDBusConnection("scim_panel"_L1).send(message);
0612 
0613                 break;
0614             case DBusEvent::REG_PROPERTIES:
0615                 panel_props.clear();
0616                 data = ev->data();
0617                 for (const QVariant &v : std::as_const(data)) {
0618                     Property prop = v.value<Property>();
0619                     panel_props << prop;
0620                     SCIM_DEBUG_MAIN(1) << "REG_PROPERTIES" << qPrintable(Property2String(v.value<Property>())) << "\n";
0621                 }
0622 
0623                 list_result.clear();
0624                 list_result << Property2String(logo_prop);
0625                 list_result << PropertyList2LeafOnlyStringList(panel_props);
0626                 SCIM_DEBUG_MAIN(1) << "SIMPLIFY_PROPS " << panel_props.size() << " " << list_result.size() - 1 << "\n";
0627                 for (const QList<Property> &props : std::as_const(helper_props_map)) {
0628                     list_result << PropertyList2LeafOnlyStringList(props);
0629                 }
0630                 list_result << Property2String(show_help_prop);
0631 
0632                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "RegisterProperties"_L1);
0633 
0634                 message << list_result;
0635                 QDBusConnection("scim_panel"_L1).send(message);
0636 
0637                 break;
0638             case DBusEvent::RM_HELPER:
0639                 helper_props_map.remove(ev->data().at(0).toInt());
0640                 list_result.clear();
0641                 list_result << Property2String(logo_prop);
0642                 list_result << PropertyList2LeafOnlyStringList(panel_props);
0643                 for (const QList<Property> &props : std::as_const(helper_props_map)) {
0644                     list_result << PropertyList2LeafOnlyStringList(props);
0645                 }
0646                 list_result << Property2String(show_help_prop);
0647 
0648                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "RegisterProperties"_L1);
0649 
0650                 message << list_result;
0651                 QDBusConnection("scim_panel"_L1).send(message);
0652 
0653                 break;
0654             case DBusEvent::RM_PROPERTY:
0655                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "RemoveProperty"_L1);
0656                 // message << ev->data().at(0).V();
0657                 QDBusConnection("scim_panel"_L1).send(message);
0658                 break;
0659             default:
0660                 message = QDBusMessage::createSignal("/kimpanel"_L1, "org.kde.kimpanel.inputmethod"_L1, "ImplementMe"_L1);
0661                 // message << ev->data().at(0).toInt();
0662                 SCIM_DEBUG_MAIN(1) << "Implement me:" << ev->scim_event_type() << "\n";
0663                 QDBusConnection("scim_panel"_L1).send(message);
0664                 break;
0665             }
0666 
0667             return true;
0668         }
0669         return QObject::event(e);
0670     }
0671 
0672 private:
0673     QList<Property> panel_props;
0674     QMap<int, QList<Property>> helper_props_map;
0675     Property logo_prop;
0676     Property show_help_prop;
0677     QString factory_prop_prefix;
0678     QString helper_prop_prefix;
0679     QStringList cached_panel_props;
0680 };
0681 
0682 class PanelAgentThread : public QThread
0683 {
0684     Q_OBJECT
0685 public:
0686     explicit PanelAgentThread(QObject *parent = nullptr)
0687         : QThread(parent)
0688     {
0689     }
0690     ~PanelAgentThread()
0691     {
0692     }
0693     void run() override
0694     {
0695         if (!_panel_agent->run())
0696             std::cerr << "Failed to run Panel.\n";
0697         _global_resource_lock.lock();
0698         _should_exit = true;
0699         _global_resource_lock.unlock();
0700     }
0701 };
0702 
0703 //////////////////////////////////////////////////////////////////////
0704 // Start of PanelAgent Functions
0705 //////////////////////////////////////////////////////////////////////
0706 static bool initialize_panel_agent(const String &config, const String &display, bool resident)
0707 {
0708     _panel_agent = new PanelAgent();
0709 
0710     if (!_panel_agent->initialize(config, display, resident))
0711         return false;
0712 
0713     _panel_agent->signal_connect_transaction_start(slot(slot_transaction_start));
0714     _panel_agent->signal_connect_transaction_end(slot(slot_transaction_end));
0715     _panel_agent->signal_connect_reload_config(slot(slot_reload_config));
0716     _panel_agent->signal_connect_turn_on(slot(slot_turn_on));
0717     _panel_agent->signal_connect_turn_off(slot(slot_turn_off));
0718     _panel_agent->signal_connect_update_screen(slot(slot_update_screen));
0719     _panel_agent->signal_connect_update_spot_location(slot(slot_update_spot_location));
0720     _panel_agent->signal_connect_update_factory_info(slot(slot_update_factory_info));
0721     _panel_agent->signal_connect_show_help(slot(slot_show_help));
0722     _panel_agent->signal_connect_show_factory_menu(slot(slot_show_factory_menu));
0723     _panel_agent->signal_connect_show_preedit_string(slot(slot_show_preedit_string));
0724     _panel_agent->signal_connect_show_aux_string(slot(slot_show_aux_string));
0725     _panel_agent->signal_connect_show_lookup_table(slot(slot_show_lookup_table));
0726     _panel_agent->signal_connect_hide_preedit_string(slot(slot_hide_preedit_string));
0727     _panel_agent->signal_connect_hide_aux_string(slot(slot_hide_aux_string));
0728     _panel_agent->signal_connect_hide_lookup_table(slot(slot_hide_lookup_table));
0729     _panel_agent->signal_connect_update_preedit_string(slot(slot_update_preedit_string));
0730     _panel_agent->signal_connect_update_preedit_caret(slot(slot_update_preedit_caret));
0731     _panel_agent->signal_connect_update_aux_string(slot(slot_update_aux_string));
0732     _panel_agent->signal_connect_update_lookup_table(slot(slot_update_lookup_table));
0733     _panel_agent->signal_connect_register_properties(slot(slot_register_properties));
0734     _panel_agent->signal_connect_update_property(slot(slot_update_property));
0735     _panel_agent->signal_connect_register_helper_properties(slot(slot_register_helper_properties));
0736     _panel_agent->signal_connect_update_helper_property(slot(slot_update_helper_property));
0737     _panel_agent->signal_connect_register_helper(slot(slot_register_helper));
0738     _panel_agent->signal_connect_remove_helper(slot(slot_remove_helper));
0739     _panel_agent->signal_connect_lock(slot(slot_lock));
0740     _panel_agent->signal_connect_unlock(slot(slot_unlock));
0741 
0742     _panel_agent->get_helper_list(_helper_list);
0743 
0744     return true;
0745 }
0746 
0747 static bool run_panel_agent(void)
0748 {
0749     SCIM_DEBUG_MAIN(1) << "run_panel_agent ()\n";
0750 
0751     _panel_agent_thread = NULL;
0752 
0753     if (_panel_agent && _panel_agent->valid()) {
0754         _panel_agent_thread = new PanelAgentThread();
0755         _panel_agent_thread->start();
0756     }
0757 
0758     return (_panel_agent_thread != NULL);
0759 }
0760 
0761 static void start_auto_start_helpers(void)
0762 {
0763     SCIM_DEBUG_MAIN(1) << "start_auto_start_helpers () begin\n";
0764 
0765     // Add Helper object items.
0766     for (size_t i = 0; i < _helper_list.size(); ++i) {
0767         SCIM_DEBUG_MAIN(1) << "--" << _helper_list[i].uuid << "--" << _helper_list[i].name << "--\n";
0768         if ((_helper_list[i].option & SCIM_HELPER_AUTO_START)) {
0769             _panel_agent->start_helper(_helper_list[i].uuid);
0770         }
0771     }
0772     SCIM_DEBUG_MAIN(1) << "start_auto_start_helpers () end\n";
0773 }
0774 
0775 static void slot_transaction_start(void)
0776 {
0777     SCIM_DEBUG_MAIN(1) << "slot_transaction_start ()\n";
0778     _transaction_lock.lock();
0779 }
0780 
0781 static void slot_transaction_end(void)
0782 {
0783     SCIM_DEBUG_MAIN(1) << "slot_transaction_end ()\n";
0784     _transaction_lock.unlock();
0785 }
0786 
0787 static void slot_reload_config(void)
0788 {
0789     SCIM_DEBUG_MAIN(1) << "slot_reload_config ()\n";
0790     if (!_config.null())
0791         _config->reload();
0792     else
0793         SCIM_DEBUG_MAIN(1) << "config is null\n";
0794 }
0795 
0796 static void slot_turn_on(void)
0797 {
0798     SCIM_DEBUG_MAIN(1) << "slot_turn_on ()" << _dbus_handler << "\n";
0799     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::TURN_ON));
0800 }
0801 
0802 static void slot_turn_off(void)
0803 {
0804     SCIM_DEBUG_MAIN(1) << "slot_turn_off ()\n";
0805     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::TURN_OFF));
0806 
0807     /*
0808      */
0809 }
0810 
0811 static void slot_update_screen(int num)
0812 {
0813     SCIM_DEBUG_MAIN(1) << "slot_update_screen ()\n";
0814     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_SCREEN, QVariantList() << num));
0815 }
0816 
0817 static void slot_update_factory_info(const PanelFactoryInfo &info)
0818 {
0819     SCIM_DEBUG_MAIN(1) << "slot_update_factory_info ()\n";
0820     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_FACTORY_INFO, QVariantList() << QVariant::fromValue(info)));
0821 }
0822 
0823 static void slot_show_help(const String &help)
0824 {
0825     SCIM_DEBUG_MAIN(1) << "slot_show_help ()\n";
0826     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_HELP, QVariantList() << QString::fromUtf8(help.c_str())));
0827 }
0828 
0829 static void slot_show_factory_menu(const std::vector<PanelFactoryInfo> &factories)
0830 {
0831     SCIM_DEBUG_MAIN(1) << "slot_show_factory_menu ()\n";
0832     QVariantList list;
0833     for (const PanelFactoryInfo &info : factories) {
0834         list << QVariant::fromValue(info);
0835     }
0836     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_FACTORY_MENU, list));
0837 }
0838 
0839 static void slot_update_spot_location(int x, int y)
0840 {
0841     SCIM_DEBUG_MAIN(1) << "slot_update_spot_location ()\n";
0842     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_SPOT_LOC, QVariantList() << x << y));
0843 }
0844 
0845 static void slot_show_preedit_string(void)
0846 {
0847     SCIM_DEBUG_MAIN(1) << "slot_show_preedit_string ()\n";
0848     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_PREEDIT));
0849 }
0850 
0851 static void slot_show_aux_string(void)
0852 {
0853     SCIM_DEBUG_MAIN(1) << "slot_show_aux_string ()\n";
0854     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_AUX));
0855 }
0856 
0857 static void slot_show_lookup_table(void)
0858 {
0859     SCIM_DEBUG_MAIN(1) << "slot_show_lookup_table ()\n";
0860     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_LOOKUPTABLE));
0861 }
0862 
0863 static void slot_hide_preedit_string(void)
0864 {
0865     SCIM_DEBUG_MAIN(1) << "slot_hide_preedit_string ()\n";
0866     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::HIDE_PREEDIT));
0867 }
0868 
0869 static void slot_hide_aux_string(void)
0870 {
0871     SCIM_DEBUG_MAIN(1) << "slot_hide_aux_string ()\n";
0872     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::HIDE_AUX));
0873 }
0874 
0875 static void slot_hide_lookup_table(void)
0876 {
0877     SCIM_DEBUG_MAIN(1) << "slot_hide_lookup_table ()\n";
0878     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::HIDE_LOOKUPTABLE));
0879 }
0880 
0881 static void slot_update_preedit_string(const String &str, const AttributeList &attrs)
0882 {
0883     SCIM_DEBUG_MAIN(1) << "slot_update_preedit_string ()" << str << "\n";
0884     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_PREEDIT_STR, QVariantList() << QString::fromUtf8(str.c_str()) << AttrList2String(attrs)));
0885 }
0886 
0887 static void slot_update_preedit_caret(int caret)
0888 {
0889     SCIM_DEBUG_MAIN(1) << "slot_update_preedit_caret ()" << caret << "\n";
0890     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_PREEDIT_CARET, QVariantList() << caret));
0891 }
0892 
0893 static void slot_update_aux_string(const String &str, const AttributeList &attrs)
0894 {
0895     SCIM_DEBUG_MAIN(1) << "slot_update_aux_string ()" << str << "\n";
0896     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_AUX, QVariantList() << QString::fromUtf8(str.c_str()) << AttrList2String(attrs)));
0897 }
0898 
0899 static void slot_update_lookup_table(const LookupTable &table)
0900 {
0901     SCIM_DEBUG_MAIN(1) << "slot_update_lookup_table ()\n";
0902     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_LOOKUPTABLE, LookupTable2VariantList(table)));
0903 
0904     qApp->postEvent(
0905         _dbus_handler,
0906         new DBusEvent(DBusEvent::UP_LOOKUPTABLE_CURSOR, QVariantList() << (table.is_cursor_visible() ? table.get_cursor_pos_in_current_page() : -1)));
0907 }
0908 
0909 static void slot_register_properties(const PropertyList &props)
0910 {
0911     SCIM_DEBUG_MAIN(1) << "slot_register_properties ()\n";
0912     QVariantList list;
0913     for (const Property &prop : props) {
0914         list << QVariant::fromValue(prop);
0915     }
0916     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::REG_PROPERTIES, list));
0917 }
0918 
0919 static void slot_update_property(const Property &prop)
0920 {
0921     SCIM_DEBUG_MAIN(1) << "slot_update_property ()\n";
0922     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_PROPERTY, QVariantList() << QVariant::fromValue(prop)));
0923 }
0924 
0925 static void slot_register_helper_properties(int id, const PropertyList &props)
0926 {
0927     SCIM_DEBUG_MAIN(1) << "slot_register_helper_properties ()\n";
0928     QVariantList list;
0929     for (const Property &prop : props) {
0930         list << QVariant::fromValue(prop);
0931     }
0932     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::REG_HELPER_PROPERTIES, QVariantList() << id << list));
0933 }
0934 
0935 static void slot_update_helper_property(int id, const Property &prop)
0936 {
0937     SCIM_DEBUG_MAIN(1) << "slot_update_helper_property ()\n";
0938     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_HELPER_PROPERTY, QVariantList() << id << QVariant::fromValue(prop)));
0939 }
0940 
0941 static void slot_register_helper(int id, const HelperInfo &helper)
0942 {
0943     SCIM_DEBUG_MAIN(1) << "slot_register_helper ()\n";
0944     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::REG_HELPER, QVariantList() << id << QVariant::fromValue(helper)));
0945 }
0946 
0947 static void slot_remove_helper(int id)
0948 {
0949     SCIM_DEBUG_MAIN(1) << "slot_remove_helper ()\n";
0950     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::RM_HELPER, QVariantList() << id));
0951 }
0952 
0953 static void slot_lock(void)
0954 {
0955     SCIM_DEBUG_MAIN(1) << "slot_lock ()\n";
0956     //_panel_agent_lock.lock();
0957 }
0958 
0959 static void slot_unlock(void)
0960 {
0961     SCIM_DEBUG_MAIN(1) << "slot_unlock ()\n";
0962     //_panel_agent_lock.unlock();
0963 }
0964 //////////////////////////////////////////////////////////////////////
0965 // End of PanelAgent-Functions
0966 //////////////////////////////////////////////////////////////////////
0967 
0968 static void signalhandler(int sig)
0969 {
0970     Q_UNUSED(sig)
0971     SCIM_DEBUG_MAIN(1) << "In signal handler...\n";
0972 
0973     if (_panel_agent)
0974         _panel_agent->stop();
0975 }
0976 
0977 int main(int argc, char *argv[])
0978 {
0979     std::vector<String> config_list;
0980 
0981     int i;
0982 
0983     bool daemon = false;
0984 
0985     int new_argc = 0;
0986     char **new_argv = new char *[40];
0987 
0988     String config_name("simple");
0989     String display_name;
0990     bool should_resident = true;
0991 
0992     //    QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
0993     // Display version info
0994     //    std::cerr << "GTK Panel of SCIM " << SCIM_VERSION << "\n\n";
0995 
0996     // get modules list
0997     scim_get_config_module_list(config_list);
0998 
0999     // Add a dummy config module, it's not really a module!
1000     config_list.push_back("dummy");
1001 
1002     // Use socket Config module as default if available.
1003     if (!config_list.empty()) {
1004         if (std::find(config_list.begin(), config_list.end(), config_name) == config_list.end())
1005             config_name = config_list[0];
1006     }
1007 
1008     // DebugOutput::set_output("/home/ora/a.log");
1009     // DebugOutput::enable_debug (SCIM_DEBUG_AllMask);
1010 
1011     // parse command options
1012     i = 0;
1013     while (i < argc) {
1014         if (++i >= argc)
1015             break;
1016 
1017         if (String("-l") == argv[i] || String("--list") == argv[i]) {
1018             std::vector<String>::iterator it;
1019 
1020             std::cout << "\n";
1021             std::cout << "Available Config module:\n";
1022             for (it = config_list.begin(); it != config_list.end(); ++it)
1023                 std::cout << "    " << *it << "\n";
1024 
1025             return 0;
1026         }
1027 
1028         if (String("-c") == argv[i] || String("--config") == argv[i]) {
1029             if (++i >= argc) {
1030                 std::cerr << "no argument for option " << argv[i - 1] << "\n";
1031                 return -1;
1032             }
1033             config_name = argv[i];
1034             continue;
1035         }
1036 
1037         if (String("-h") == argv[i] || String("--help") == argv[i]) {
1038             std::cout << "Usage: " << argv[0] << " [option]...\n\n"
1039                       << "The options are: \n"
1040                       << "  --display DISPLAY    Run on display DISPLAY.\n"
1041                       << "  -l, --list           List all of available config modules.\n"
1042                       << "  -c, --config NAME    Uses specified Config module.\n"
1043                       << "  -d, --daemon         Run " << argv[0] << " as a daemon.\n"
1044                       << "  -ns, --no-stay       Quit if no connected client.\n"
1045 #if ENABLE_DEBUG
1046                       << "  -v, --verbose LEVEL  Enable debug info, to specific LEVEL.\n"
1047                       << "  -o, --output FILE    Output debug information into FILE.\n"
1048 #endif
1049                       << "  -h, --help           Show this help message.\n";
1050             return 0;
1051         }
1052 
1053         if (String("-d") == argv[i] || String("--daemon") == argv[i]) {
1054             daemon = true;
1055             continue;
1056         }
1057 
1058         if (String("-ns") == argv[i] || String("--no-stay") == argv[i]) {
1059             should_resident = false;
1060             continue;
1061         }
1062 
1063         if (String("-v") == argv[i] || String("--verbose") == argv[i]) {
1064             if (++i >= argc) {
1065                 std::cerr << "no argument for option " << argv[i - 1] << "\n";
1066                 return -1;
1067             }
1068             DebugOutput::set_verbose_level(atoi(argv[i]));
1069             continue;
1070         }
1071 
1072         if (String("-o") == argv[i] || String("--output") == argv[i]) {
1073             if (++i >= argc) {
1074                 std::cerr << "No argument for option " << argv[i - 1] << "\n";
1075                 return -1;
1076             }
1077             DebugOutput::set_output(argv[i]);
1078             continue;
1079         }
1080 
1081         if (String("--display") == argv[i]) {
1082             if (++i >= argc) {
1083                 std::cerr << "No argument for option " << argv[i - 1] << "\n";
1084                 return -1;
1085             }
1086             display_name = argv[i];
1087             continue;
1088         }
1089 
1090         if (String("--") == argv[i])
1091             break;
1092 
1093         std::cerr << "Invalid command line option: " << argv[i] << "\n";
1094         return -1;
1095     } // End of command line parsing.
1096 
1097     new_argv[new_argc++] = argv[0];
1098 
1099     // Store the rest argvs into new_argv.
1100     for (++i; i < argc && new_argc < 40; ++i) {
1101         new_argv[new_argc++] = argv[i];
1102     }
1103 
1104     // Make up DISPLAY env.
1105     if (display_name.length()) {
1106         new_argv[new_argc++] = strdup("--display");
1107         new_argv[new_argc++] = const_cast<char *>(display_name.c_str());
1108 
1109         setenv("DISPLAY", display_name.c_str(), 1);
1110     }
1111 
1112     new_argv[new_argc] = 0;
1113 
1114     if (!config_name.length()) {
1115         std::cerr << "No Config module is available!\n";
1116         return -1;
1117     }
1118 
1119     if (config_name != "dummy") {
1120         // load config module
1121         _config_module = new ConfigModule(config_name);
1122 
1123         if (!_config_module || !_config_module->valid()) {
1124             std::cerr << "Can not load " << config_name << " Config module.\n";
1125             return -1;
1126         }
1127 
1128         // create config instance
1129         _config = _config_module->create_config();
1130     } else {
1131         _config = new DummyConfig();
1132     }
1133 
1134     if (_config.null()) {
1135         std::cerr << "Failed to create Config instance from " << config_name << " Config module.\n";
1136         return -1;
1137     }
1138 
1139     KDE_signal(SIGQUIT, signalhandler);
1140     KDE_signal(SIGTERM, signalhandler);
1141     KDE_signal(SIGINT, signalhandler);
1142     KDE_signal(SIGHUP, signalhandler);
1143 
1144     const QByteArray display = qgetenv("DISPLAY");
1145     if (display.constData())
1146         display_name = String(display.constData());
1147 
1148     if (!initialize_panel_agent(config_name, display_name, should_resident)) {
1149         std::cerr << "Failed to initialize Panel Agent!\n";
1150         return -1;
1151     }
1152 
1153     if (daemon)
1154         scim_daemon();
1155 
1156     // connect the configuration reload signal.
1157     _config->signal_connect_reload(slot(ui_config_reload_callback));
1158 
1159     qRegisterMetaType<scim::Property>("scim::Property");
1160     qRegisterMetaType<PanelFactoryInfo>("PanelFactoryInfo");
1161     qRegisterMetaType<HelperInfo>("HelperInfo");
1162 
1163     QDBusConnection::connectToBus(QDBusConnection::SessionBus, "scim_panel"_L1);
1164     _dbus_handler = new DBusHandler();
1165     _dbus_handler->setInitialHelpers(_helper_list);
1166 
1167     if (!run_panel_agent()) {
1168         std::cerr << "Failed to run Socket Server!\n";
1169         return -1;
1170     }
1171 
1172     start_auto_start_helpers();
1173 
1174     QCoreApplication app(argc, argv);
1175     app.exec();
1176 
1177     _panel_agent_thread->wait();
1178     _config.reset();
1179 
1180     std::cerr << "Successfully exited.\n";
1181 
1182     return 0;
1183 }
1184 
1185 #include "main.moc"
1186 
1187 #undef QT_NO_KEYWORDS
1188 
1189 /*
1190 vim:ts=4:nowrap:expandtab
1191 */