1 /*
2     SPDX-FileCopyrightText: 2009 Wang Hoi <zealot.hoi@gmail.com>
3     SPDX-FileCopyrightText: 2011 Weng Xuetian <wengxt@gmail.com>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "kimpanelagent.h"
9 #include "impaneladaptor.h"
10 
11 // Qt
12 #include <QByteArray>
13 #include <QDBusServiceWatcher>
14 #include <QList>
15 #include <QMap>
16 #include <QString>
17 #include <QVariant>
18 
19 int PanelAgent::m_connectionIndex = 0;
20 
PanelAgent(QObject * parent)21 PanelAgent::PanelAgent(QObject *parent)
22     : QObject(parent)
23     , m_adaptor(new ImpanelAdaptor(this))
24     , m_adaptor2(new Impanel2Adaptor(this))
25     , m_watcher(new QDBusServiceWatcher(this))
26     , m_connection(QDBusConnection::connectToBus(QDBusConnection::SessionBus, QStringLiteral("kimpanel_bus_%0").arg(++m_connectionIndex)))
27 {
28     m_watcher->setConnection(QDBusConnection::sessionBus());
29     m_watcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
30     m_connection.registerObject(QStringLiteral("/org/kde/impanel"), this);
31     m_connection.registerService(QStringLiteral("org.kde.impanel"));
32 
33     // directly connect to corresponding signal
34     m_connection.connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("Enable"), this, SIGNAL(enable(bool)));
35     m_connection.connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ShowPreedit"), this, SIGNAL(showPreedit(bool)));
36     m_connection.connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ShowAux"), this, SIGNAL(showAux(bool)));
37     m_connection
38         .connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ShowLookupTable"), this, SIGNAL(showLookupTable(bool)));
39     m_connection.connect(QString(),
40                          QString(),
41                          QStringLiteral("org.kde.kimpanel.inputmethod"),
42                          QStringLiteral("UpdateLookupTableCursor"),
43                          this,
44                          SIGNAL(updateLookupTableCursor(int)));
45 
46     // do some serialization
47     m_connection.connect(QString(),
48                          QString(),
49                          QStringLiteral("org.kde.kimpanel.inputmethod"),
50                          QStringLiteral("UpdateLookupTable"),
51                          this,
52                          SLOT(UpdateLookupTable(QStringList, QStringList, QStringList, bool, bool)));
53     m_connection.connect(QString(),
54                          QString(),
55                          QStringLiteral("org.kde.kimpanel.inputmethod"),
56                          QStringLiteral("UpdatePreeditCaret"),
57                          this,
58                          SIGNAL(updatePreeditCaret(int)));
59     m_connection.connect(QString(),
60                          QString(),
61                          QStringLiteral("org.kde.kimpanel.inputmethod"),
62                          QStringLiteral("UpdatePreeditText"),
63                          this,
64                          SLOT(UpdatePreeditText(QString, QString)));
65     m_connection
66         .connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateAux"), this, SLOT(UpdateAux(QString, QString)));
67     m_connection.connect(QString(),
68                          QString(),
69                          QStringLiteral("org.kde.kimpanel.inputmethod"),
70                          QStringLiteral("UpdateSpotLocation"),
71                          this,
72                          SIGNAL(updateSpotLocation(int, int)));
73     m_connection.connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateScreen"), this, SLOT(UpdateScreen(int)));
74     m_connection
75         .connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("UpdateProperty"), this, SLOT(UpdateProperty(QString)));
76     m_connection.connect(QString(),
77                          QString(),
78                          QStringLiteral("org.kde.kimpanel.inputmethod"),
79                          QStringLiteral("RegisterProperties"),
80                          this,
81                          SLOT(RegisterProperties(QStringList)));
82     m_connection.connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ExecDialog"), this, SLOT(ExecDialog(QString)));
83     m_connection.connect(QString(), QString(), QStringLiteral("org.kde.kimpanel.inputmethod"), QStringLiteral("ExecMenu"), this, SLOT(ExecMenu(QStringList)));
84 
85     connect(m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &PanelAgent::serviceUnregistered);
86 }
87 
~PanelAgent()88 PanelAgent::~PanelAgent()
89 {
90     // destructor
91     QDBusConnection::disconnectFromBus(m_connection.name());
92 }
93 
serviceUnregistered(const QString & service)94 void PanelAgent::serviceUnregistered(const QString &service)
95 {
96     if (service == m_currentService) {
97         m_watcher->setWatchedServices(QStringList());
98         m_cachedProps.clear();
99         m_currentService = QString();
100         Q_EMIT showAux(false);
101         Q_EMIT showPreedit(false);
102         Q_EMIT showLookupTable(false);
103         Q_EMIT registerProperties(QList<KimpanelProperty>());
104     }
105 }
106 
configure()107 void PanelAgent::configure()
108 {
109     Q_EMIT Configure();
110 }
111 
lookupTablePageDown()112 void PanelAgent::lookupTablePageDown()
113 {
114     Q_EMIT LookupTablePageDown();
115 }
116 
lookupTablePageUp()117 void PanelAgent::lookupTablePageUp()
118 {
119     Q_EMIT LookupTablePageUp();
120 }
121 
movePreeditCaret(int pos)122 void PanelAgent::movePreeditCaret(int pos)
123 {
124     Q_EMIT MovePreeditCaret(pos);
125 }
126 
triggerProperty(const QString & key)127 void PanelAgent::triggerProperty(const QString &key)
128 {
129     Q_EMIT TriggerProperty(key);
130 }
131 
selectCandidate(int idx)132 void PanelAgent::selectCandidate(int idx)
133 {
134     Q_EMIT SelectCandidate(idx);
135 }
136 
String2AttrList(const QString & str)137 static QList<TextAttribute> String2AttrList(const QString &str)
138 {
139     QList<TextAttribute> result;
140     if (str.isEmpty()) {
141         return result;
142     }
143     foreach (const QString &s, str.split(QLatin1Char(';'))) {
144         TextAttribute attr;
145         QStringList list = s.split(QLatin1Char(':'));
146         if (list.size() < 4)
147             continue;
148         switch (list.at(0).toInt()) {
149         case 0:
150             attr.type = TextAttribute::None;
151             break;
152         case 1:
153             attr.type = TextAttribute::Decorate;
154             break;
155         case 2:
156             attr.type = TextAttribute::Foreground;
157             break;
158         case 3:
159             attr.type = TextAttribute::Background;
160             break;
161         default:
162             attr.type = TextAttribute::None;
163         }
164         attr.start = list.at(1).toInt();
165         attr.length = list.at(2).toInt();
166         attr.value = list.at(3).toInt();
167         result << attr;
168     }
169     return result;
170 }
171 
String2Property(const QString & str)172 static KimpanelProperty String2Property(const QString &str)
173 {
174     KimpanelProperty result;
175 
176     QStringList list = str.split(QLatin1Char(':'));
177 
178     if (list.size() < 4)
179         return result;
180 
181     result.key = list.at(0);
182     result.label = list.at(1);
183     result.icon = list.at(2);
184     result.tip = list.at(3);
185     result.hint = list.size() > 4 ? list.at(4) : QString();
186 
187     return result;
188 }
189 
Args2LookupTable(const QStringList & labels,const QStringList & candis,const QStringList & attrs,bool has_prev,bool has_next)190 static KimpanelLookupTable Args2LookupTable(const QStringList &labels, const QStringList &candis, const QStringList &attrs, bool has_prev, bool has_next)
191 {
192     Q_ASSERT(labels.size() == candis.size());
193     Q_ASSERT(labels.size() == attrs.size());
194 
195     KimpanelLookupTable result;
196 
197     for (int i = 0; i < labels.size(); i++) {
198         KimpanelLookupTable::Entry entry;
199 
200         entry.label = labels.at(i);
201         entry.text = candis.at(i);
202         entry.attr = String2AttrList(attrs.at(i));
203 
204         result.entries << entry;
205     }
206 
207     result.has_prev = has_prev;
208     result.has_next = has_next;
209     return result;
210 }
211 
created()212 void PanelAgent::created()
213 {
214     Q_EMIT PanelCreated();
215     Q_EMIT PanelCreated2();
216 }
217 
exit()218 void PanelAgent::exit()
219 {
220     Q_EMIT Exit();
221 }
222 
reloadConfig()223 void PanelAgent::reloadConfig()
224 {
225     Q_EMIT ReloadConfig();
226 }
227 
UpdateLookupTable(const QStringList & labels,const QStringList & candis,const QStringList & attrlists,bool has_prev,bool has_next)228 void PanelAgent::UpdateLookupTable(const QStringList &labels, const QStringList &candis, const QStringList &attrlists, bool has_prev, bool has_next)
229 {
230     Q_EMIT updateLookupTable(Args2LookupTable(labels, candis, attrlists, has_prev, has_next));
231 }
232 
UpdatePreeditText(const QString & text,const QString & attr)233 void PanelAgent::UpdatePreeditText(const QString &text, const QString &attr)
234 {
235     Q_EMIT updatePreeditText(text, String2AttrList(attr));
236 }
237 
UpdateAux(const QString & text,const QString & attr)238 void PanelAgent::UpdateAux(const QString &text, const QString &attr)
239 {
240     Q_EMIT updateAux(text, String2AttrList(attr));
241 }
242 
UpdateScreen(int screen_id)243 void PanelAgent::UpdateScreen(int screen_id)
244 {
245     Q_UNUSED(screen_id);
246 }
247 
UpdateProperty(const QString & prop)248 void PanelAgent::UpdateProperty(const QString &prop)
249 {
250     Q_EMIT updateProperty(String2Property(prop));
251 }
252 
RegisterProperties(const QStringList & props)253 void PanelAgent::RegisterProperties(const QStringList &props)
254 {
255     const QDBusMessage &msg = message();
256     if (msg.service() != m_currentService) {
257         m_watcher->removeWatchedService(m_currentService);
258         if (m_currentService.isEmpty()) {
259             Q_EMIT PanelRegistered();
260         }
261         m_currentService = msg.service();
262         m_watcher->addWatchedService(m_currentService);
263     }
264     if (m_cachedProps != props) {
265         m_cachedProps = props;
266         QList<KimpanelProperty> list;
267         foreach (const QString &prop, props) {
268             list << String2Property(prop);
269         }
270 
271         Q_EMIT registerProperties(list);
272     }
273 }
274 
ExecDialog(const QString & prop)275 void PanelAgent::ExecDialog(const QString &prop)
276 {
277     Q_EMIT execDialog(String2Property(prop));
278 }
279 
ExecMenu(const QStringList & entries)280 void PanelAgent::ExecMenu(const QStringList &entries)
281 {
282     QList<KimpanelProperty> list;
283     foreach (const QString &entry, entries) {
284         list << String2Property(entry);
285     }
286 
287     Q_EMIT execMenu(list);
288 }
289 
SetSpotRect(int x,int y,int w,int h)290 void PanelAgent::SetSpotRect(int x, int y, int w, int h)
291 {
292     Q_EMIT updateSpotRect(x, y, w, h);
293 }
294 
SetLookupTable(const QStringList & labels,const QStringList & candis,const QStringList & attrlists,bool hasPrev,bool hasNext,int cursor,int layout)295 void PanelAgent::SetLookupTable(const QStringList &labels,
296                                 const QStringList &candis,
297                                 const QStringList &attrlists,
298                                 bool hasPrev,
299                                 bool hasNext,
300                                 int cursor,
301                                 int layout)
302 {
303     Q_EMIT updateLookupTableFull(Args2LookupTable(labels, candis, attrlists, hasPrev, hasNext), cursor, layout);
304 }
305