1 /***************************************************************************
2  *   Copyright (C) 2008~2010 by Zealot.Hoi                                 *
3  *   Copyright (C) 2010~2012 by CSSlayer                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
19  ***************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <memory.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <ctype.h>
26 #include <limits.h>
27 #include <libintl.h>
28 #include <sys/socket.h>
29 #include <dbus/dbus.h>
30 
31 #include "config.h"
32 #include "fcitx/ui.h"
33 #include "fcitx-utils/log.h"
34 #include "module/dbus/fcitx-dbus.h"
35 #include "fcitx/instance.h"
36 #include "fcitx/module.h"
37 #include "fcitx/frontend.h"
38 #include "fcitx/hook.h"
39 #include "fcitx-utils/utils.h"
40 #include "fcitx/candidate.h"
41 
42 #define FCITX_KIMPANEL_INTERFACE "org.kde.kimpanel.inputmethod"
43 #define FCITX_KIMPANEL_PATH "/kimpanel"
44 
45 #define GetMenuItem(m, i) ((FcitxMenuItem*) utarray_eltptr(&(m)->shell, (i)))
46 
CheckAddPrefix(const char ** name)47 static inline boolean CheckAddPrefix( const char** name) {
48     boolean result = !((*name)[0] == '\0' || (*name)[0] == '/' || (*name)[0] == '@');
49     if ((*name)[0] == '@') {
50         (*name) += 1;
51     }
52 
53     return result;
54 }
55 
56 const char * kimpanel_introspection_xml =
57     "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
58     "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">"
59     "<node name=\"" FCITX_KIMPANEL_PATH "\">"
60     "<interface name=\"org.freedesktop.DBus.Introspectable\">"
61     "<method name=\"Introspect\">"
62     "<arg name=\"data\" direction=\"out\" type=\"s\"/>"
63     "</method>"
64     "</interface>"
65     "<interface name=\"" FCITX_KIMPANEL_INTERFACE "\">"
66     "<signal name=\"ExecDialog\">"
67     "<arg name=\"prop\" direction=\"in\" type=\"s\"/>"
68     "</signal>"
69     "<signal name=\"ExecMenu\">"
70     "<arg name=\"prop\" direction=\"in\" type=\"as\"/>"
71     "</signal>"
72     "<signal name=\"RegisterProperties\">"
73     "<arg name=\"prop\" direction=\"in\" type=\"as\"/>"
74     "</signal>"
75     "<signal name=\"UpdateProperty\">"
76     "<arg name=\"prop\" direction=\"in\" type=\"s\"/>"
77     "</signal>"
78     "<signal name=\"RemoveProperty\">"
79     "<arg name=\"prop\" direction=\"in\" type=\"s\"/>"
80     "</signal>"
81     "<signal name=\"ShowAux\">"
82     "<arg name=\"toshow\" direction=\"in\" type=\"b\"/>"
83     "</signal>"
84     "<signal name=\"ShowPreedit\">"
85     "<arg name=\"toshow\" direction=\"in\" type=\"b\"/>"
86     "</signal>"
87     "<signal name=\"ShowLookupTable\">"
88     "<arg name=\"toshow\" direction=\"in\" type=\"b\"/>"
89     "</signal>"
90     "<signal name=\"UpdateLookupTable\">"
91     "<arg name=\"label\" direction=\"in\" type=\"as\"/>"
92     "<arg name=\"text\" direction=\"in\" type=\"as\"/>"
93     "</signal>"
94     "<signal name=\"UpdateLookupTableCursor\">"
95     "<arg name=\"cursor\" direction=\"in\" type=\"i\"/>"
96     "</signal>"
97     "<signal name=\"UpdatePreeditCaret\">"
98     "<arg name=\"position\" direction=\"in\" type=\"i\"/>"
99     "</signal>"
100     "<signal name=\"UpdatePreeditText\">"
101     "<arg name=\"text\" direction=\"in\" type=\"s\"/>"
102     "<arg name=\"attr\" direction=\"in\" type=\"s\"/>"
103     "</signal>"
104     "<signal name=\"UpdateAux\">"
105     "<arg name=\"text\" direction=\"in\" type=\"s\"/>"
106     "<arg name=\"attr\" direction=\"in\" type=\"s\"/>"
107     "</signal>"
108     "<signal name=\"UpdateSpotLocation\">"
109     "<arg name=\"x\" direction=\"in\" type=\"i\"/>"
110     "<arg name=\"y\" direction=\"in\" type=\"i\"/>"
111     "</signal>"
112     "<signal name=\"UpdateScreen\">"
113     "<arg name=\"screen\" direction=\"in\" type=\"i\"/>"
114     "</signal>"
115     "<signal name=\"Enable\">"
116     "<arg name=\"toenable\" direction=\"in\" type=\"b\"/>"
117     "</signal>"
118     "</interface>"
119     "</node>";
120 
121 typedef struct _FcitxKimpanelUI {
122     FcitxInstance* owner;
123     FcitxAddon* addon;
124     DBusConnection* conn;
125     int iOffsetY;
126     int iOffsetX;
127     FcitxMessages* messageUp;
128     FcitxMessages* messageDown;
129     int iCursorPos;
130     int lastUpdateY;
131     int lastUpdateX;
132     int version;
133     int lastUpdateW;
134     int lastUpdateH;
135     int lastCursor;
136     boolean hasSetLookupTable;
137     boolean hasSetRelativeSpotRect;
138 } FcitxKimpanelUI;
139 
140 static void* KimpanelCreate(FcitxInstance* instance);
141 static void KimpanelCloseInputWindow(void* arg);
142 static void KimpanelShowInputWindow(void* arg);
143 static void KimpanelMoveInputWindow(void* arg);
144 static void KimpanelRegisterMenu(void *arg, FcitxUIMenu* menu);
145 static void KimpanelUpdateStatus(void *arg, FcitxUIStatus* status);
146 static void KimpanelRegisterStatus(void *arg, FcitxUIStatus* status);
147 static void KimpanelRegisterComplexStatus(void* arg, FcitxUIComplexStatus* status);
148 static void KimpanelUpdateComplexStatus(void* arg, FcitxUIComplexStatus* status);
149 static void KimpanelOnInputFocus(void *arg);
150 static void KimpanelOnInputUnFocus(void *arg);
151 static void KimpanelOnTriggerOn(void *arg);
152 static void KimpanelOnTriggerOff(void *arg);
153 static void KimpanelSuspend(void* arg);
154 static void KimpanelDestroy(void* arg);
155 static void KimpanelOwnerChanged(void* user_data, void* arg, const char* serviceName, const char* oldName, const char* newName);
156 
157 static void KimUpdateLookupTableCursor(FcitxKimpanelUI* kimpanel, int cursor);
158 static void KimShowAux(FcitxKimpanelUI* kimpanel, boolean toShow);
159 static void KimShowPreedit(FcitxKimpanelUI* kimpanel, boolean toShow);
160 static void KimUpdateSpotLocation(FcitxKimpanelUI* kimpanel, int x, int y);
161 static void KimSetSpotRect(FcitxKimpanelUI* kimpanel, int x, int y, int w, int h, boolean relative);
162 static void KimShowLookupTable(FcitxKimpanelUI* kimpanel, boolean toShow);
163 static void KimUpdateLookupTable(FcitxKimpanelUI* kimpanel, char *labels[], int nLabel, char *texts[], int nText, boolean has_prev, boolean has_next);
164 static void KimSetLookupTable(FcitxKimpanelUI* kimpanel,
165                               char *labels[], int nLabel,
166                               char *texts[], int nText,
167                               boolean has_prev,
168                               boolean has_next,
169                               int cursor,
170                               int layout);
171 static void KimUpdatePreeditText(FcitxKimpanelUI* kimpanel, char *text);
172 static void KimUpdateAux(FcitxKimpanelUI* kimpanel, char *text);
173 static void KimUpdatePreeditCaret(FcitxKimpanelUI* kimpanel, int position);
174 static void KimEnable(FcitxKimpanelUI* kimpanel, boolean toEnable);
175 static void KimRegisterProperties(FcitxKimpanelUI* kimpanel, char *props[], int n);
176 static void KimUpdateProperty(FcitxKimpanelUI* kimpanel, char *prop);
177 static DBusHandlerResult KimpanelDBusEventHandler(DBusConnection *connection, DBusMessage *message, void *user_data);
178 static DBusHandlerResult KimpanelDBusFilter(DBusConnection *connection, DBusMessage *message, void *user_data);
179 static int CalKimCursorPos(FcitxKimpanelUI *kimpanel);
180 static void KimpanelInputIMChanged(void *arg);
181 static char* Status2String(FcitxInstance* instance, FcitxUIStatus* status);
182 static char* ComplexStatus2String(FcitxInstance* instance, FcitxUIComplexStatus* status);
183 static void KimpanelRegisterAllStatus(FcitxKimpanelUI* kimpanel);
184 static void KimpanelSetIMStatus(FcitxKimpanelUI* kimpanel);
185 static void KimExecMenu(FcitxKimpanelUI* kimpanel, char *props[], int n);
186 static void KimpanelServiceExistCallback(DBusPendingCall *call, void *data);
187 static void KimpanelIntrospect(FcitxKimpanelUI* kimpanel);
188 static void KimpanelIntrospectCallback(DBusPendingCall *call, void *data);
189 
190 #define KIMPANEL_BUFFER_SIZE 4096
191 #ifndef DBUS_TIMEOUT_USE_DEFAULT
192 #  define DBUS_TIMEOUT_USE_DEFAULT (-1)
193 #endif
194 
195 FCITX_DEFINE_PLUGIN(fcitx_kimpanel_ui, ui, FcitxUI) = {
196     KimpanelCreate,
197     KimpanelCloseInputWindow,
198     KimpanelShowInputWindow,
199     KimpanelMoveInputWindow,
200     KimpanelUpdateStatus,
201     KimpanelRegisterStatus,
202     KimpanelRegisterMenu,
203     KimpanelOnInputFocus,
204     KimpanelOnInputUnFocus,
205     KimpanelOnTriggerOn,
206     KimpanelOnTriggerOff,
207     NULL,
208     NULL,
209     NULL,
210     KimpanelSuspend,
211     NULL,
212     KimpanelDestroy,
213     KimpanelRegisterComplexStatus,
214     KimpanelUpdateComplexStatus,
215     NULL
216 };
217 
218 #define INDICATOR_KEYBOARD_PREFIX "@indicator-keyboard-"
219 #define INDICATOR_KEYBOARD_LENGTH (strlen(INDICATOR_KEYBOARD_PREFIX))
220 
221 static inline boolean
isUnity()222 isUnity()
223 {
224     return fcitx_utils_strcmp0(getenv("XDG_CURRENT_DESKTOP"), "Unity") == 0;
225 }
226 
SetIMMenu(FcitxIM * pim,char ** prop)227 static void SetIMMenu(FcitxIM *pim, char** prop)
228 {
229     char layout[] = INDICATOR_KEYBOARD_PREFIX "Xx";
230     const char *icon = "";
231     if (strncmp(pim->uniqueName, "fcitx-keyboard-",
232                 strlen("fcitx-keyboard-")) != 0) {
233         icon = pim->strIconName;
234     } else if (isUnity()) {
235         layout[INDICATOR_KEYBOARD_LENGTH] = toupper(pim->langCode[0]);
236         layout[INDICATOR_KEYBOARD_LENGTH + 1] = tolower(pim->langCode[1]);
237         icon = layout;
238     }
239     boolean result = CheckAddPrefix(&icon);
240     fcitx_utils_alloc_cat_str(*prop, "/Fcitx/im/", pim->uniqueName, ":",
241                               pim->strName,
242                               result ? ":fcitx-" : ":", icon, ":", pim->strName);
243 }
244 
SetIMIcon(FcitxInstance * instance,char ** prop)245 static void SetIMIcon(FcitxInstance* instance, char** prop)
246 {
247     char layout[] = INDICATOR_KEYBOARD_PREFIX "Xx";
248     const char* icon;
249     char* imname;
250     char* description;
251     char temp[LANGCODE_LENGTH + 1] = { '\0', };
252     FCITX_UNUSED(temp);
253     FcitxInputContext* ic = FcitxInstanceGetCurrentIC(instance);
254     if (ic == NULL) {
255         icon = "kbd";
256         imname = _("No input window");
257         description = _("No input window");
258     } else if (FcitxInstanceGetCurrentStatev2(instance) == IS_ACTIVE) {
259         FcitxIM* im = FcitxInstanceGetCurrentIM(instance);
260         if (im) {
261             if (strncmp(im->uniqueName, "fcitx-keyboard-",
262                         strlen("fcitx-keyboard-")) == 0) {
263                 if (isUnity()) {
264                     layout[INDICATOR_KEYBOARD_LENGTH] =
265                         toupper(im->langCode[0]);
266                     layout[INDICATOR_KEYBOARD_LENGTH + 1] =
267                         tolower(im->langCode[1]);
268                     icon = layout;
269                 } else {
270                     icon = "";
271                 }
272                 imname = im->uniqueName + strlen("fcitx-keyboard-");
273             }
274             else
275             {
276                 icon = im->strIconName;
277                 imname = im->strName;
278             }
279             description = im->strName;
280         } else {
281             icon = "kbd";
282             imname = _("Disabled");
283             description = _("Input Method Disabled");
284         }
285     } else {
286         icon = "kbd";
287         imname = _("Disabled");
288         description = _("Input Method Disabled");
289     }
290     /* add fcitx- prefix, unless icon name is an absolute path */
291 
292     char *icon_prefix;
293     boolean result = CheckAddPrefix(&icon);
294     if (result) {
295         icon_prefix = ":fcitx-";
296     } else {
297         icon_prefix = ":";
298     }
299     fcitx_utils_alloc_cat_str(*prop, "/Fcitx/im:", imname, icon_prefix, icon,
300                               ":", description, ":menu");
301 }
302 
KimpanelCreate(FcitxInstance * instance)303 void* KimpanelCreate(FcitxInstance* instance)
304 {
305     FcitxKimpanelUI *kimpanel = fcitx_utils_malloc0(sizeof(FcitxKimpanelUI));
306 
307     kimpanel->addon = FcitxAddonsGetAddonByName(FcitxInstanceGetAddons(instance), "fcitx-kimpanel-ui");
308     kimpanel->lastCursor = -2;
309     kimpanel->version = 1;
310     kimpanel->iCursorPos = 0;
311     kimpanel->owner = instance;
312     kimpanel->conn = FcitxDBusGetConnection(instance);
313 
314     DBusError err;
315     dbus_error_init(&err);
316     do {
317         if (kimpanel->conn == NULL) {
318             FcitxLog(ERROR, "DBus Not initialized");
319             break;
320         }
321 
322         // add a rule to receive signals from kimpanel
323         dbus_bus_add_match(kimpanel->conn,
324                            "type='signal',sender='org.kde.impanel',interface='org.kde.impanel'",
325                            &err);
326         dbus_connection_flush(kimpanel->conn);
327         if (dbus_error_is_set(&err)) {
328             FcitxLog(ERROR, "Match Error (%s)", err.message);
329             break;
330         }
331         dbus_bus_add_match(kimpanel->conn,
332                            "type='signal',sender='org.kde.impanel',interface='org.kde.impanel2'",
333                            &err);
334         dbus_connection_flush(kimpanel->conn);
335         if (dbus_error_is_set(&err)) {
336             FcitxLog(ERROR, "Match Error (%s)", err.message);
337             break;
338         }
339 
340         int id = FcitxDBusWatchName(instance, "org.kde.impanel", kimpanel,
341                                     KimpanelOwnerChanged, NULL, NULL);
342         if (id == 0) {
343             break;
344         }
345 
346         if (!dbus_connection_add_filter(kimpanel->conn, KimpanelDBusFilter, kimpanel, NULL)) {
347             FcitxLog(ERROR, "No memory");
348             break;
349         }
350 
351         DBusObjectPathVTable vtable = {NULL, &KimpanelDBusEventHandler, NULL, NULL, NULL, NULL };
352 
353         dbus_connection_register_object_path(kimpanel->conn, FCITX_KIMPANEL_PATH, &vtable, kimpanel);
354 
355         kimpanel->messageUp = FcitxMessagesNew();
356         kimpanel->messageDown = FcitxMessagesNew();
357 
358         FcitxIMEventHook imchangehk;
359         imchangehk.arg = kimpanel;
360         imchangehk.func = KimpanelInputIMChanged;
361         FcitxInstanceRegisterIMChangedHook(instance, imchangehk);
362 
363         const char* kimpanelServiceName = "org.kde.impanel";
364         DBusMessage* message = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameHasOwner");
365         dbus_message_append_args(message, DBUS_TYPE_STRING, &kimpanelServiceName, DBUS_TYPE_INVALID);
366 
367         DBusPendingCall *call = NULL;
368         dbus_bool_t reply =
369             dbus_connection_send_with_reply(kimpanel->conn, message,
370                                             &call, DBUS_TIMEOUT_USE_DEFAULT);
371         if (reply == TRUE) {
372             dbus_pending_call_set_notify(call,
373                                          KimpanelServiceExistCallback,
374                                          kimpanel,
375                                          NULL);
376             dbus_pending_call_unref(call);
377         }
378         dbus_connection_flush(kimpanel->conn);
379         dbus_message_unref(message);
380 
381         KimpanelRegisterAllStatus(kimpanel);
382         dbus_error_free(&err);
383         return kimpanel;
384     } while (0);
385 
386     dbus_error_free(&err);
387     free(kimpanel);
388     return NULL;
389 }
390 
KimpanelRegisterAllStatus(FcitxKimpanelUI * kimpanel)391 void KimpanelRegisterAllStatus(FcitxKimpanelUI* kimpanel)
392 {
393     FcitxInstance* instance = kimpanel->owner;
394     UT_array* uistats = FcitxInstanceGetUIStats(instance);
395     UT_array* uicompstats = FcitxInstanceGetUIComplexStats(instance);
396     char **prop = fcitx_utils_malloc0(sizeof(char*) * (2 + utarray_len(uistats) + utarray_len(uicompstats)));
397 
398     char *fcitx = _("Fcitx");
399     fcitx_utils_alloc_cat_str(prop[0], "/Fcitx/logo:", fcitx, ":fcitx:", fcitx, ":menu");
400     SetIMIcon(instance, &prop[1]);
401 
402     int count = 2;
403 
404     FcitxUIComplexStatus *compstatus;
405     for (compstatus = (FcitxUIComplexStatus *) utarray_front(uicompstats);
406          compstatus != NULL;
407          compstatus = (FcitxUIComplexStatus *) utarray_next(uicompstats, compstatus)) {
408         if (!compstatus->visible)
409             continue;
410         prop[count] = ComplexStatus2String(instance, compstatus);
411         count ++;
412     }
413 
414     FcitxUIStatus *status;
415     for (status = (FcitxUIStatus *) utarray_front(uistats);
416          status != NULL;
417          status = (FcitxUIStatus *) utarray_next(uistats, status)) {
418         if (!status->visible)
419             continue;
420         prop[count] = Status2String(instance, status);
421         count ++;
422     }
423 
424     KimRegisterProperties(kimpanel, prop, count);
425 
426     while (count --)
427         free(prop[count]);
428 
429     free(prop);
430 }
431 
KimpanelSetIMStatus(FcitxKimpanelUI * kimpanel)432 void KimpanelSetIMStatus(FcitxKimpanelUI* kimpanel)
433 {
434     FcitxInstance* instance = kimpanel->owner;
435     char* status = NULL;
436 
437     SetIMIcon(instance, &status);
438     KimUpdateProperty(kimpanel, status);
439     free(status);
440 }
441 
KimpanelInputIMChanged(void * arg)442 void KimpanelInputIMChanged(void* arg)
443 {
444     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
445     if (kimpanel->addon != FcitxInstanceGetCurrentUI(kimpanel->owner))
446         return;
447     KimpanelSetIMStatus(kimpanel);
448 }
449 
KimpanelOnInputFocus(void * arg)450 void KimpanelOnInputFocus(void* arg)
451 {
452     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
453     KimEnable(kimpanel, (FcitxInstanceGetCurrentStatev2(kimpanel->owner) == IS_ACTIVE));
454     KimpanelSetIMStatus(kimpanel);
455 }
456 
KimpanelOnInputUnFocus(void * arg)457 void KimpanelOnInputUnFocus(void* arg)
458 {
459     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
460     KimEnable(kimpanel, (FcitxInstanceGetCurrentStatev2(kimpanel->owner) == IS_ACTIVE));
461     KimpanelSetIMStatus(kimpanel);
462 }
463 
KimpanelOnTriggerOff(void * arg)464 void KimpanelOnTriggerOff(void* arg)
465 {
466     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
467     KimEnable(kimpanel, false);
468     KimpanelSetIMStatus(kimpanel);
469 }
470 
KimpanelOnTriggerOn(void * arg)471 void KimpanelOnTriggerOn(void* arg)
472 {
473     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
474     KimEnable(kimpanel, true);
475     KimpanelSetIMStatus(kimpanel);
476 }
477 
KimpanelCloseInputWindow(void * arg)478 void KimpanelCloseInputWindow(void* arg)
479 {
480     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
481     FcitxLog(DEBUG, "KimpanelCloseInputWindow");
482     /* why kimpanel sucks, there is not obvious method to close it */
483     KimShowAux(kimpanel, false);
484     KimShowPreedit(kimpanel, false);
485     KimShowLookupTable(kimpanel, false);
486 }
487 
KimpanelMoveInputWindow(void * arg)488 void KimpanelMoveInputWindow(void* arg)
489 {
490     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
491     FcitxLog(DEBUG, "KimpanelMoveInputWindow");
492     kimpanel->iOffsetX = 12;
493     kimpanel->iOffsetY = 0;
494 
495     int x = 0, y = 0, w = 0, h = 0;
496 
497     FcitxInputContext* ic = FcitxInstanceGetCurrentIC(kimpanel->owner);
498     if (!ic) {
499         return;
500     }
501     FcitxInstanceGetWindowRect(kimpanel->owner, ic, &x, &y, &w, &h);
502 
503     if (kimpanel->version == 1)
504         KimUpdateSpotLocation(kimpanel, x, y + h);
505     else
506         KimSetSpotRect(kimpanel, x, y, w, h, !!(ic->contextCaps & CAPACITY_RELATIVE_CURSOR_RECT));
507 }
508 
KimpanelRegisterMenu(void * arg,FcitxUIMenu * menu)509 void KimpanelRegisterMenu(void* arg, FcitxUIMenu* menu)
510 {
511     FCITX_UNUSED(arg);
512     FCITX_UNUSED(menu);
513     return;
514 }
515 
KimpanelRegisterStatus(void * arg,FcitxUIStatus * status)516 void KimpanelRegisterStatus(void* arg, FcitxUIStatus* status)
517 {
518     FCITX_UNUSED(status);
519     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
520     KimpanelRegisterAllStatus(kimpanel);
521     return ;
522 }
523 
KimpanelRegisterComplexStatus(void * arg,FcitxUIComplexStatus * status)524 void KimpanelRegisterComplexStatus(void* arg, FcitxUIComplexStatus* status)
525 {
526     FCITX_UNUSED(status);
527     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*)arg;
528     KimpanelRegisterAllStatus(kimpanel);
529     return ;
530 }
531 
Status2String(FcitxInstance * instance,FcitxUIStatus * status)532 char* Status2String(FcitxInstance* instance, FcitxUIStatus* status)
533 {
534     char *result;
535     FcitxUIMenu *menu = FcitxUIGetMenuByStatusName(instance, status->name);
536     fcitx_utils_alloc_cat_str(result, "/Fcitx/", status->name, ":",
537                               status->shortDescription, ":fcitx-", status->name,
538                               ((status->getCurrentStatus(status->arg)) ?
539                                "-active:" : "-inactive:"),
540                               status->longDescription,
541                               menu ? ":menu" : ":");
542     return result;
543 }
544 
545 
ComplexStatus2String(FcitxInstance * instance,FcitxUIComplexStatus * status)546 char* ComplexStatus2String(FcitxInstance* instance, FcitxUIComplexStatus* status)
547 {
548     const char* icon = status->getIconName(status->arg);
549     char *str;
550     boolean result = CheckAddPrefix(&icon);
551     FcitxUIMenu *menu = FcitxUIGetMenuByStatusName(instance, status->name);
552     fcitx_utils_alloc_cat_str(str, "/Fcitx/", status->name, ":",
553                               status->shortDescription,
554                               (result ? ":fcitx-" : ":"),
555                               icon, ":",
556                               status->longDescription,
557                               menu ? ":menu" : ":"
558                              );
559     return str;
560 }
561 
KimpanelShowInputWindow(void * arg)562 void KimpanelShowInputWindow(void* arg)
563 {
564     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
565     FcitxInstance* instance = kimpanel->owner;
566     FcitxInputState* input = FcitxInstanceGetInputState(instance);
567     FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);
568     kimpanel->iCursorPos = FcitxUINewMessageToOldStyleMessage(instance, kimpanel->messageUp, kimpanel->messageDown);
569     FcitxMessages* messageDown = kimpanel->messageDown;
570     FcitxMessages* messageUp = kimpanel->messageUp;
571     FcitxLog(DEBUG, "KimpanelShowInputWindow");
572     KimpanelMoveInputWindow(kimpanel);
573 
574     boolean hasPrev = FcitxCandidateWordHasPrev(candList);
575     boolean hasNext = FcitxCandidateWordHasNext(candList);
576     FcitxCandidateLayoutHint layout = FcitxCandidateWordGetLayoutHint(candList);
577 
578     int n = FcitxMessagesGetMessageCount(messageDown);
579     int nLabels = 0;
580     int nTexts = 0;
581     char *label[33];
582     char *text[33];
583     char cmb[KIMPANEL_BUFFER_SIZE] = "";
584     int i;
585     int pos = -1;
586 
587     if (n) {
588         for (i = 0; i < n; i++) {
589             FcitxLog(DEBUG, "Type: %d Text: %s" , FcitxMessagesGetMessageType(messageDown, i), FcitxMessagesGetMessageString(messageDown, i));
590 
591             if (FcitxMessagesGetMessageType(messageDown, i) == MSG_INDEX) {
592                 if (nLabels) {
593                     text[nTexts++] = strdup(cmb);
594                 }
595                 char *needfree = FcitxInstanceProcessOutputFilter(instance, FcitxMessagesGetMessageString(messageDown, i));
596                 char *msgstr;
597                 if (needfree)
598                     msgstr = needfree;
599                 else
600                     msgstr = strdup(FcitxMessagesGetMessageString(messageDown, i));
601 
602                 label[nLabels++] = msgstr;
603                 strcpy(cmb, "");
604             } else {
605                 char *needfree = FcitxInstanceProcessOutputFilter(instance, FcitxMessagesGetMessageString(messageDown, i));
606                 char *msgstr;
607                 if (needfree)
608                     msgstr = needfree;
609                 else
610                     msgstr = FcitxMessagesGetMessageString(messageDown, i);
611 
612                 if (strlen(cmb) + strlen(msgstr) + 1 < KIMPANEL_BUFFER_SIZE)
613                     strcat(cmb, msgstr);
614                 if (needfree)
615                     free(needfree);
616                 if (FcitxMessagesGetMessageType(messageDown, i) == MSG_FIRSTCAND)
617                     pos = nTexts;
618             }
619         }
620         text[nTexts++] = strdup(cmb);
621         if (nLabels < nTexts) {
622             for (; nLabels < nTexts; nLabels++) {
623                 label[nLabels] = strdup("");
624             }
625         } else if (nTexts < nLabels) {
626             for (; nTexts < nLabels; nTexts++) {
627                 text[nTexts] = strdup("");
628             }
629         }
630         FcitxLog(DEBUG, "Labels %d, Texts %d, CMB:%s", nLabels, nTexts, cmb);
631         if (nTexts == 0) {
632             KimShowLookupTable(kimpanel, false);
633         } else {
634             if (kimpanel->hasSetLookupTable)
635                 KimSetLookupTable(kimpanel, label, nLabels, text, nTexts, hasPrev, hasNext, pos, layout);
636             else
637                 KimUpdateLookupTable(kimpanel, label, nLabels, text, nTexts, hasPrev, hasNext);
638             KimShowLookupTable(kimpanel, true);
639         }
640         for (i = 0; i < nTexts; i++)
641             free(text[i]);
642         for (i = 0; i < nLabels; i++)
643             free(label[i]);
644     } else {
645         if (kimpanel->hasSetLookupTable)
646             KimSetLookupTable(kimpanel, NULL, 0, NULL, 0, hasNext, hasNext, pos, layout);
647         else
648             KimUpdateLookupTable(kimpanel, NULL, 0, NULL, 0, hasPrev, hasNext);
649         KimShowLookupTable(kimpanel, false);
650     }
651 
652     if (!kimpanel->hasSetLookupTable)
653         KimUpdateLookupTableCursor(kimpanel, pos);
654 
655     n = FcitxMessagesGetMessageCount(messageUp);
656     char aux[MESSAGE_MAX_LENGTH] = "";
657     char empty[MESSAGE_MAX_LENGTH] = "";
658     if (n) {
659         for (i = 0; i < n; i++) {
660 
661             char *needfree = FcitxInstanceProcessOutputFilter(instance, FcitxMessagesGetMessageString(messageUp, i));
662             char *msgstr;
663             if (needfree)
664                 msgstr = needfree;
665             else
666                 msgstr = FcitxMessagesGetMessageString(messageUp, i);
667 
668             strcat(aux, msgstr);
669             if (needfree)
670                 free(needfree);
671             FcitxLog(DEBUG, "updateMesssages Up:%s", aux);
672         }
673         if (FcitxInputStateGetShowCursor(input)) {
674             KimUpdatePreeditText(kimpanel, aux);
675             KimUpdateAux(kimpanel, empty);
676             KimShowPreedit(kimpanel, true);
677             KimUpdatePreeditCaret(kimpanel, CalKimCursorPos(kimpanel));
678             KimShowAux(kimpanel, false);
679         } else {
680             KimUpdatePreeditText(kimpanel, empty);
681             KimUpdateAux(kimpanel, aux);
682             KimShowPreedit(kimpanel, false);
683             KimShowAux(kimpanel, true);
684         }
685     } else {
686         KimShowPreedit(kimpanel, false);
687         KimShowAux(kimpanel, false);
688     }
689 
690 }
691 
KimpanelUpdateStatus(void * arg,FcitxUIStatus * status)692 void KimpanelUpdateStatus(void* arg, FcitxUIStatus* status)
693 {
694     FCITX_UNUSED(status);
695     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
696     KimpanelRegisterAllStatus(kimpanel);
697     return ;
698 }
699 
KimpanelUpdateComplexStatus(void * arg,FcitxUIComplexStatus * status)700 void KimpanelUpdateComplexStatus(void* arg, FcitxUIComplexStatus* status)
701 {
702     FCITX_UNUSED(status);
703     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
704     KimpanelRegisterAllStatus(kimpanel);
705     return ;
706 }
707 
708 static DBusHandlerResult
KimpanelDBusEventHandler(DBusConnection * connection,DBusMessage * msg,void * arg)709 KimpanelDBusEventHandler(DBusConnection *connection,
710                          DBusMessage *msg, void *arg)
711 {
712     FCITX_UNUSED(connection);
713     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*)arg;
714 
715     if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) {
716         DBusMessage *reply = dbus_message_new_method_return(msg);
717 
718         dbus_message_append_args(reply, DBUS_TYPE_STRING, &kimpanel_introspection_xml, DBUS_TYPE_INVALID);
719         dbus_connection_send(kimpanel->conn, reply, NULL);
720         dbus_message_unref(reply);
721         return DBUS_HANDLER_RESULT_HANDLED;
722     }
723     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
724 }
725 
KimpanelReset(FcitxKimpanelUI * kimpanel)726 void KimpanelReset(FcitxKimpanelUI* kimpanel)
727 {
728     kimpanel->lastCursor = -2;
729     kimpanel->lastUpdateH = -2;
730     kimpanel->lastUpdateW = -2;
731     kimpanel->lastUpdateX = -2;
732     kimpanel->lastUpdateY = -2;
733 }
734 
KimpanelDBusFilter(DBusConnection * connection,DBusMessage * msg,void * user_data)735 DBusHandlerResult KimpanelDBusFilter(DBusConnection* connection, DBusMessage* msg, void* user_data)
736 {
737     FCITX_UNUSED(connection);
738     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) user_data;
739     FcitxInstance* instance = kimpanel->owner;
740     FcitxInputState* input = FcitxInstanceGetInputState(kimpanel->owner);
741     int int0;
742     const char* s0 = NULL;
743     if (dbus_message_is_signal(msg, "org.kde.impanel", "MovePreeditCaret")) {
744         FcitxLog(DEBUG, "MovePreeditCaret");
745         DBusError error;
746         dbus_error_init(&error);
747         dbus_message_get_args(msg, &error, DBUS_TYPE_INT32, &int0 , DBUS_TYPE_INVALID);
748         dbus_error_free(&error);
749         return DBUS_HANDLER_RESULT_HANDLED;
750     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "SelectCandidate")) {
751         FcitxLog(DEBUG, "SelectCandidate: ");
752         DBusError error;
753         dbus_error_init(&error);
754         if (dbus_message_get_args(msg, &error, DBUS_TYPE_INT32, &int0 , DBUS_TYPE_INVALID)) {
755             FcitxInstanceChooseCandidateByIndex(instance, int0);
756         }
757         dbus_error_free(&error);
758         return DBUS_HANDLER_RESULT_HANDLED;
759     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "LookupTablePageUp")) {
760         FcitxLog(DEBUG, "LookupTablePageUp");
761         if (FcitxCandidateWordPageCount(FcitxInputStateGetCandidateList(input)) != 0) {
762             FcitxCandidateWordGoPrevPage(FcitxInputStateGetCandidateList(input));
763             FcitxInstanceProcessInputReturnValue(instance, IRV_DISPLAY_CANDWORDS);
764         }
765         return DBUS_HANDLER_RESULT_HANDLED;
766     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "LookupTablePageDown")) {
767         FcitxLog(DEBUG, "LookupTablePageDown");
768         if (FcitxCandidateWordPageCount(FcitxInputStateGetCandidateList(input)) != 0) {
769             FcitxCandidateWordGoNextPage(FcitxInputStateGetCandidateList(input));
770             FcitxInstanceProcessInputReturnValue(instance, IRV_DISPLAY_CANDWORDS);
771         }
772         return DBUS_HANDLER_RESULT_HANDLED;
773     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "TriggerProperty")) {
774         FcitxLog(DEBUG, "TriggerProperty: ");
775         DBusError error;
776         dbus_error_init(&error);
777         if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &s0 , DBUS_TYPE_INVALID)) {
778             if (strlen(s0) > strlen("/Fcitx/")) {
779                 s0 += strlen("/Fcitx/");
780                 if (strcmp("logo", s0) == 0) {
781                     char *prop[3];
782                     char *trans_str = _("Toggle Input Method");
783                     fcitx_utils_alloc_cat_str(prop[0], "/Fcitx/logo/toggle:",
784                                               trans_str, "::", trans_str);
785                     trans_str = _("Configure Current Input Method");
786                     fcitx_utils_alloc_cat_str(prop[1],
787                                               "/Fcitx/logo/configureim:",
788                                               trans_str, ":configure:",
789                                               trans_str);
790                     trans_str = _("Restart");
791                     fcitx_utils_alloc_cat_str(prop[2], "/Fcitx/logo/restart:",
792                                               trans_str, ":view-refresh:",
793                                               trans_str);
794                     KimExecMenu(kimpanel, prop, 3);
795                     int i;
796                     for (i = 0;i < 3;i++) {
797                         free(prop[i]);
798                     }
799                 } else if (strncmp("logo/", s0, strlen("logo/")) == 0) {
800                     s0 += strlen("logo/");
801                     if (strcmp(s0, "toggle") == 0)
802                         FcitxInstanceChangeIMState(instance, FcitxInstanceGetCurrentIC(instance));
803                     else if (strcmp(s0, "configureim") == 0) {
804                         FcitxIM* im = FcitxInstanceGetCurrentIM(kimpanel->owner);
805                         if (im && im->owner) {
806                             fcitx_utils_launch_configure_tool_for_addon(im->uniqueName);
807                         }
808                         else
809                             fcitx_utils_launch_configure_tool();
810                     }
811                     else if (strcmp(s0, "restart") == 0) {
812                         FcitxInstanceRestart(instance);
813                     }
814                 } else if (strcmp("keyboard", s0) == 0) {
815                     FcitxInstanceCloseIM(instance,
816                                          FcitxInstanceGetCurrentIC(instance));
817                 } else if (strncmp("im/", s0, strlen("im/")) == 0) {
818                     s0 += strlen("im/");
819                     FcitxInstanceSwitchIMByName(instance, s0);
820                 } else if (strncmp("im", s0, strlen("im")) == 0) {
821                     UT_array* imes = FcitxInstanceGetIMEs(instance);
822                     FcitxIM* pim;
823                     int index = 0;
824                     size_t len = utarray_len(imes);
825                     char **prop = fcitx_utils_malloc0(len * sizeof(char*));
826                     for (pim = (FcitxIM *) utarray_front(imes);
827                          pim != NULL;
828                          pim = (FcitxIM *) utarray_next(imes, pim)) {
829 
830                         SetIMMenu(pim, &prop[index]);
831                         index ++;
832                     }
833                     KimExecMenu(kimpanel, prop, len);
834                     while (len --)
835                         free(prop[len]);
836                     free(prop);
837                 } else {
838                     /* menu */
839                     const char* pos;
840                     if ((pos = strchr(s0, '/'))) {
841                         char* statusName = strndup(s0, pos - s0);
842                         FcitxUIMenu* menup = FcitxUIGetMenuByStatusName(instance, statusName);
843                         free(statusName);
844                         pos ++;
845                         int index = 0;
846                         sscanf(pos, "%d", &index);
847                         if (menup)
848                             menup->MenuAction(menup, index);
849                     } else {
850                         FcitxUIMenu *menu = FcitxUIGetMenuByStatusName(instance, s0);
851                         if (menu) {
852                             menu->UpdateMenu(menu);
853 
854                             unsigned int i = 0, index = 0;
855                             unsigned int len = utarray_len(&menu->shell);
856                             char *prop[len];
857                             for (i = 0; i < len; i++) {
858                                 FcitxMenuItem *menu_item = GetMenuItem(menu, i);
859                                 if (menu_item->type == MENUTYPE_SIMPLE) {
860                                     asprintf(&prop[index],
861                                              "/Fcitx/%s/%d:%s::%s", s0, index,
862                                              menu_item->tipstr,
863                                              menu_item->tipstr);
864                                     index++;
865                                 }
866                             }
867                             KimExecMenu(kimpanel, prop, index);
868                             while (index--)
869                                 free(prop[index]);
870                         } else {
871                             FcitxUIUpdateStatus(instance, s0);
872                         }
873                     }
874                 }
875             }
876         }
877         dbus_error_free(&error);
878         return DBUS_HANDLER_RESULT_HANDLED;
879     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "PanelCreated")) {
880         FcitxLog(DEBUG, "PanelCreated");
881         FcitxUIResumeFromFallback(instance);
882         KimpanelReset(kimpanel);
883         KimpanelRegisterAllStatus(kimpanel);
884         return DBUS_HANDLER_RESULT_HANDLED;
885     } else if (dbus_message_is_signal(msg, "org.kde.impanel2", "PanelCreated2")) {
886         FcitxLog(DEBUG, "PanelCreated2");
887         FcitxUIResumeFromFallback(instance);
888         kimpanel->version = 2;
889         KimpanelReset(kimpanel);
890         KimpanelRegisterAllStatus(kimpanel);
891         KimpanelIntrospect(kimpanel);
892         return DBUS_HANDLER_RESULT_HANDLED;
893     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "Exit")) {
894         FcitxLog(DEBUG, "Exit");
895         FcitxInstanceEnd(instance);
896         return DBUS_HANDLER_RESULT_HANDLED;
897     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "ReloadConfig")) {
898         FcitxLog(DEBUG, "ReloadConfig");
899         FcitxInstanceReloadConfig(instance);
900         return DBUS_HANDLER_RESULT_HANDLED;
901     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "Restart")) {
902         FcitxLog(DEBUG, "Restart");
903         FcitxInstanceRestart(instance);
904         return DBUS_HANDLER_RESULT_HANDLED;
905     } else if (dbus_message_is_signal(msg, "org.kde.impanel", "Configure")) {
906         FcitxLog(DEBUG, "Configure");
907         fcitx_utils_launch_configure_tool();
908         return DBUS_HANDLER_RESULT_HANDLED;
909     }
910 
911     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
912 }
913 
KimpanelOwnerChanged(void * user_data,void * arg,const char * serviceName,const char * oldName,const char * newName)914 void KimpanelOwnerChanged(void* user_data, void* arg, const char* serviceName, const char* oldName, const char* newName) {
915     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) user_data;
916     /* old die and no new one */
917     if (strcmp(serviceName, "org.kde.impanel") == 0) {
918         if (strlen(oldName) > 0 && strlen(newName) == 0) {
919             FcitxUISwitchToFallback(kimpanel->owner);
920         }
921     }
922 }
923 
KimExecDialog(FcitxKimpanelUI * kimpanel,char * prop)924 void KimExecDialog(FcitxKimpanelUI* kimpanel, char *prop)
925 {
926     dbus_uint32_t serial = 0; // unique number to associate replies with requests
927     DBusMessage* msg;
928 
929     // create a signal and check for errors
930     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
931                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
932                                   "ExecDialog"); // name of the signal
933     if (NULL == msg) {
934         FcitxLog(DEBUG, "Message Null");
935         return;
936     }
937 
938     if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID)) {
939         dbus_connection_send(kimpanel->conn, msg, &serial);
940     }
941 
942     dbus_connection_flush(kimpanel->conn);
943 
944     // free the message
945     dbus_message_unref(msg);
946 
947 }
948 
KimExecMenu(FcitxKimpanelUI * kimpanel,char * props[],int n)949 void KimExecMenu(FcitxKimpanelUI* kimpanel, char *props[], int n)
950 {
951 
952     dbus_uint32_t serial = 0; // unique number to associate replies with requests
953     DBusMessage* msg;
954     DBusMessageIter args;
955     int i;
956 
957     // create a signal and check for errors
958     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
959                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
960                                   "ExecMenu"); // name of the signal
961     if (NULL == msg) {
962         FcitxLog(DEBUG, "Message Null");
963         return;
964     }
965 
966     for (i = 0; i < n; i++) {
967         if (!fcitx_utf8_check_string(props[i]))
968             return;
969     }
970 
971     // append arguments onto signal
972     dbus_message_iter_init_append(msg, &args);
973     DBusMessageIter sub;
974     dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &sub);
975     for (i = 0; i < n; i++) {
976         if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &props[i])) {
977             FcitxLog(DEBUG, "Out Of Memory!");
978         }
979     }
980     dbus_message_iter_close_container(&args, &sub);
981 
982     // send the message and flush the connection
983     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
984         FcitxLog(DEBUG, "Out Of Memory!");
985     }
986     dbus_connection_flush(kimpanel->conn);
987 
988     // free the message
989     dbus_message_unref(msg);
990 
991 }
992 
KimRegisterProperties(FcitxKimpanelUI * kimpanel,char * props[],int n)993 void KimRegisterProperties(FcitxKimpanelUI* kimpanel, char *props[], int n)
994 {
995     dbus_uint32_t serial = 0; // unique number to associate replies with requests
996     DBusMessage* msg;
997     DBusMessageIter args;
998     int i;
999 
1000     // create a signal and check for errors
1001     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1002                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1003                                   "RegisterProperties"); // name of the signal
1004     if (NULL == msg) {
1005         FcitxLog(DEBUG, "Message Null");
1006         return;
1007     }
1008 
1009     for (i = 0; i < n; i++) {
1010         if (!fcitx_utf8_check_string(props[i]))
1011             return;
1012     }
1013 
1014     // append arguments onto signal
1015     dbus_message_iter_init_append(msg, &args);
1016     DBusMessageIter sub;
1017     dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &sub);
1018     for (i = 0; i < n; i++) {
1019         if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &props[i])) {
1020             FcitxLog(DEBUG, "Out Of Memory!");
1021         }
1022     }
1023     dbus_message_iter_close_container(&args, &sub);
1024 
1025     // send the message and flush the connection
1026     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1027         FcitxLog(DEBUG, "Out Of Memory!");
1028     }
1029 
1030     // free the message
1031     dbus_message_unref(msg);
1032 
1033 }
1034 
KimUpdateProperty(FcitxKimpanelUI * kimpanel,char * prop)1035 void KimUpdateProperty(FcitxKimpanelUI* kimpanel, char *prop)
1036 {
1037 
1038     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1039     DBusMessage* msg;
1040     DBusMessageIter args;
1041 
1042     // create a signal and check for errors
1043     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1044                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1045                                   "UpdateProperty"); // name of the signal
1046     if (NULL == msg) {
1047         FcitxLog(DEBUG, "Message Null");
1048         return;
1049     }
1050 
1051     if (!fcitx_utf8_check_string(prop))
1052         return;
1053 
1054     // append arguments onto signal
1055     dbus_message_iter_init_append(msg, &args);
1056     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &prop)) {
1057         FcitxLog(DEBUG, "Out Of Memory!");
1058     }
1059 
1060     // send the message and flush the connection
1061     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1062         FcitxLog(DEBUG, "Out Of Memory!");
1063     }
1064 
1065     // free the message
1066     dbus_message_unref(msg);
1067 
1068 }
1069 
KimRemoveProperty(FcitxKimpanelUI * kimpanel,char * prop)1070 void KimRemoveProperty(FcitxKimpanelUI* kimpanel, char *prop)
1071 {
1072 
1073     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1074     DBusMessage* msg;
1075     DBusMessageIter args;
1076 
1077     // create a signal and check for errors
1078     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1079                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1080                                   "RemoveProperty"); // name of the signal
1081     if (NULL == msg) {
1082         FcitxLog(DEBUG, "Message Null");
1083         return;
1084     }
1085 
1086     if (!fcitx_utf8_check_string(prop))
1087         return;
1088 
1089     // append arguments onto signal
1090     dbus_message_iter_init_append(msg, &args);
1091     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &prop)) {
1092         FcitxLog(DEBUG, "Out Of Memory!");
1093     }
1094 
1095     // send the message and flush the connection
1096     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1097         FcitxLog(DEBUG, "Out Of Memory!");
1098     }
1099 
1100     // free the message
1101     dbus_message_unref(msg);
1102 
1103 }
1104 
KimEnable(FcitxKimpanelUI * kimpanel,boolean toEnable)1105 void KimEnable(FcitxKimpanelUI* kimpanel, boolean toEnable)
1106 {
1107     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1108     DBusMessage* msg;
1109     DBusMessageIter args;
1110 
1111     // create a signal and check for errors
1112     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1113                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1114                                   "Enable"); // name of the signal
1115     if (NULL == msg) {
1116         FcitxLog(DEBUG, "Message Null");
1117         return;
1118     }
1119 
1120     // append arguments onto signal
1121     dbus_message_iter_init_append(msg, &args);
1122     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &toEnable)) {
1123         FcitxLog(DEBUG, "Out Of Memory!");
1124     }
1125 
1126     // send the message and flush the connection
1127     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1128         FcitxLog(DEBUG, "Out Of Memory!");
1129     }
1130 
1131     // free the message
1132     dbus_message_unref(msg);
1133 
1134 }
1135 
KimShowAux(FcitxKimpanelUI * kimpanel,boolean toShow)1136 void KimShowAux(FcitxKimpanelUI* kimpanel, boolean toShow)
1137 {
1138 
1139     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1140     DBusMessage* msg;
1141     DBusMessageIter args;
1142 
1143     // create a signal and check for errors
1144     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1145                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1146                                   "ShowAux"); // name of the signal
1147     if (NULL == msg) {
1148         FcitxLog(DEBUG, "Message Null");
1149         return;
1150     }
1151 
1152     // append arguments onto signal
1153     dbus_message_iter_init_append(msg, &args);
1154     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &toShow)) {
1155         FcitxLog(DEBUG, "Out Of Memory!");
1156     }
1157 
1158     // send the message and flush the connection
1159     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1160         FcitxLog(DEBUG, "Out Of Memory!");
1161     }
1162 
1163     // free the message
1164     dbus_message_unref(msg);
1165 
1166 }
1167 
KimShowPreedit(FcitxKimpanelUI * kimpanel,boolean toShow)1168 void KimShowPreedit(FcitxKimpanelUI* kimpanel, boolean toShow)
1169 {
1170 
1171     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1172     DBusMessage* msg;
1173     DBusMessageIter args;
1174 
1175     // create a signal and check for errors
1176     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1177                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1178                                   "ShowPreedit"); // name of the signal
1179     if (NULL == msg) {
1180         FcitxLog(DEBUG, "Message Null");
1181         return;
1182     }
1183 
1184     // append arguments onto signal
1185     dbus_message_iter_init_append(msg, &args);
1186     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &toShow)) {
1187         FcitxLog(DEBUG, "Out Of Memory!");
1188     }
1189 
1190     // send the message and flush the connection
1191     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1192         FcitxLog(DEBUG, "Out Of Memory!");
1193     }
1194 
1195     // free the message
1196     dbus_message_unref(msg);
1197 
1198 }
1199 
KimUpdateLookupTableCursor(FcitxKimpanelUI * kimpanel,int cursor)1200 void KimUpdateLookupTableCursor(FcitxKimpanelUI* kimpanel, int cursor)
1201 {
1202     if (kimpanel->lastCursor != cursor)
1203         kimpanel->lastCursor = cursor;
1204     else
1205         return;
1206     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1207     DBusMessage* msg;
1208     DBusMessageIter args;
1209 
1210     // create a signal and check for errors
1211     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1212                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1213                                   "UpdateLookupTableCursor"); // name of the signal
1214     if (NULL == msg) {
1215         FcitxLog(DEBUG, "Message Null");
1216         return;
1217     }
1218 
1219     // append arguments onto signal
1220     dbus_message_iter_init_append(msg, &args);
1221     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &cursor)) {
1222         FcitxLog(DEBUG, "Out Of Memory!");
1223     }
1224 
1225     // send the message and flush the connection
1226     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1227         FcitxLog(DEBUG, "Out Of Memory!");
1228     }
1229 
1230     // free the message
1231     dbus_message_unref(msg);
1232 }
1233 
KimShowLookupTable(FcitxKimpanelUI * kimpanel,boolean toShow)1234 void KimShowLookupTable(FcitxKimpanelUI* kimpanel, boolean toShow)
1235 {
1236 
1237     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1238     DBusMessage* msg;
1239     DBusMessageIter args;
1240 
1241     // create a signal and check for errors
1242     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1243                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1244                                   "ShowLookupTable"); // name of the signal
1245     if (NULL == msg) {
1246         FcitxLog(DEBUG, "Message Null");
1247         return;
1248     }
1249 
1250     // append arguments onto signal
1251     dbus_message_iter_init_append(msg, &args);
1252     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &toShow)) {
1253         FcitxLog(DEBUG, "Out Of Memory!");
1254     }
1255 
1256     // send the message and flush the connection
1257     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1258         FcitxLog(DEBUG, "Out Of Memory!");
1259     }
1260 
1261     // free the message
1262     dbus_message_unref(msg);
1263 
1264 }
1265 
KimUpdateLookupTable(FcitxKimpanelUI * kimpanel,char * labels[],int nLabel,char * texts[],int nText,boolean has_prev,boolean has_next)1266 void KimUpdateLookupTable(FcitxKimpanelUI* kimpanel, char *labels[], int nLabel, char *texts[], int nText, boolean has_prev, boolean has_next)
1267 {
1268     int i;
1269     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1270     DBusMessage* msg;
1271     DBusMessageIter args;
1272 
1273     // create a signal and check for errors
1274     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1275                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1276                                   "UpdateLookupTable"); // name of the signal
1277     if (NULL == msg) {
1278         FcitxLog(DEBUG, "Message Null");
1279         return;
1280     }
1281     for (i = 0; i < nLabel; i++) {
1282         if (!fcitx_utf8_check_string(labels[i]))
1283             return;
1284     }
1285     for (i = 0; i < nText; i++) {
1286         if (!fcitx_utf8_check_string(texts[i]))
1287             return;
1288     }
1289     DBusMessageIter subLabel;
1290     DBusMessageIter subText;
1291     DBusMessageIter subAttrs;
1292     // append arguments onto signal
1293     dbus_message_iter_init_append(msg, &args);
1294     dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &subLabel);
1295     for (i = 0; i < nLabel; i++) {
1296         if (!dbus_message_iter_append_basic(&subLabel, DBUS_TYPE_STRING,
1297                                             &labels[i])) {
1298             FcitxLog(DEBUG, "Out Of Memory!");
1299         }
1300     }
1301     dbus_message_iter_close_container(&args, &subLabel);
1302 
1303     dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &subText);
1304     for (i = 0; i < nText; i++) {
1305         if (!dbus_message_iter_append_basic(&subText, DBUS_TYPE_STRING,
1306                                             &texts[i])) {
1307             FcitxLog(DEBUG, "Out Of Memory!");
1308         }
1309     }
1310     dbus_message_iter_close_container(&args, &subText);
1311 
1312     char *attr = "";
1313     dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &subAttrs);
1314     for (i = 0; i < nLabel; i++) {
1315         if (!dbus_message_iter_append_basic(&subAttrs, DBUS_TYPE_STRING, &attr)) {
1316             FcitxLog(DEBUG, "Out Of Memory!");
1317         }
1318     }
1319     dbus_message_iter_close_container(&args, &subAttrs);
1320 
1321     dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &has_prev);
1322     dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &has_next);
1323 
1324     // send the message and flush the connection
1325     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1326         FcitxLog(DEBUG, "Out Of Memory!");
1327     }
1328 
1329     // free the message
1330     dbus_message_unref(msg);
1331 
1332 }
1333 
KimSetLookupTable(FcitxKimpanelUI * kimpanel,char * labels[],int nLabel,char * texts[],int nText,boolean has_prev,boolean has_next,int cursor,int layout)1334 void KimSetLookupTable(FcitxKimpanelUI* kimpanel,
1335                        char *labels[], int nLabel,
1336                        char *texts[], int nText,
1337                        boolean has_prev,
1338                        boolean has_next,
1339                        int cursor,
1340                        int layout
1341                       )
1342 {
1343     int i;
1344     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1345     DBusMessage* msg;
1346     DBusMessageIter args;
1347 
1348     // create a signal and check for errors
1349     msg = dbus_message_new_method_call("org.kde.impanel",
1350                                        "/org/kde/impanel",
1351                                        "org.kde.impanel2",
1352                                        "SetLookupTable"); // name of the signal
1353     if (NULL == msg) {
1354         FcitxLog(DEBUG, "Message Null");
1355         return;
1356     }
1357     for (i = 0; i < nLabel; i++) {
1358         if (!fcitx_utf8_check_string(labels[i]))
1359             return;
1360     }
1361     for (i = 0; i < nText; i++) {
1362         if (!fcitx_utf8_check_string(texts[i]))
1363             return;
1364     }
1365     DBusMessageIter subLabel;
1366     DBusMessageIter subText;
1367     DBusMessageIter subAttrs;
1368     // append arguments onto signal
1369     dbus_message_iter_init_append(msg, &args);
1370     dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &subLabel);
1371     for (i = 0; i < nLabel; i++) {
1372         if (!dbus_message_iter_append_basic(&subLabel, DBUS_TYPE_STRING, &labels[i])) {
1373             FcitxLog(DEBUG, "Out Of Memory!");
1374         }
1375     }
1376     dbus_message_iter_close_container(&args, &subLabel);
1377 
1378     dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &subText);
1379     for (i = 0; i < nText; i++) {
1380         if (!dbus_message_iter_append_basic(&subText, DBUS_TYPE_STRING, &texts[i])) {
1381             FcitxLog(DEBUG, "Out Of Memory!");
1382         }
1383     }
1384     dbus_message_iter_close_container(&args, &subText);
1385 
1386     char *attr = "";
1387     dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &subAttrs);
1388     for (i = 0; i < nLabel; i++) {
1389         if (!dbus_message_iter_append_basic(&subAttrs, DBUS_TYPE_STRING, &attr)) {
1390             FcitxLog(DEBUG, "Out Of Memory!");
1391         }
1392     }
1393     dbus_message_iter_close_container(&args, &subAttrs);
1394 
1395     dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &has_prev);
1396     dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &has_next);
1397     dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &cursor);
1398     dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &layout);
1399 
1400     // send the message and flush the connection
1401     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1402         FcitxLog(DEBUG, "Out Of Memory!");
1403     }
1404 
1405     // free the message
1406     dbus_message_unref(msg);
1407 
1408 }
1409 
KimUpdatePreeditCaret(FcitxKimpanelUI * kimpanel,int position)1410 void KimUpdatePreeditCaret(FcitxKimpanelUI* kimpanel, int position)
1411 {
1412 
1413     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1414     DBusMessage* msg;
1415     DBusMessageIter args;
1416 
1417     // create a signal and check for errors
1418     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1419                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1420                                   "UpdatePreeditCaret"); // name of the signal
1421     if (NULL == msg) {
1422         FcitxLog(DEBUG, "Message Null");
1423         return;
1424     }
1425 
1426     // append arguments onto signal
1427     dbus_message_iter_init_append(msg, &args);
1428     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &position)) {
1429         FcitxLog(DEBUG, "Out Of Memory!");
1430     }
1431 
1432     // send the message and flush the connection
1433     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1434         FcitxLog(DEBUG, "Out Of Memory!");
1435     }
1436 
1437     // free the message
1438     dbus_message_unref(msg);
1439 
1440 }
1441 
KimUpdatePreeditText(FcitxKimpanelUI * kimpanel,char * text)1442 void KimUpdatePreeditText(FcitxKimpanelUI* kimpanel, char *text)
1443 {
1444 
1445     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1446     DBusMessage* msg;
1447     DBusMessageIter args;
1448 
1449     // create a signal and check for errors
1450     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1451                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1452                                   "UpdatePreeditText"); // name of the signal
1453     if (NULL == msg) {
1454         FcitxLog(DEBUG, "Message Null");
1455         return;
1456     }
1457 
1458     char *attr = "";
1459     // append arguments onto signal
1460     dbus_message_iter_init_append(msg, &args);
1461     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &text)) {
1462         FcitxLog(DEBUG, "Out Of Memory!");
1463     }
1464     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &attr)) {
1465         FcitxLog(DEBUG, "Out Of Memory!");
1466     }
1467 
1468     // send the message and flush the connection
1469     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1470         FcitxLog(DEBUG, "Out Of Memory!");
1471     }
1472 
1473     // free the message
1474     dbus_message_unref(msg);
1475 
1476 }
1477 
KimUpdateAux(FcitxKimpanelUI * kimpanel,char * text)1478 void KimUpdateAux(FcitxKimpanelUI* kimpanel, char *text)
1479 {
1480 
1481     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1482     DBusMessage* msg;
1483     DBusMessageIter args;
1484 
1485     // create a signal and check for errors
1486     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1487                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1488                                   "UpdateAux"); // name of the signal
1489     if (NULL == msg) {
1490         FcitxLog(DEBUG, "Message Null");
1491         return;
1492     }
1493     if (!fcitx_utf8_check_string(text))
1494         return;
1495 
1496     char *attr = "";
1497 
1498     // append arguments onto signal
1499     dbus_message_iter_init_append(msg, &args);
1500     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &text)) {
1501         FcitxLog(DEBUG, "Out Of Memory!");
1502     }
1503     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &attr)) {
1504         FcitxLog(DEBUG, "Out Of Memory!");
1505     }
1506 
1507     // send the message and flush the connection
1508     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1509         FcitxLog(DEBUG, "Out Of Memory!");
1510     }
1511 
1512     // free the message
1513     dbus_message_unref(msg);
1514 
1515 }
1516 
KimUpdateSpotLocation(FcitxKimpanelUI * kimpanel,int x,int y)1517 void KimUpdateSpotLocation(FcitxKimpanelUI* kimpanel, int x, int y)
1518 {
1519     if (kimpanel->lastUpdateX == x && kimpanel->lastUpdateY == y)
1520         return;
1521     kimpanel->lastUpdateX = x;
1522     kimpanel->lastUpdateY = y;
1523     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1524     DBusMessage* msg;
1525     DBusMessageIter args;
1526 
1527     // create a signal and check for errors
1528     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1529                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1530                                   "UpdateSpotLocation"); // name of the signal
1531     if (NULL == msg) {
1532         FcitxLog(DEBUG, "Message Null");
1533         return;
1534     }
1535 
1536     // append arguments onto signal
1537     dbus_message_iter_init_append(msg, &args);
1538     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &x)) {
1539         FcitxLog(DEBUG, "Out Of Memory!");
1540     }
1541     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &y)) {
1542         FcitxLog(DEBUG, "Out Of Memory!");
1543     }
1544 
1545     // send the message and flush the connection
1546     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1547         FcitxLog(DEBUG, "Out Of Memory!");
1548     }
1549 
1550     // free the message
1551     dbus_message_unref(msg);
1552 
1553 }
1554 
KimSetSpotRect(FcitxKimpanelUI * kimpanel,int x,int y,int w,int h,boolean relative)1555 void KimSetSpotRect(FcitxKimpanelUI* kimpanel, int x, int y, int w, int h, boolean relative)
1556 {
1557     if (kimpanel->lastUpdateX == x && kimpanel->lastUpdateY == y && kimpanel->lastUpdateW == w && kimpanel->lastUpdateH == h)
1558         return;
1559     kimpanel->lastUpdateX = x;
1560     kimpanel->lastUpdateY = y;
1561     kimpanel->lastUpdateW = w;
1562     kimpanel->lastUpdateH = h;
1563     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1564     DBusMessage* msg;
1565 
1566     boolean useRelative = kimpanel->hasSetRelativeSpotRect && relative;
1567 
1568     // create a signal and check for errors
1569     msg = dbus_message_new_method_call("org.kde.impanel",
1570                                        "/org/kde/impanel",
1571                                        "org.kde.impanel2",
1572                                        useRelative ? "SetRelativeSpotRect" : "SetSpotRect"); // name of the signal
1573     if (NULL == msg) {
1574         FcitxLog(DEBUG, "Message Null");
1575         return;
1576     }
1577 
1578     if (!dbus_message_append_args(
1579             msg,
1580             DBUS_TYPE_INT32, &x,
1581             DBUS_TYPE_INT32, &y,
1582             DBUS_TYPE_INT32, &w,
1583             DBUS_TYPE_INT32, &h,
1584             DBUS_TYPE_INVALID
1585             )) {
1586         FcitxLog(DEBUG, "Out Of Memory!");
1587     }
1588 
1589     // send the message and flush the connection
1590     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1591         FcitxLog(DEBUG, "Out Of Memory!");
1592     }
1593 
1594     // free the message
1595     dbus_message_unref(msg);
1596 }
1597 
1598 
KimUpdateScreen(FcitxKimpanelUI * kimpanel,int id)1599 void KimUpdateScreen(FcitxKimpanelUI* kimpanel, int id)
1600 {
1601 
1602     dbus_uint32_t serial = 0; // unique number to associate replies with requests
1603     DBusMessage* msg;
1604     DBusMessageIter args;
1605 
1606     // create a signal and check for errors
1607     msg = dbus_message_new_signal(FCITX_KIMPANEL_PATH, // object name of the signal
1608                                   FCITX_KIMPANEL_INTERFACE, // interface name of the signal
1609                                   "UpdateScreen"); // name of the signal
1610     if (NULL == msg) {
1611         FcitxLog(DEBUG, "Message Null");
1612         return;
1613     }
1614 
1615     // append arguments onto signal
1616     dbus_message_iter_init_append(msg, &args);
1617     if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &id)) {
1618         FcitxLog(DEBUG, "Out Of Memory!");
1619     }
1620 
1621     // send the message and flush the connection
1622     if (!dbus_connection_send(kimpanel->conn, msg, &serial)) {
1623         FcitxLog(DEBUG, "Out Of Memory!");
1624     }
1625 
1626     // free the message
1627     dbus_message_unref(msg);
1628 
1629 }
1630 
CalKimCursorPos(FcitxKimpanelUI * kimpanel)1631 int CalKimCursorPos(FcitxKimpanelUI *kimpanel)
1632 {
1633     int i = 0;
1634     unsigned int iChar;
1635     int iCount = 0;
1636     FcitxMessages *messageUp = kimpanel->messageUp;
1637 
1638     const char *p1;
1639     const char *pivot;
1640 
1641     iChar = kimpanel->iCursorPos;
1642 
1643     for (i = 0;i < FcitxMessagesGetMessageCount(messageUp);i++) {
1644         if (kimpanel->iCursorPos && iChar) {
1645             p1 = pivot = FcitxMessagesGetMessageString(messageUp, i);
1646             while (*p1 && p1 < pivot + iChar) {
1647                 p1 = p1 + fcitx_utf8_char_len(p1);
1648                 iCount ++;
1649             }
1650             if (strlen(FcitxMessagesGetMessageString(messageUp, i)) > iChar) {
1651                 iChar = 0;
1652             } else {
1653                 iChar -= strlen(FcitxMessagesGetMessageString(messageUp, i));
1654             }
1655         }
1656     }
1657 
1658     return iCount;
1659 }
1660 
KimpanelServiceExistCallback(DBusPendingCall * call,void * data)1661 void KimpanelServiceExistCallback(DBusPendingCall *call, void *data)
1662 {
1663     FcitxKimpanelUI *kimpanel = (FcitxKimpanelUI*)data;
1664 
1665     DBusMessage *msg = dbus_pending_call_steal_reply(call);
1666 
1667     if (msg) {
1668         dbus_bool_t has = FALSE;
1669         DBusError error;
1670         dbus_error_init(&error);
1671         dbus_message_get_args(msg, &error,
1672                               DBUS_TYPE_BOOLEAN, &has, DBUS_TYPE_INVALID);
1673         dbus_message_unref(msg);
1674         dbus_error_free(&error);
1675         if (!has) {
1676             FcitxUISwitchToFallback(kimpanel->owner);
1677         } else {
1678             KimpanelIntrospect(kimpanel);
1679         }
1680     }
1681 }
1682 
KimpanelIntrospect(FcitxKimpanelUI * kimpanel)1683 void KimpanelIntrospect(FcitxKimpanelUI* kimpanel)
1684 {
1685     const char* kimpanelServiceName = "org.kde.impanel";
1686     DBusMessage* message = dbus_message_new_method_call(kimpanelServiceName, "/org/kde/impanel", DBUS_INTERFACE_INTROSPECTABLE, "Introspect");
1687 
1688     DBusPendingCall *call = NULL;
1689     dbus_bool_t reply =
1690         dbus_connection_send_with_reply(kimpanel->conn, message,
1691                                         &call, DBUS_TIMEOUT_USE_DEFAULT);
1692     dbus_message_unref(message);
1693     if (reply == TRUE) {
1694         dbus_pending_call_set_notify(call, KimpanelIntrospectCallback,
1695                                      kimpanel, NULL);
1696         dbus_pending_call_unref(call);
1697     }
1698     dbus_connection_flush(kimpanel->conn);
1699 }
1700 
KimpanelIntrospectCallback(DBusPendingCall * call,void * data)1701 void KimpanelIntrospectCallback(DBusPendingCall *call, void *data)
1702 {
1703     FcitxKimpanelUI *kimpanel = (FcitxKimpanelUI*)data;
1704     DBusMessage *msg = dbus_pending_call_steal_reply(call);
1705 
1706     if (msg) {
1707         const char *s;
1708         DBusError error;
1709         dbus_error_init(&error);
1710         if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &s,
1711                                   DBUS_TYPE_INVALID)) {
1712             if (strstr(s, "org.kde.impanel2")) {
1713                 kimpanel->version = 2;
1714                 if (strstr(s, "SetLookupTable")) {
1715                     kimpanel->hasSetLookupTable = true;
1716                 }
1717                 if (strstr(s, "SetRelativeSpotRect")) {
1718                     kimpanel->hasSetRelativeSpotRect = true;
1719                 }
1720             }
1721         }
1722         dbus_message_unref(msg);
1723         dbus_error_free(&error);
1724     }
1725 }
1726 
1727 
KimpanelSuspend(void * arg)1728 void KimpanelSuspend(void* arg)
1729 {
1730     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
1731     kimpanel->version = 1;
1732     kimpanel->hasSetLookupTable = false;
1733     kimpanel->hasSetRelativeSpotRect = false;
1734 }
1735 
1736 
KimpanelDestroy(void * arg)1737 void KimpanelDestroy(void* arg)
1738 {
1739     FcitxKimpanelUI* kimpanel = (FcitxKimpanelUI*) arg;
1740     KimpanelCloseInputWindow(kimpanel);
1741     KimRegisterProperties(kimpanel, NULL, 0);
1742     dbus_connection_unregister_object_path(kimpanel->conn, FCITX_KIMPANEL_PATH);
1743     dbus_connection_remove_filter(kimpanel->conn, KimpanelDBusFilter, kimpanel);
1744 
1745     dbus_bus_remove_match(kimpanel->conn,
1746                           "type='signal',sender='org.kde.impanel',interface='org.kde.impanel'",
1747                            NULL);
1748     dbus_bus_remove_match(kimpanel->conn,
1749                           "type='signal',sender='org.kde.impanel',interface='org.kde.impanel2'",
1750                           NULL);
1751 
1752     dbus_connection_flush(kimpanel->conn);
1753 
1754     free(kimpanel->messageUp);
1755     free(kimpanel->messageDown);
1756     free(kimpanel);
1757 }
1758 
1759 // kate: indent-mode cstyle; space-indent on; indent-width 0;
1760