1 /*
2     SPDX-FileCopyrightText: 2009 Wang Hoi <zealot.hoi@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 /** @file scim_panel_dbus.cpp
8  */
9 
10 #define KDE_signal signal
11 
12 #undef QT_NO_STL
13 #define QT_STL
14 
15 #define QT_NO_KEYWORDS
16 
17 #include <config-scim.h>
18 #include <errno.h>
19 #include <list>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 
27 #include <QCoreApplication>
28 #include <QDBusConnection>
29 #include <QDBusMessage>
30 #include <QMutex>
31 #include <QObject>
32 #include <QProcess>
33 #include <QString>
34 #include <QStringList>
35 #include <QThread>
36 
37 #define Uses_C_STDIO
38 #define Uses_C_STDLIB
39 #define Uses_SCIM_LOOKUP_TABLE
40 #define Uses_SCIM_SOCKET
41 #define Uses_SCIM_TRANSACTION
42 #define Uses_SCIM_TRANS_COMMANDS
43 #define Uses_SCIM_CONFIG
44 #define Uses_SCIM_CONFIG_MODULE
45 //#define Uses_SCIM_DEBUG
46 #define Uses_SCIM_HELPER
47 #define Uses_SCIM_HELPER_MODULE
48 #define Uses_SCIM_PANEL_AGENT
49 #define Uses_STL_MAP
50 
51 #define ENABLE_DEBUG 9
52 // scim use exceptions and template, so it doesn't work in hidden visibility
53 #pragma GCC visibility push(default)
54 #include <scim.h>
55 #pragma GCC visibility pop
56 
57 Q_DECLARE_METATYPE(scim::Property)
58 Q_DECLARE_METATYPE(scim::PanelFactoryInfo)
59 Q_DECLARE_METATYPE(scim::HelperInfo)
60 
61 using namespace scim;
62 
63 // PanelAgent related functions
64 static bool initialize_panel_agent(const String &config, const String &display, bool resident);
65 static bool run_panel_agent(void);
66 static void start_auto_start_helpers(void);
67 
68 static void slot_transaction_start(void);
69 static void slot_transaction_end(void);
70 static void slot_reload_config(void);
71 static void slot_turn_on(void);
72 static void slot_turn_off(void);
73 static void slot_update_screen(int screen);
74 static void slot_update_spot_location(int x, int y);
75 static void slot_update_factory_info(const PanelFactoryInfo &info);
76 static void slot_show_help(const String &help);
77 static void slot_show_factory_menu(const std::vector<PanelFactoryInfo> &menu);
78 
79 static void slot_show_preedit_string(void);
80 static void slot_show_aux_string(void);
81 static void slot_show_lookup_table(void);
82 static void slot_hide_preedit_string(void);
83 static void slot_hide_aux_string(void);
84 static void slot_hide_lookup_table(void);
85 static void slot_update_preedit_string(const String &str, const AttributeList &attrs);
86 static void slot_update_preedit_caret(int caret);
87 static void slot_update_aux_string(const String &str, const AttributeList &attrs);
88 static void slot_update_lookup_table(const LookupTable &table);
89 static void slot_register_properties(const PropertyList &props);
90 static void slot_update_property(const Property &prop);
91 
92 static void slot_register_helper_properties(int id, const PropertyList &props);
93 static void slot_update_helper_property(int id, const Property &prop);
94 static void slot_register_helper(int id, const HelperInfo &helper);
95 static void slot_remove_helper(int id);
96 static void slot_lock(void);
97 static void slot_unlock(void);
98 
99 /////////////////////////////////////////////////////////////////////////////
100 // Declaration of internal variables.
101 /////////////////////////////////////////////////////////////////////////////
102 // static bool               _ui_initialized              = false;
103 
104 static ConfigModule *_config_module = nullptr;
105 static ConfigPointer _config;
106 
107 static std::vector<HelperInfo> _helper_list;
108 
109 static bool _should_exit = false;
110 
111 // static bool               _panel_is_on                 = false;
112 
113 static PanelAgent *_panel_agent = nullptr;
114 
115 static QList<PanelFactoryInfo> _factory_list;
116 
117 class PanelAgentThread;
118 PanelAgentThread *_panel_agent_thread;
119 
120 class DBusHandler;
121 DBusHandler *_dbus_handler;
122 
123 static QMutex _panel_agent_lock;
124 static QMutex _global_resource_lock;
125 static QMutex _transaction_lock;
126 
127 /////////////////////////////////////////////////////////////////////////////
128 // Implementation of internal functions.
129 /////////////////////////////////////////////////////////////////////////////
130 
ui_config_reload_callback(const ConfigPointer & config)131 static void ui_config_reload_callback(const ConfigPointer &config)
132 {
133     _config = config;
134 }
135 
AttrList2String(const AttributeList & attr_list)136 static QString AttrList2String(const AttributeList &attr_list)
137 {
138     QString result;
139     Q_FOREACH (const Attribute &attr, attr_list) {
140         int type = (int)attr.get_type();
141         unsigned int start = attr.get_start();
142         unsigned int length = attr.get_length();
143         unsigned int value = attr.get_value();
144         result += QString("%1:%2:%3:%4;").arg(type).arg(start).arg(length).arg(value);
145     }
146     return result;
147 }
148 
LookupTable2VariantList(const LookupTable & lookup_table)149 static QVariantList LookupTable2VariantList(const LookupTable &lookup_table)
150 {
151     QVariantList result;
152     QStringList labels;
153     QStringList candidates;
154     QStringList attrlist_list;
155     int current_page_size = lookup_table.get_current_page_size();
156 
157     for (int i = 0; i < current_page_size; ++i) {
158         labels << QString::fromStdWString(lookup_table.get_candidate_label(i));
159     }
160     for (int i = 0; i < current_page_size; ++i) {
161         candidates << QString::fromStdWString(lookup_table.get_candidate_in_current_page(i));
162         attrlist_list << AttrList2String(lookup_table.get_attributes_in_current_page(i));
163     }
164 
165     result << labels << candidates << attrlist_list << lookup_table.get_current_page_start()
166            << (lookup_table.get_current_page_start() + lookup_table.get_current_page_size() < ((int)lookup_table.number_of_candidates()));
167 
168     // result << labels << candidates << attrlist_list;
169     return result;
170 }
171 
Property2String(const Property & prop)172 static QString Property2String(const Property &prop)
173 {
174     QString result;
175     int state = 0;
176     if (prop.active())
177         state |= SCIM_PROPERTY_ACTIVE;
178     if (prop.visible())
179         state |= SCIM_PROPERTY_VISIBLE;
180     result = QString("%1:%2:%3:%4:%5")
181                  .arg(QString::fromUtf8(prop.get_key().c_str()))
182                  .arg(QString::fromUtf8(prop.get_label().c_str()))
183                  .arg(QString::fromUtf8(prop.get_icon().c_str()))
184                  .arg(QString::fromUtf8(prop.get_tip().c_str()))
185                  .arg(state);
186     return result;
187 }
188 
189 #if 0
190 static QString
191 PanelFactoryInfo2String(const PanelFactoryInfo &info)
192 {
193     QString result = QString("%1:%2:%3:%4")
194                      .arg(QString::fromUtf8(info.uuid.c_str()))
195                      .arg(QString::fromUtf8(info.name.c_str()))
196                      .arg(QString::fromUtf8(info.icon.c_str()))
197                      .arg(QString::fromUtf8(info.lang.c_str()));
198     return result;
199 }
200 #endif
201 
PropertyList2LeafOnlyStringList(const QList<Property> & props)202 static QStringList PropertyList2LeafOnlyStringList(const QList<Property> &props)
203 {
204     QStringList list;
205     list.clear();
206     for (int i = 0; i < props.size(); ++i) {
207         bool ok = true;
208         for (int j = 0; j < props.size(); ++j) {
209             if (props.at(i).is_a_leaf_of(props.at(j))) {
210                 SCIM_DEBUG_MAIN(1) << "Leaf" << props.at(i).get_key() << " " << props.at(j).get_key() << "\n";
211                 ok = false;
212             }
213         }
214         if (ok)
215             list << Property2String(props.at(i));
216     }
217     return list;
218 }
219 
220 static int dbus_event_type = QEvent::registerEventType(1988);
221 class DBusEvent : public QEvent
222 {
223 public:
224     enum SCIM_EVENT_TYPE {
225         TURN_ON,
226         TURN_OFF,
227         UP_SCREEN,
228         UP_SPOT_LOC,
229         UP_AUX,
230         UP_PREEDIT_STR,
231         UP_PREEDIT_CARET,
232         UP_LOOKUPTABLE,
233         UP_LOOKUPTABLE_CURSOR,
234         UP_FACTORY_INFO,
235         UP_PROPERTY,
236         UP_HELPER_PROPERTY,
237         REG_PROPERTIES,
238         REG_HELPER_PROPERTIES,
239         REG_HELPER,
240         RM_HELPER,
241         RM_PROPERTY,
242         SHOW_LOOKUPTABLE,
243         HIDE_LOOKUPTABLE,
244         SHOW_PREEDIT,
245         HIDE_PREEDIT,
246         SHOW_AUX,
247         HIDE_AUX,
248         SHOW_HELP,
249         SHOW_FACTORY_MENU,
250     };
DBusEvent(SCIM_EVENT_TYPE t,const QVariantList & arglist=QVariantList ())251     DBusEvent(SCIM_EVENT_TYPE t, const QVariantList &arglist = QVariantList())
252         : QEvent((QEvent::Type)dbus_event_type)
253         , m_evtype(t)
254         , m_data(arglist)
255     {
256     }
scim_event_type() const257     SCIM_EVENT_TYPE scim_event_type() const
258     {
259         return m_evtype;
260     }
data() const261     QVariantList data() const
262     {
263         return m_data;
264     }
265 
266 private:
267     SCIM_EVENT_TYPE m_evtype;
268     QVariantList m_data;
269 };
270 class DBusHandler : public QObject
271 {
272     Q_OBJECT
273 public:
DBusHandler(QObject * parent=nullptr)274     explicit DBusHandler(QObject *parent = nullptr)
275         : QObject(parent)
276     {
277         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "MovePreeditCaret", this, SLOT(MovePreeditCaret(int)));
278         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "SelectCandidate", this, SLOT(SelectCandidate(int)));
279         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "LookupTablePageUp", this, SLOT(LookupTablePageUp()));
280         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "LookupTablePageDown", this, SLOT(LookupTablePageDown()));
281         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "TriggerProperty", this, SLOT(TriggerProperty(QString)));
282         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "PanelCreated", this, SLOT(PanelCreated()));
283         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "Exit", this, SLOT(Exit()));
284         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "ReloadConfig", this, SLOT(ReloadConfig()));
285         QDBusConnection("scim_panel").connect("", "", "org.kde.impanel", "Configure", this, SLOT(Configure()));
286 
287         logo_prop = Property("/Logo", "SCIM", String(SCIM_ICON_DIR) + "/trademark.png", "SCIM Input Method");
288         show_help_prop = Property("/StartHelp", "Help", "help-about", "About SCIM…");
289         factory_prop_prefix = QString::fromUtf8("/Factory/");
290         helper_prop_prefix = QString::fromUtf8("/Helper/");
291     }
~DBusHandler()292     ~DBusHandler()
293     {
294     }
295 
setInitialHelpers(const std::vector<HelperInfo> & _helper_list)296     void setInitialHelpers(const std::vector<HelperInfo> &_helper_list)
297     {
298         QList<Property> props;
299         Q_FOREACH (const HelperInfo &info, _helper_list) {
300             if (((info.option & SCIM_HELPER_STAND_ALONE) != 0) && ((info.option & SCIM_HELPER_AUTO_START) == 0)) {
301                 props << Property(String(helper_prop_prefix.toUtf8().constData()) + info.uuid, info.name, info.icon, info.description);
302             }
303         }
304         if (!props.isEmpty()) {
305             helper_props_map.insert(0, props);
306         }
307     }
308 public Q_SLOTS:
MovePreeditCaret(int pos)309     void MovePreeditCaret(int pos)
310     {
311         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << pos << "\n";
312         _panel_agent->move_preedit_caret(pos);
313     }
SelectCandidate(int idx)314     void SelectCandidate(int idx)
315     {
316         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << idx << "\n";
317         _panel_agent->select_candidate(idx);
318     }
LookupTablePageUp()319     void LookupTablePageUp()
320     {
321         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
322         _panel_agent->lookup_table_page_up();
323     }
LookupTablePageDown()324     void LookupTablePageDown()
325     {
326         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
327         _panel_agent->lookup_table_page_down();
328     }
TriggerProperty(const QString & key)329     void TriggerProperty(const QString &key)
330     {
331         SCIM_DEBUG_MAIN(1) << qPrintable(key) << "\n";
332         if (key == show_help_prop.get_key().c_str()) {
333             SCIM_DEBUG_MAIN(1) << "about_to_show_help"
334                                << "\n";
335             _panel_agent->request_help();
336             return;
337         }
338         if (key == logo_prop.get_key().c_str()) {
339             SCIM_DEBUG_MAIN(1) << "about_to_show_factory_menu"
340                                << "\n";
341             _panel_agent->request_factory_menu();
342             return;
343         }
344         if (key.startsWith(factory_prop_prefix)) {
345             QString factory_uuid = key;
346             factory_uuid.remove(0, factory_prop_prefix.size());
347             SCIM_DEBUG_MAIN(1) << "about_to_change_factory" << qPrintable(factory_uuid) << "\n";
348             _panel_agent->change_factory(factory_uuid.toUtf8().constData());
349             return;
350         }
351         if (key.startsWith(helper_prop_prefix)) {
352             QString helper_uuid = key;
353             helper_uuid.remove(0, helper_prop_prefix.size());
354             SCIM_DEBUG_MAIN(1) << "about_to_start_helper" << qPrintable(helper_uuid) << "\n";
355             _panel_agent->start_helper(helper_uuid.toUtf8().constData());
356             return;
357         }
358         int i = 0;
359         for (i = 0; i < panel_props.size(); ++i) {
360             if (panel_props.at(i).get_key() == String(key.toUtf8().constData())) {
361                 break;
362             }
363         }
364         // found one
365         QStringList list_result;
366         list_result.clear();
367         if (i < panel_props.size()) {
368             for (int j = 0; j < panel_props.size(); ++j) {
369                 if (panel_props.at(j).is_a_leaf_of(panel_props.at(i))) {
370                     list_result << Property2String(panel_props.at(j));
371                 }
372             }
373             if (list_result.isEmpty()) {
374                 _panel_agent->trigger_property(key.toUtf8().constData());
375             } else {
376                 SCIM_DEBUG_MAIN(1) << "ExecMenu" << qPrintable(key) << "\n";
377                 QDBusMessage message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu");
378                 message << list_result;
379                 QDBusConnection("scim_panel").send(message);
380             }
381         }
382     }
PanelCreated()383     void PanelCreated()
384     {
385         QDBusMessage message;
386         QStringList list_result;
387 
388         list_result.clear();
389         list_result << Property2String(logo_prop);
390         list_result << PropertyList2LeafOnlyStringList(panel_props);
391 
392         Q_FOREACH (const QList<Property> &props, helper_props_map) {
393             list_result << PropertyList2LeafOnlyStringList(props);
394         }
395 
396         list_result << Property2String(show_help_prop);
397 
398         message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "RegisterProperties");
399 
400         message << list_result;
401         QDBusConnection("scim_panel").send(message);
402     }
Exit()403     void Exit()
404     {
405         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
406         _panel_agent->exit();
407         _panel_agent->stop();
408         exit(1);
409     }
ReloadConfig()410     void ReloadConfig()
411     {
412         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
413         _panel_agent->reload_config();
414         if (!_config.null())
415             _config->reload();
416     }
Configure()417     void Configure()
418     {
419         SCIM_DEBUG_MAIN(1) << Q_FUNC_INFO << "\n";
420         QProcess::startDetached("scim-setup");
421     }
422 
423 protected:
event(QEvent * e)424     bool event(QEvent *e) override
425     {
426         QStringList list_result;
427         QList<Property> prop_list;
428         if (e->type() == dbus_event_type) {
429             DBusEvent *ev = (DBusEvent *)e;
430 
431             QDBusMessage message;
432 
433             switch (ev->scim_event_type()) {
434             case DBusEvent::TURN_ON:
435                 /*
436                                 list_result.clear();
437                                 list_result << Property2String(logo_prop);
438                                 list_result << PropertyList2LeafOnlyStringList(panel_props);
439                                 Q_FOREACH(const QList<Property> &props, helper_props_map.values()) {
440                                     list_result << PropertyList2LeafOnlyStringList(props);
441                                 }
442                                 list_result << Property2String(show_help_prop);
443 
444                                 message = QDBusMessage::createSignal("/kimpanel",
445                                     "org.kde.kimpanel.inputmethod",
446                                     "RegisterProperties");
447 
448                                 message << list_result;
449                                 QDBusConnection("scim_panel").send(message);
450                 */
451                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "Enable");
452                 message << true;
453                 QDBusConnection("scim_panel").send(message);
454                 break;
455             case DBusEvent::TURN_OFF:
456                 logo_prop.set_icon(String(SCIM_ICON_DIR) + "/trademark.png");
457 
458                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty");
459                 message << Property2String(logo_prop);
460                 QDBusConnection("scim_panel").send(message);
461                 /*
462                                 list_result.clear();
463                                 list_result << Property2String(logo_prop);
464                                 Q_FOREACH (const QList<Property> &prop_list, helper_props_map.values()) {
465                                     list_result << PropertyList2LeafOnlyStringList(prop_list);
466                                 }
467                                 list_result << Property2String(show_help_prop);
468 
469                                 message = QDBusMessage::createSignal("/kimpanel",
470                                     "org.kde.kimpanel.inputmethod",
471                                     "RegisterProperties");
472 
473                                 message << list_result;
474 
475                                 QDBusConnection("scim_panel").send(message);
476                 */
477                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "Enable");
478                 message << false;
479                 QDBusConnection("scim_panel").send(message);
480                 break;
481             case DBusEvent::SHOW_HELP:
482                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ExecDialog");
483                 message << Property2String(Property("/Help", "Help", "", ev->data().at(0).toString().toUtf8().constData()));
484                 QDBusConnection("scim_panel").send(message);
485                 break;
486             case DBusEvent::SHOW_FACTORY_MENU:
487                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ExecMenu");
488                 // X                 _factory_list.clear();
489                 list_result.clear();
490                 Q_FOREACH (const QVariant &v, ev->data()) {
491                     PanelFactoryInfo factory_info = v.value<PanelFactoryInfo>();
492                     // X                     _factory_list << factory_info;
493                     list_result << Property2String(Property(String(factory_prop_prefix.toUtf8().constData()) + factory_info.uuid,
494                                                             factory_info.name,
495                                                             factory_info.icon,
496                                                             factory_info.lang));
497                 }
498                 message << list_result;
499                 SCIM_DEBUG_MAIN(1) << qPrintable(list_result.join(";")) << "\n";
500                 QDBusConnection("scim_panel").send(message);
501                 break;
502             case DBusEvent::SHOW_PREEDIT:
503                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit");
504                 message << true;
505                 QDBusConnection("scim_panel").send(message);
506                 break;
507             case DBusEvent::SHOW_AUX:
508                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux");
509                 message << true;
510                 QDBusConnection("scim_panel").send(message);
511                 break;
512             case DBusEvent::SHOW_LOOKUPTABLE:
513                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable");
514                 message << true;
515                 QDBusConnection("scim_panel").send(message);
516                 break;
517             case DBusEvent::HIDE_PREEDIT:
518                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ShowPreedit");
519                 message << false;
520                 QDBusConnection("scim_panel").send(message);
521                 break;
522             case DBusEvent::HIDE_AUX:
523                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ShowAux");
524                 message << false;
525                 QDBusConnection("scim_panel").send(message);
526                 break;
527             case DBusEvent::HIDE_LOOKUPTABLE:
528                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ShowLookupTable");
529                 message << false;
530                 QDBusConnection("scim_panel").send(message);
531                 break;
532             case DBusEvent::UP_PROPERTY:
533                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty");
534                 message << Property2String(ev->data().at(0).value<Property>());
535                 QDBusConnection("scim_panel").send(message);
536                 break;
537             case DBusEvent::UP_LOOKUPTABLE:
538                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateLookupTable");
539                 message << ev->data().at(0).toStringList();
540                 message << ev->data().at(1).toStringList();
541                 message << ev->data().at(2).toStringList();
542                 message << ev->data().at(3).toBool();
543                 message << ev->data().at(4).toBool();
544                 QDBusConnection("scim_panel").send(message);
545                 break;
546             case DBusEvent::UP_LOOKUPTABLE_CURSOR:
547                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateLookupTableCursor");
548                 message << ev->data().at(0).toInt();
549                 QDBusConnection("scim_panel").send(message);
550                 break;
551             case DBusEvent::UP_PREEDIT_CARET:
552                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditCaret");
553                 message << ev->data().at(0).toInt();
554                 QDBusConnection("scim_panel").send(message);
555                 break;
556             case DBusEvent::UP_PREEDIT_STR:
557                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdatePreeditText");
558                 message << ev->data().at(0).toString();
559                 message << ev->data().at(1).toString();
560                 QDBusConnection("scim_panel").send(message);
561                 break;
562             case DBusEvent::UP_AUX:
563                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateAux");
564                 message << ev->data().at(0).toString();
565                 message << ev->data().at(1).toString();
566                 QDBusConnection("scim_panel").send(message);
567                 break;
568             case DBusEvent::UP_SPOT_LOC:
569                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateSpotLocation");
570                 message << ev->data().at(0).toInt();
571                 message << ev->data().at(1).toInt();
572                 QDBusConnection("scim_panel").send(message);
573                 break;
574             case DBusEvent::UP_SCREEN:
575                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateScreen");
576                 message << ev->data().at(0).toInt();
577                 QDBusConnection("scim_panel").send(message);
578                 break;
579             case DBusEvent::UP_FACTORY_INFO:
580                 SCIM_DEBUG_MAIN(1) << "update factory info\n";
581 
582                 logo_prop.set_icon(ev->data().at(0).value<PanelFactoryInfo>().icon);
583                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "UpdateProperty");
584                 message << Property2String(logo_prop);
585                 QDBusConnection("scim_panel").send(message);
586                 break;
587             case DBusEvent::REG_HELPER:
588                 break;
589             case DBusEvent::REG_HELPER_PROPERTIES:
590                 helper_props_map.clear();
591                 prop_list.clear();
592                 Q_FOREACH (const QVariant &v, ev->data().at(1).toList()) {
593                     Property prop = v.value<Property>();
594                     prop_list << prop;
595                 }
596                 helper_props_map.insert(ev->data().at(0).toInt(), prop_list);
597 
598                 list_result.clear();
599                 list_result << Property2String(logo_prop);
600                 list_result << PropertyList2LeafOnlyStringList(panel_props);
601                 Q_FOREACH (const QList<Property> &props, helper_props_map) {
602                     list_result << PropertyList2LeafOnlyStringList(props);
603                 }
604                 list_result << Property2String(show_help_prop);
605 
606                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "RegisterProperties");
607 
608                 message << list_result;
609                 QDBusConnection("scim_panel").send(message);
610 
611                 break;
612             case DBusEvent::REG_PROPERTIES:
613                 panel_props.clear();
614                 Q_FOREACH (const QVariant &v, ev->data()) {
615                     Property prop = v.value<Property>();
616                     panel_props << prop;
617                     SCIM_DEBUG_MAIN(1) << "REG_PROPERTIES" << qPrintable(Property2String(v.value<Property>())) << "\n";
618                 }
619 
620                 list_result.clear();
621                 list_result << Property2String(logo_prop);
622                 list_result << PropertyList2LeafOnlyStringList(panel_props);
623                 SCIM_DEBUG_MAIN(1) << "SIMPLIFY_PROPS " << panel_props.size() << " " << list_result.size() - 1 << "\n";
624                 Q_FOREACH (const QList<Property> &props, helper_props_map) {
625                     list_result << PropertyList2LeafOnlyStringList(props);
626                 }
627                 list_result << Property2String(show_help_prop);
628 
629                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "RegisterProperties");
630 
631                 message << list_result;
632                 QDBusConnection("scim_panel").send(message);
633 
634                 break;
635             case DBusEvent::RM_HELPER:
636                 helper_props_map.remove(ev->data().at(0).toInt());
637                 list_result.clear();
638                 list_result << Property2String(logo_prop);
639                 list_result << PropertyList2LeafOnlyStringList(panel_props);
640                 Q_FOREACH (const QList<Property> &props, helper_props_map) {
641                     list_result << PropertyList2LeafOnlyStringList(props);
642                 }
643                 list_result << Property2String(show_help_prop);
644 
645                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "RegisterProperties");
646 
647                 message << list_result;
648                 QDBusConnection("scim_panel").send(message);
649 
650                 break;
651             case DBusEvent::RM_PROPERTY:
652                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "RemoveProperty");
653                 // message << ev->data().at(0).V();
654                 QDBusConnection("scim_panel").send(message);
655                 break;
656             default:
657                 message = QDBusMessage::createSignal("/kimpanel", "org.kde.kimpanel.inputmethod", "ImplementMe");
658                 // message << ev->data().at(0).toInt();
659                 SCIM_DEBUG_MAIN(1) << "Implement me:" << ev->scim_event_type() << "\n";
660                 QDBusConnection("scim_panel").send(message);
661                 break;
662             }
663 
664             return true;
665         }
666         return QObject::event(e);
667     }
668 
669 private:
670     QList<Property> panel_props;
671     QMap<int, QList<Property>> helper_props_map;
672     Property logo_prop;
673     Property show_help_prop;
674     QString factory_prop_prefix;
675     QString helper_prop_prefix;
676     QStringList cached_panel_props;
677 };
678 
679 class PanelAgentThread : public QThread
680 {
681     Q_OBJECT
682 public:
PanelAgentThread(QObject * parent=nullptr)683     explicit PanelAgentThread(QObject *parent = nullptr)
684         : QThread(parent)
685     {
686     }
~PanelAgentThread()687     ~PanelAgentThread()
688     {
689     }
run()690     void run() override
691     {
692         if (!_panel_agent->run())
693             std::cerr << "Failed to run Panel.\n";
694         _global_resource_lock.lock();
695         _should_exit = true;
696         _global_resource_lock.unlock();
697     }
698 };
699 
700 //////////////////////////////////////////////////////////////////////
701 // Start of PanelAgent Functions
702 //////////////////////////////////////////////////////////////////////
initialize_panel_agent(const String & config,const String & display,bool resident)703 static bool initialize_panel_agent(const String &config, const String &display, bool resident)
704 {
705     _panel_agent = new PanelAgent();
706 
707     if (!_panel_agent->initialize(config, display, resident))
708         return false;
709 
710     _panel_agent->signal_connect_transaction_start(slot(slot_transaction_start));
711     _panel_agent->signal_connect_transaction_end(slot(slot_transaction_end));
712     _panel_agent->signal_connect_reload_config(slot(slot_reload_config));
713     _panel_agent->signal_connect_turn_on(slot(slot_turn_on));
714     _panel_agent->signal_connect_turn_off(slot(slot_turn_off));
715     _panel_agent->signal_connect_update_screen(slot(slot_update_screen));
716     _panel_agent->signal_connect_update_spot_location(slot(slot_update_spot_location));
717     _panel_agent->signal_connect_update_factory_info(slot(slot_update_factory_info));
718     _panel_agent->signal_connect_show_help(slot(slot_show_help));
719     _panel_agent->signal_connect_show_factory_menu(slot(slot_show_factory_menu));
720     _panel_agent->signal_connect_show_preedit_string(slot(slot_show_preedit_string));
721     _panel_agent->signal_connect_show_aux_string(slot(slot_show_aux_string));
722     _panel_agent->signal_connect_show_lookup_table(slot(slot_show_lookup_table));
723     _panel_agent->signal_connect_hide_preedit_string(slot(slot_hide_preedit_string));
724     _panel_agent->signal_connect_hide_aux_string(slot(slot_hide_aux_string));
725     _panel_agent->signal_connect_hide_lookup_table(slot(slot_hide_lookup_table));
726     _panel_agent->signal_connect_update_preedit_string(slot(slot_update_preedit_string));
727     _panel_agent->signal_connect_update_preedit_caret(slot(slot_update_preedit_caret));
728     _panel_agent->signal_connect_update_aux_string(slot(slot_update_aux_string));
729     _panel_agent->signal_connect_update_lookup_table(slot(slot_update_lookup_table));
730     _panel_agent->signal_connect_register_properties(slot(slot_register_properties));
731     _panel_agent->signal_connect_update_property(slot(slot_update_property));
732     _panel_agent->signal_connect_register_helper_properties(slot(slot_register_helper_properties));
733     _panel_agent->signal_connect_update_helper_property(slot(slot_update_helper_property));
734     _panel_agent->signal_connect_register_helper(slot(slot_register_helper));
735     _panel_agent->signal_connect_remove_helper(slot(slot_remove_helper));
736     _panel_agent->signal_connect_lock(slot(slot_lock));
737     _panel_agent->signal_connect_unlock(slot(slot_unlock));
738 
739     _panel_agent->get_helper_list(_helper_list);
740 
741     return true;
742 }
743 
run_panel_agent(void)744 static bool run_panel_agent(void)
745 {
746     SCIM_DEBUG_MAIN(1) << "run_panel_agent ()\n";
747 
748     _panel_agent_thread = NULL;
749 
750     if (_panel_agent && _panel_agent->valid()) {
751         _panel_agent_thread = new PanelAgentThread();
752         _panel_agent_thread->start();
753     }
754 
755     return (_panel_agent_thread != NULL);
756 }
757 
start_auto_start_helpers(void)758 static void start_auto_start_helpers(void)
759 {
760     SCIM_DEBUG_MAIN(1) << "start_auto_start_helpers () begin\n";
761 
762     // Add Helper object items.
763     for (size_t i = 0; i < _helper_list.size(); ++i) {
764         SCIM_DEBUG_MAIN(1) << "--" << _helper_list[i].uuid << "--" << _helper_list[i].name << "--\n";
765         if ((_helper_list[i].option & SCIM_HELPER_AUTO_START)) {
766             _panel_agent->start_helper(_helper_list[i].uuid);
767         }
768     }
769     SCIM_DEBUG_MAIN(1) << "start_auto_start_helpers () end\n";
770 }
771 
slot_transaction_start(void)772 static void slot_transaction_start(void)
773 {
774     SCIM_DEBUG_MAIN(1) << "slot_transaction_start ()\n";
775     _transaction_lock.lock();
776 }
777 
slot_transaction_end(void)778 static void slot_transaction_end(void)
779 {
780     SCIM_DEBUG_MAIN(1) << "slot_transaction_end ()\n";
781     _transaction_lock.unlock();
782 }
783 
slot_reload_config(void)784 static void slot_reload_config(void)
785 {
786     SCIM_DEBUG_MAIN(1) << "slot_reload_config ()\n";
787     if (!_config.null())
788         _config->reload();
789     else
790         SCIM_DEBUG_MAIN(1) << "config is null\n";
791 }
792 
slot_turn_on(void)793 static void slot_turn_on(void)
794 {
795     SCIM_DEBUG_MAIN(1) << "slot_turn_on ()" << _dbus_handler << "\n";
796     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::TURN_ON));
797 }
798 
slot_turn_off(void)799 static void slot_turn_off(void)
800 {
801     SCIM_DEBUG_MAIN(1) << "slot_turn_off ()\n";
802     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::TURN_OFF));
803 
804     /*
805      */
806 }
807 
slot_update_screen(int num)808 static void slot_update_screen(int num)
809 {
810     SCIM_DEBUG_MAIN(1) << "slot_update_screen ()\n";
811     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_SCREEN, QVariantList() << num));
812 }
813 
slot_update_factory_info(const PanelFactoryInfo & info)814 static void slot_update_factory_info(const PanelFactoryInfo &info)
815 {
816     SCIM_DEBUG_MAIN(1) << "slot_update_factory_info ()\n";
817     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_FACTORY_INFO, QVariantList() << QVariant::fromValue(info)));
818 }
819 
slot_show_help(const String & help)820 static void slot_show_help(const String &help)
821 {
822     SCIM_DEBUG_MAIN(1) << "slot_show_help ()\n";
823     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_HELP, QVariantList() << QString::fromUtf8(help.c_str())));
824 }
825 
slot_show_factory_menu(const std::vector<PanelFactoryInfo> & factories)826 static void slot_show_factory_menu(const std::vector<PanelFactoryInfo> &factories)
827 {
828     SCIM_DEBUG_MAIN(1) << "slot_show_factory_menu ()\n";
829     QVariantList list;
830     Q_FOREACH (const PanelFactoryInfo &info, factories) {
831         list << QVariant::fromValue(info);
832     }
833     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_FACTORY_MENU, list));
834 }
835 
slot_update_spot_location(int x,int y)836 static void slot_update_spot_location(int x, int y)
837 {
838     SCIM_DEBUG_MAIN(1) << "slot_update_spot_location ()\n";
839     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_SPOT_LOC, QVariantList() << x << y));
840 }
841 
slot_show_preedit_string(void)842 static void slot_show_preedit_string(void)
843 {
844     SCIM_DEBUG_MAIN(1) << "slot_show_preedit_string ()\n";
845     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_PREEDIT));
846 }
847 
slot_show_aux_string(void)848 static void slot_show_aux_string(void)
849 {
850     SCIM_DEBUG_MAIN(1) << "slot_show_aux_string ()\n";
851     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_AUX));
852 }
853 
slot_show_lookup_table(void)854 static void slot_show_lookup_table(void)
855 {
856     SCIM_DEBUG_MAIN(1) << "slot_show_lookup_table ()\n";
857     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::SHOW_LOOKUPTABLE));
858 }
859 
slot_hide_preedit_string(void)860 static void slot_hide_preedit_string(void)
861 {
862     SCIM_DEBUG_MAIN(1) << "slot_hide_preedit_string ()\n";
863     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::HIDE_PREEDIT));
864 }
865 
slot_hide_aux_string(void)866 static void slot_hide_aux_string(void)
867 {
868     SCIM_DEBUG_MAIN(1) << "slot_hide_aux_string ()\n";
869     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::HIDE_AUX));
870 }
871 
slot_hide_lookup_table(void)872 static void slot_hide_lookup_table(void)
873 {
874     SCIM_DEBUG_MAIN(1) << "slot_hide_lookup_table ()\n";
875     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::HIDE_LOOKUPTABLE));
876 }
877 
slot_update_preedit_string(const String & str,const AttributeList & attrs)878 static void slot_update_preedit_string(const String &str, const AttributeList &attrs)
879 {
880     SCIM_DEBUG_MAIN(1) << "slot_update_preedit_string ()" << str << "\n";
881     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_PREEDIT_STR, QVariantList() << QString::fromUtf8(str.c_str()) << AttrList2String(attrs)));
882 }
883 
slot_update_preedit_caret(int caret)884 static void slot_update_preedit_caret(int caret)
885 {
886     SCIM_DEBUG_MAIN(1) << "slot_update_preedit_caret ()" << caret << "\n";
887     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_PREEDIT_CARET, QVariantList() << caret));
888 }
889 
slot_update_aux_string(const String & str,const AttributeList & attrs)890 static void slot_update_aux_string(const String &str, const AttributeList &attrs)
891 {
892     SCIM_DEBUG_MAIN(1) << "slot_update_aux_string ()" << str << "\n";
893     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_AUX, QVariantList() << QString::fromUtf8(str.c_str()) << AttrList2String(attrs)));
894 }
895 
slot_update_lookup_table(const LookupTable & table)896 static void slot_update_lookup_table(const LookupTable &table)
897 {
898     SCIM_DEBUG_MAIN(1) << "slot_update_lookup_table ()\n";
899     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_LOOKUPTABLE, LookupTable2VariantList(table)));
900 
901     qApp->postEvent(
902         _dbus_handler,
903         new DBusEvent(DBusEvent::UP_LOOKUPTABLE_CURSOR, QVariantList() << (table.is_cursor_visible() ? table.get_cursor_pos_in_current_page() : -1)));
904 }
905 
slot_register_properties(const PropertyList & props)906 static void slot_register_properties(const PropertyList &props)
907 {
908     SCIM_DEBUG_MAIN(1) << "slot_register_properties ()\n";
909     QVariantList list;
910     Q_FOREACH (const Property &prop, props) {
911         list << QVariant::fromValue(prop);
912     }
913     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::REG_PROPERTIES, list));
914 }
915 
slot_update_property(const Property & prop)916 static void slot_update_property(const Property &prop)
917 {
918     SCIM_DEBUG_MAIN(1) << "slot_update_property ()\n";
919     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_PROPERTY, QVariantList() << QVariant::fromValue(prop)));
920 }
921 
slot_register_helper_properties(int id,const PropertyList & props)922 static void slot_register_helper_properties(int id, const PropertyList &props)
923 {
924     SCIM_DEBUG_MAIN(1) << "slot_register_helper_properties ()\n";
925     QVariantList list;
926     Q_FOREACH (const Property &prop, props) {
927         list << QVariant::fromValue(prop);
928     }
929     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::REG_HELPER_PROPERTIES, QVariantList() << id << list));
930 }
931 
slot_update_helper_property(int id,const Property & prop)932 static void slot_update_helper_property(int id, const Property &prop)
933 {
934     SCIM_DEBUG_MAIN(1) << "slot_update_helper_property ()\n";
935     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::UP_HELPER_PROPERTY, QVariantList() << id << QVariant::fromValue(prop)));
936 }
937 
slot_register_helper(int id,const HelperInfo & helper)938 static void slot_register_helper(int id, const HelperInfo &helper)
939 {
940     SCIM_DEBUG_MAIN(1) << "slot_register_helper ()\n";
941     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::REG_HELPER, QVariantList() << id << QVariant::fromValue(helper)));
942 }
943 
slot_remove_helper(int id)944 static void slot_remove_helper(int id)
945 {
946     SCIM_DEBUG_MAIN(1) << "slot_remove_helper ()\n";
947     qApp->postEvent(_dbus_handler, new DBusEvent(DBusEvent::RM_HELPER, QVariantList() << id));
948 }
949 
slot_lock(void)950 static void slot_lock(void)
951 {
952     SCIM_DEBUG_MAIN(1) << "slot_lock ()\n";
953     //_panel_agent_lock.lock();
954 }
955 
slot_unlock(void)956 static void slot_unlock(void)
957 {
958     SCIM_DEBUG_MAIN(1) << "slot_unlock ()\n";
959     //_panel_agent_lock.unlock();
960 }
961 //////////////////////////////////////////////////////////////////////
962 // End of PanelAgent-Functions
963 //////////////////////////////////////////////////////////////////////
964 
signalhandler(int sig)965 static void signalhandler(int sig)
966 {
967     Q_UNUSED(sig)
968     SCIM_DEBUG_MAIN(1) << "In signal handler...\n";
969 
970     if (_panel_agent)
971         _panel_agent->stop();
972 }
973 
main(int argc,char * argv[])974 int main(int argc, char *argv[])
975 {
976     std::vector<String> config_list;
977 
978     int i;
979 
980     bool daemon = false;
981 
982     int new_argc = 0;
983     char **new_argv = new char *[40];
984 
985     String config_name("simple");
986     String display_name;
987     bool should_resident = true;
988 
989     //    QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
990     // Display version info
991     //    std::cerr << "GTK Panel of SCIM " << SCIM_VERSION << "\n\n";
992 
993     // get modules list
994     scim_get_config_module_list(config_list);
995 
996     // Add a dummy config module, it's not really a module!
997     config_list.push_back("dummy");
998 
999     // Use socket Config module as default if available.
1000     if (!config_list.empty()) {
1001         if (std::find(config_list.begin(), config_list.end(), config_name) == config_list.end())
1002             config_name = config_list[0];
1003     }
1004 
1005     // DebugOutput::set_output("/home/ora/a.log");
1006     // DebugOutput::enable_debug (SCIM_DEBUG_AllMask);
1007 
1008     // parse command options
1009     i = 0;
1010     while (i < argc) {
1011         if (++i >= argc)
1012             break;
1013 
1014         if (String("-l") == argv[i] || String("--list") == argv[i]) {
1015             std::vector<String>::iterator it;
1016 
1017             std::cout << "\n";
1018             std::cout << "Available Config module:\n";
1019             for (it = config_list.begin(); it != config_list.end(); ++it)
1020                 std::cout << "    " << *it << "\n";
1021 
1022             return 0;
1023         }
1024 
1025         if (String("-c") == argv[i] || String("--config") == argv[i]) {
1026             if (++i >= argc) {
1027                 std::cerr << "no argument for option " << argv[i - 1] << "\n";
1028                 return -1;
1029             }
1030             config_name = argv[i];
1031             continue;
1032         }
1033 
1034         if (String("-h") == argv[i] || String("--help") == argv[i]) {
1035             std::cout << "Usage: " << argv[0] << " [option]...\n\n"
1036                       << "The options are: \n"
1037                       << "  --display DISPLAY    Run on display DISPLAY.\n"
1038                       << "  -l, --list           List all of available config modules.\n"
1039                       << "  -c, --config NAME    Uses specified Config module.\n"
1040                       << "  -d, --daemon         Run " << argv[0] << " as a daemon.\n"
1041                       << "  -ns, --no-stay       Quit if no connected client.\n"
1042 #if ENABLE_DEBUG
1043                       << "  -v, --verbose LEVEL  Enable debug info, to specific LEVEL.\n"
1044                       << "  -o, --output FILE    Output debug information into FILE.\n"
1045 #endif
1046                       << "  -h, --help           Show this help message.\n";
1047             return 0;
1048         }
1049 
1050         if (String("-d") == argv[i] || String("--daemon") == argv[i]) {
1051             daemon = true;
1052             continue;
1053         }
1054 
1055         if (String("-ns") == argv[i] || String("--no-stay") == argv[i]) {
1056             should_resident = false;
1057             continue;
1058         }
1059 
1060         if (String("-v") == argv[i] || String("--verbose") == argv[i]) {
1061             if (++i >= argc) {
1062                 std::cerr << "no argument for option " << argv[i - 1] << "\n";
1063                 return -1;
1064             }
1065             DebugOutput::set_verbose_level(atoi(argv[i]));
1066             continue;
1067         }
1068 
1069         if (String("-o") == argv[i] || String("--output") == argv[i]) {
1070             if (++i >= argc) {
1071                 std::cerr << "No argument for option " << argv[i - 1] << "\n";
1072                 return -1;
1073             }
1074             DebugOutput::set_output(argv[i]);
1075             continue;
1076         }
1077 
1078         if (String("--display") == argv[i]) {
1079             if (++i >= argc) {
1080                 std::cerr << "No argument for option " << argv[i - 1] << "\n";
1081                 return -1;
1082             }
1083             display_name = argv[i];
1084             continue;
1085         }
1086 
1087         if (String("--") == argv[i])
1088             break;
1089 
1090         std::cerr << "Invalid command line option: " << argv[i] << "\n";
1091         return -1;
1092     } // End of command line parsing.
1093 
1094     new_argv[new_argc++] = argv[0];
1095 
1096     // Store the rest argvs into new_argv.
1097     for (++i; i < argc && new_argc < 40; ++i) {
1098         new_argv[new_argc++] = argv[i];
1099     }
1100 
1101     // Make up DISPLAY env.
1102     if (display_name.length()) {
1103         new_argv[new_argc++] = strdup("--display");
1104         new_argv[new_argc++] = const_cast<char *>(display_name.c_str());
1105 
1106         setenv("DISPLAY", display_name.c_str(), 1);
1107     }
1108 
1109     new_argv[new_argc] = 0;
1110 
1111     if (!config_name.length()) {
1112         std::cerr << "No Config module is available!\n";
1113         return -1;
1114     }
1115 
1116     if (config_name != "dummy") {
1117         // load config module
1118         _config_module = new ConfigModule(config_name);
1119 
1120         if (!_config_module || !_config_module->valid()) {
1121             std::cerr << "Can not load " << config_name << " Config module.\n";
1122             return -1;
1123         }
1124 
1125         // create config instance
1126         _config = _config_module->create_config();
1127     } else {
1128         _config = new DummyConfig();
1129     }
1130 
1131     if (_config.null()) {
1132         std::cerr << "Failed to create Config instance from " << config_name << " Config module.\n";
1133         return -1;
1134     }
1135 
1136     KDE_signal(SIGQUIT, signalhandler);
1137     KDE_signal(SIGTERM, signalhandler);
1138     KDE_signal(SIGINT, signalhandler);
1139     KDE_signal(SIGHUP, signalhandler);
1140 
1141     const QByteArray display = qgetenv("DISPLAY");
1142     if (display.constData())
1143         display_name = String(display.constData());
1144 
1145     if (!initialize_panel_agent(config_name, display_name, should_resident)) {
1146         std::cerr << "Failed to initialize Panel Agent!\n";
1147         return -1;
1148     }
1149 
1150     if (daemon)
1151         scim_daemon();
1152 
1153     // connect the configuration reload signal.
1154     _config->signal_connect_reload(slot(ui_config_reload_callback));
1155 
1156     qRegisterMetaType<scim::Property>("scim::Property");
1157     qRegisterMetaType<PanelFactoryInfo>("PanelFactoryInfo");
1158     qRegisterMetaType<HelperInfo>("HelperInfo");
1159 
1160     QDBusConnection::connectToBus(QDBusConnection::SessionBus, "scim_panel");
1161     _dbus_handler = new DBusHandler();
1162     _dbus_handler->setInitialHelpers(_helper_list);
1163 
1164     if (!run_panel_agent()) {
1165         std::cerr << "Failed to run Socket Server!\n";
1166         return -1;
1167     }
1168 
1169     start_auto_start_helpers();
1170 
1171     QCoreApplication app(argc, argv);
1172     app.exec();
1173 
1174     _panel_agent_thread->wait();
1175     _config.reset();
1176 
1177     std::cerr << "Successfully exited.\n";
1178 
1179     return 0;
1180 }
1181 
1182 #include "main.moc"
1183 
1184 #undef QT_NO_KEYWORDS
1185 
1186 /*
1187 vim:ts=4:nowrap:expandtab
1188 */
1189