1 /***************************************************************************
2 * Copyright (C) 2010~2012 by CSSlayer *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
19
20 #include <limits.h>
21 #include <dbus/dbus.h>
22
23 #include "fcitx/fcitx.h"
24 #include "fcitx/frontend.h"
25 #include "fcitx-utils/utils.h"
26 #include "module/dbus/fcitx-dbus.h"
27 #include "module/dbusstuff/property.h"
28 #include "fcitx/instance.h"
29 #include "fcitx/module.h"
30 #include "fcitx-utils/log.h"
31 #include "fcitx/configfile.h"
32 #include "fcitx/hook.h"
33 #include "ipc.h"
34
35 #define GetIPCIC(ic) ((FcitxIPCIC*) (ic)->privateic)
36
37 typedef struct _FcitxIPCCreateICPriv {
38 DBusMessage* message;
39 DBusConnection* conn;
40 } FcitxIPCCreateICPriv;
41
42 typedef struct _FcitxLastSentIMInfo
43 {
44 char* name;
45 char* uniqueName;
46 char* langCode;
47 } FcitxLastSentIMInfo;
48
49 typedef struct _FcitxIPCIC {
50 int id;
51 char* sender;
52 char path[32];
53 int width;
54 int height;
55 pid_t pid;
56 char* surroundingText;
57 unsigned int anchor;
58 unsigned int cursor;
59 boolean lastPreeditIsEmpty;
60 boolean isPriv;
61 FcitxLastSentIMInfo lastSentIMInfo;
62 } FcitxIPCIC;
63
64 typedef struct _FcitxIPCFrontend {
65 int frontendid;
66 int maxid;
67 DBusConnection* _conn;
68 DBusConnection* _privconn;
69 FcitxInstance* owner;
70 } FcitxIPCFrontend;
71
72 typedef struct _FcitxIPCKeyEvent {
73 FcitxKeySym sym;
74 unsigned int state;
75 } FcitxIPCKeyEvent;
76
77 static void* IPCCreate(FcitxInstance* instance, int frontendid);
78 static boolean IPCDestroy(void* arg);
79 void IPCCreateIC(void* arg, FcitxInputContext* context, void *priv);
80 boolean IPCCheckIC(void* arg, FcitxInputContext* context, void* priv);
81 void IPCDestroyIC(void* arg, FcitxInputContext* context);
82 static void IPCEnableIM(void* arg, FcitxInputContext* ic);
83 static void IPCCloseIM(void* arg, FcitxInputContext* ic);
84 static void IPCCommitString(void* arg, FcitxInputContext* ic, const char* str);
85 static void IPCForwardKey(void* arg, FcitxInputContext* ic, FcitxKeyEventType event, FcitxKeySym sym, unsigned int state);
86 static void IPCSetWindowOffset(void* arg, FcitxInputContext* ic, int x, int y);
87 static void IPCGetWindowRect(void* arg, FcitxInputContext* ic, int* x, int* y, int* w, int* h);
88 static void IPCUpdatePreedit(void* arg, FcitxInputContext* ic);
89 static void IPCDeleteSurroundingText(void* arg, FcitxInputContext* ic, int offset, unsigned int size);
90 static boolean IPCGetSurroundingText(void* arg, FcitxInputContext* ic, char** str, unsigned int* cursor, unsigned int* anchor);
91 static void IPCUpdateClientSideUI(void* arg, FcitxInputContext* ic);
92 static DBusHandlerResult IPCDBusEventHandler(DBusConnection *connection, DBusMessage *message, void *user_data);
93 static DBusHandlerResult IPCICDBusEventHandler(DBusConnection *connection, DBusMessage *msg, void *user_data);
94 static void IPCICFocusIn(FcitxIPCFrontend* ipc, FcitxInputContext* ic);
95 static void IPCICFocusOut(FcitxIPCFrontend* ipc, FcitxInputContext* ic);
96 static void IPCICReset(FcitxIPCFrontend* ipc, FcitxInputContext* ic);
97 static void IPCICSetCursorRect(FcitxIPCFrontend* ipc, FcitxInputContext* ic, int x, int y, int w, int h);
98 static int IPCProcessKey(FcitxIPCFrontend* ipc, FcitxInputContext* callic, const uint32_t originsym, const uint32_t keycode, const uint32_t originstate, uint32_t t, FcitxKeyEventType type);
99 static boolean IPCCheckICFromSameApplication(void* arg, FcitxInputContext* icToCheck, FcitxInputContext* ic);
100 static void IPCEmitPropertiesChanged(void* arg, const char* const* properties);
101 static void IPCEmitPropertyChanged(void* arg, const char* property);
102 static void IPCGetPropertyIMList(void* arg, DBusMessageIter* iter);
103 static void IPCSetPropertyIMList(void* arg, DBusMessageIter* iter);
104 static void IPCUpdateIMList(void* arg);
105 static void IPCGetPropertyCurrentIM(void* arg, DBusMessageIter* iter);
106 static void IPCSetPropertyCurrentIM(void* arg, DBusMessageIter* iter);
107 static void IPCUpdateCurrentIM(void* arg);
108 static void IPCUpdateIMInfoForIC(void* arg);
109 static pid_t IPCGetPid(void* arg, FcitxInputContext* ic);
110
111 const FcitxDBusPropertyTable propertTable[] = {
112 { FCITX_IM_DBUS_INTERFACE, "IMList", "a(sssb)", IPCGetPropertyIMList, IPCSetPropertyIMList },
113 { FCITX_IM_DBUS_INTERFACE, "CurrentIM", "s", IPCGetPropertyCurrentIM, IPCSetPropertyCurrentIM },
114 { NULL, NULL, NULL, NULL, NULL }
115 };
116
117 const char * im_introspection_xml =
118 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
119 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">"
120 "<node>"
121 "<interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">"
122 "<method name=\"Introspect\">"
123 "<arg name=\"data\" direction=\"out\" type=\"s\"/>"
124 "</method>"
125 "</interface>"
126 "<interface name=\"" DBUS_INTERFACE_PROPERTIES "\">"
127 "<method name=\"Get\">"
128 "<arg name=\"interface_name\" direction=\"in\" type=\"s\"/>"
129 "<arg name=\"property_name\" direction=\"in\" type=\"s\"/>"
130 "<arg name=\"value\" direction=\"out\" type=\"v\"/>"
131 "</method>"
132 "<method name=\"Set\">"
133 "<arg name=\"interface_name\" direction=\"in\" type=\"s\"/>"
134 "<arg name=\"property_name\" direction=\"in\" type=\"s\"/>"
135 "<arg name=\"value\" direction=\"in\" type=\"v\"/>"
136 "</method>"
137 "<method name=\"GetAll\">"
138 "<arg name=\"interface_name\" direction=\"in\" type=\"s\"/>"
139 "<arg name=\"values\" direction=\"out\" type=\"a{sv}\"/>"
140 "</method>"
141 "<signal name=\"PropertiesChanged\">"
142 "<arg name=\"interface_name\" type=\"s\"/>"
143 "<arg name=\"changed_properties\" type=\"a{sv}\"/>"
144 "<arg name=\"invalidated_properties\" type=\"as\"/>"
145 "</signal>"
146 "</interface>"
147 "<interface name=\"" FCITX_IM_DBUS_INTERFACE "\">"
148 "<method name=\"CreateIC\">"
149 "<arg name=\"icid\" direction=\"out\" type=\"i\"/>"
150 "<arg name=\"keyval1\" direction=\"out\" type=\"u\"/>"
151 "<arg name=\"state1\" direction=\"out\" type=\"u\"/>"
152 "<arg name=\"keyval2\" direction=\"out\" type=\"u\"/>"
153 "<arg name=\"state2\" direction=\"out\" type=\"u\"/>"
154 "</method>"
155 "<method name=\"CreateICv2\">"
156 "<arg name=\"appname\" direction=\"in\" type=\"s\"/>"
157 "<arg name=\"icid\" direction=\"out\" type=\"i\"/>"
158 "<arg name=\"enable\" direction=\"out\" type=\"b\"/>"
159 "<arg name=\"keyval1\" direction=\"out\" type=\"u\"/>"
160 "<arg name=\"state1\" direction=\"out\" type=\"u\"/>"
161 "<arg name=\"keyval2\" direction=\"out\" type=\"u\"/>"
162 "<arg name=\"state2\" direction=\"out\" type=\"u\"/>"
163 "</method>"
164 "<method name=\"CreateICv3\">"
165 "<arg name=\"appname\" direction=\"in\" type=\"s\"/>"
166 "<arg name=\"pid\" direction=\"in\" type=\"i\"/>"
167 "<arg name=\"icid\" direction=\"out\" type=\"i\"/>"
168 "<arg name=\"enable\" direction=\"out\" type=\"b\"/>"
169 "<arg name=\"keyval1\" direction=\"out\" type=\"u\"/>"
170 "<arg name=\"state1\" direction=\"out\" type=\"u\"/>"
171 "<arg name=\"keyval2\" direction=\"out\" type=\"u\"/>"
172 "<arg name=\"state2\" direction=\"out\" type=\"u\"/>"
173 "</method>"
174 "<method name=\"Exit\">"
175 "</method>"
176 "<method name=\"GetCurrentIM\">"
177 "<arg name=\"im\" direction=\"out\" type=\"s\"/>"
178 "</method>"
179 "<method name=\"SetCurrentIM\">"
180 "<arg name=\"im\" direction=\"in\" type=\"s\"/>"
181 "</method>"
182 "<method name=\"ReloadConfig\">"
183 "</method>"
184 "<method name=\"ReloadAddonConfig\">"
185 "<arg name=\"addon\" direction=\"in\" type=\"s\"/>"
186 "</method>"
187 "<method name=\"Restart\">"
188 "</method>"
189 "<method name=\"Configure\">"
190 "</method>"
191 "<method name=\"ConfigureAddon\">"
192 "<arg name=\"addon\" direction=\"in\" type=\"s\"/>"
193 "</method>"
194 "<method name=\"ConfigureIM\">"
195 "<arg name=\"im\" direction=\"in\" type=\"s\"/>"
196 "</method>"
197 "<method name=\"GetCurrentUI\">"
198 "<arg name=\"addon\" direction=\"out\" type=\"s\"/>"
199 "</method>"
200 "<method name=\"GetIMAddon\">"
201 "<arg name=\"im\" direction=\"in\" type=\"s\"/>"
202 "<arg name=\"addon\" direction=\"out\" type=\"s\"/>"
203 "</method>"
204 "<method name=\"ActivateIM\">"
205 "</method>"
206 "<method name=\"InactivateIM\">"
207 "</method>"
208 "<method name=\"ToggleIM\">"
209 "</method>"
210 "<method name=\"ResetIMList\">"
211 "</method>"
212 "<method name=\"GetCurrentState\">"
213 "<arg name=\"state\" direction=\"out\" type=\"i\"/>"
214 "</method>"
215 "<property access=\"readwrite\" type=\"a(sssb)\" name=\"IMList\">"
216 "<annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"true\"/>"
217 "</property>"
218 "<property access=\"readwrite\" type=\"s\" name=\"CurrentIM\">"
219 "<annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"true\"/>"
220 "</property>"
221 "</interface>"
222 "</node>";
223
224 const char * ic_introspection_xml =
225 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
226 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">"
227 "<node>"
228 "<interface name=\"org.freedesktop.DBus.Introspectable\">"
229 "<method name=\"Introspect\">"
230 "<arg name=\"data\" direction=\"out\" type=\"s\"/>"
231 "</method>"
232 "</interface>"
233 "<interface name=\"" FCITX_IC_DBUS_INTERFACE "\">"
234 "<method name=\"EnableIC\">"
235 "</method>"
236 "<method name=\"CloseIC\">"
237 "</method>"
238 "<method name=\"FocusIn\">"
239 "</method>"
240 "<method name=\"FocusOut\">"
241 "</method>"
242 "<method name=\"Reset\">"
243 "</method>"
244 "<method name=\"CommitPreedit\">"
245 "</method>"
246 "<method name=\"MouseEvent\">"
247 "<arg name=\"x\" direction=\"in\" type=\"i\"/>"
248 "</method>"
249 "<method name=\"SetCursorLocation\">"
250 "<arg name=\"x\" direction=\"in\" type=\"i\"/>"
251 "<arg name=\"y\" direction=\"in\" type=\"i\"/>"
252 "</method>"
253 "<method name=\"SetCursorRect\">"
254 "<arg name=\"x\" direction=\"in\" type=\"i\"/>"
255 "<arg name=\"y\" direction=\"in\" type=\"i\"/>"
256 "<arg name=\"w\" direction=\"in\" type=\"i\"/>"
257 "<arg name=\"h\" direction=\"in\" type=\"i\"/>"
258 "</method>"
259 "<method name=\"SetCapacity\">"
260 "<arg name=\"caps\" direction=\"in\" type=\"u\"/>"
261 "</method>"
262 "<method name=\"SetSurroundingText\">"
263 "<arg name=\"text\" direction=\"in\" type=\"s\"/>"
264 "<arg name=\"cursor\" direction=\"in\" type=\"u\"/>"
265 "<arg name=\"anchor\" direction=\"in\" type=\"u\"/>"
266 "</method>"
267 "<method name=\"SetSurroundingTextPosition\">"
268 "<arg name=\"cursor\" direction=\"in\" type=\"u\"/>"
269 "<arg name=\"anchor\" direction=\"in\" type=\"u\"/>"
270 "</method>"
271 "<method name=\"DestroyIC\">"
272 "</method>"
273 "<method name=\"ProcessKeyEvent\">"
274 "<arg name=\"keyval\" direction=\"in\" type=\"u\"/>"
275 "<arg name=\"keycode\" direction=\"in\" type=\"u\"/>"
276 "<arg name=\"state\" direction=\"in\" type=\"u\"/>"
277 "<arg name=\"type\" direction=\"in\" type=\"i\"/>"
278 "<arg name=\"time\" direction=\"in\" type=\"u\"/>"
279 "<arg name=\"ret\" direction=\"out\" type=\"i\"/>"
280 "</method>"
281 "<signal name=\"EnableIM\">"
282 "</signal>"
283 "<signal name=\"CloseIM\">"
284 "</signal>"
285 "<signal name=\"CommitString\">"
286 "<arg name=\"str\" type=\"s\"/>"
287 "</signal>"
288 "<signal name=\"CurrentIM\">"
289 "<arg name=\"name\" type=\"s\"/>"
290 "<arg name=\"uniqueName\" type=\"s\"/>"
291 "<arg name=\"langCode\" type=\"s\"/>"
292 "</signal>"
293 "<signal name=\"UpdatePreedit\">"
294 "<arg name=\"str\" type=\"s\"/>"
295 "<arg name=\"cursorpos\" type=\"i\"/>"
296 "</signal>"
297 "<signal name=\"DeleteSurroundingText\">"
298 "<arg name=\"offset\" type=\"i\"/>"
299 "<arg name=\"nchar\" type=\"u\"/>"
300 "</signal>"
301 "<signal name=\"UpdateFormattedPreedit\">"
302 "<arg name=\"str\" type=\"a(si)\"/>"
303 "<arg name=\"cursorpos\" type=\"i\"/>"
304 "</signal>"
305 "<signal name=\"UpdateClientSideUI\">"
306 "<arg name=\"auxup\" type=\"s\"/>"
307 "<arg name=\"auxdown\" type=\"s\"/>"
308 "<arg name=\"preedit\" type=\"s\"/>"
309 "<arg name=\"candidateword\" type=\"s\"/>"
310 "<arg name=\"imname\" type=\"s\"/>"
311 "<arg name=\"cursorpos\" type=\"i\"/>"
312 "</signal>"
313 "<signal name=\"ForwardKey\">"
314 "<arg name=\"keyval\" type=\"u\"/>"
315 "<arg name=\"state\" type=\"u\"/>"
316 "<arg name=\"type\" type=\"i\"/>"
317 "</signal>"
318 "</interface>"
319 "</node>";
320
321 FCITX_DEFINE_PLUGIN(fcitx_ipc, frontend, FcitxFrontend) = {
322 IPCCreate,
323 IPCDestroy,
324 IPCCreateIC,
325 IPCCheckIC,
326 IPCDestroyIC,
327 IPCEnableIM,
328 IPCCloseIM,
329 IPCCommitString,
330 IPCForwardKey,
331 IPCSetWindowOffset,
332 IPCGetWindowRect,
333 IPCUpdatePreedit,
334 IPCUpdateClientSideUI,
335 NULL,
336 IPCCheckICFromSameApplication,
337 IPCGetPid,
338 IPCDeleteSurroundingText,
339 IPCGetSurroundingText
340 };
341
IPCCreate(FcitxInstance * instance,int frontendid)342 void* IPCCreate(FcitxInstance* instance, int frontendid)
343 {
344 FcitxIPCFrontend* ipc = fcitx_utils_malloc0(sizeof(FcitxIPCFrontend));
345 ipc->frontendid = frontendid;
346 ipc->owner = instance;
347
348 ipc->_conn = FcitxDBusGetConnection(instance);
349 ipc->_privconn = FcitxDBusGetPrivConnection(instance);
350
351 if (ipc->_conn == NULL && ipc->_privconn == NULL) {
352 FcitxLog(ERROR, "DBus Not initialized");
353 free(ipc);
354 return NULL;
355 }
356
357
358 DBusObjectPathVTable fcitxIPCVTable = {NULL, &IPCDBusEventHandler, NULL, NULL, NULL, NULL };
359
360 if (ipc->_conn) {
361 dbus_connection_register_object_path(ipc->_conn, FCITX_IM_DBUS_PATH, &fcitxIPCVTable, ipc);
362 }
363
364 if (ipc->_privconn) {
365 dbus_connection_register_object_path(ipc->_privconn, FCITX_IM_DBUS_PATH, &fcitxIPCVTable, ipc);
366 }
367
368 FcitxIMEventHook hook;
369 hook.arg = ipc;
370 hook.func = IPCUpdateIMList;
371 FcitxInstanceRegisterUpdateIMListHook(instance, hook);
372 hook.func = IPCUpdateCurrentIM;
373 FcitxInstanceRegisterIMChangedHook(instance, hook);
374 hook.func = IPCUpdateIMInfoForIC;
375 FcitxInstanceRegisterInputFocusHook(instance, hook);
376
377 return ipc;
378 }
379
IPCDestroy(void * arg)380 boolean IPCDestroy(void* arg)
381 {
382 FCITX_UNUSED(arg);
383 return true;
384 }
385
IPCCreateIC(void * arg,FcitxInputContext * context,void * priv)386 void IPCCreateIC(void* arg, FcitxInputContext* context, void* priv)
387 {
388 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
389 FcitxIPCIC* ipcic = fcitx_utils_new(FcitxIPCIC);
390 FcitxIPCCreateICPriv* ipcpriv = (FcitxIPCCreateICPriv*) priv;
391 DBusMessage* message = ipcpriv->message;
392 DBusMessage *reply = dbus_message_new_method_return(message);
393 FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(ipc->owner);
394
395 context->privateic = ipcic;
396
397 ipcic->id = ipc->maxid;
398 ipcic->sender = strdup(dbus_message_get_sender(message));
399 ipc->maxid ++;
400 ipcic->lastPreeditIsEmpty = false;
401 ipcic->isPriv = (ipcpriv->conn != ipc->_conn);
402 sprintf(ipcic->path, FCITX_IC_DBUS_PATH, ipcic->id);
403
404 uint32_t arg1, arg2, arg3, arg4;
405 arg1 = config->hkTrigger[0].sym;
406 arg2 = config->hkTrigger[0].state;
407 arg3 = config->hkTrigger[1].sym;
408 arg4 = config->hkTrigger[1].state;
409 if (dbus_message_is_method_call(message, FCITX_IM_DBUS_INTERFACE, "CreateIC")) {
410 /* CreateIC v1 indicates that default state can only be disabled */
411 context->state = IS_CLOSED;
412 context->contextCaps |= CAPACITY_CLIENT_SIDE_CONTROL_STATE;
413 dbus_message_append_args(reply,
414 DBUS_TYPE_INT32, &ipcic->id,
415 DBUS_TYPE_UINT32, &arg1,
416 DBUS_TYPE_UINT32, &arg2,
417 DBUS_TYPE_UINT32, &arg3,
418 DBUS_TYPE_UINT32, &arg4,
419 DBUS_TYPE_INVALID);
420 } else if (dbus_message_is_method_call(message, FCITX_IM_DBUS_INTERFACE, "CreateICv2")) {
421
422 DBusError error;
423 dbus_error_init(&error);
424 char* appname = NULL;
425 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &appname, DBUS_TYPE_INVALID))
426 appname = NULL;
427 else {
428 if (strlen(appname) == 0) {
429 appname = NULL;
430 } else {
431 appname = strdup(appname);
432 }
433 }
434 ((FcitxInputContext2*)context)->prgname = appname;
435
436 if (config->shareState == ShareState_PerProgram) {
437 FcitxInstanceSetICStateFromSameApplication(ipc->owner, ipc->frontendid, context);
438 }
439
440 boolean arg0 = context->state != IS_CLOSED;
441
442 dbus_error_free(&error);
443 dbus_message_append_args(reply,
444 DBUS_TYPE_INT32, &ipcic->id,
445 DBUS_TYPE_BOOLEAN, &arg0,
446 DBUS_TYPE_UINT32, &arg1,
447 DBUS_TYPE_UINT32, &arg2,
448 DBUS_TYPE_UINT32, &arg3,
449 DBUS_TYPE_UINT32, &arg4,
450 DBUS_TYPE_INVALID);
451 } else if (dbus_message_is_method_call(message, FCITX_IM_DBUS_INTERFACE, "CreateICv3")) {
452
453 DBusError error;
454 dbus_error_init(&error);
455 int icpid = 0;
456 char* appname = NULL;
457 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &appname, DBUS_TYPE_INT32, &icpid, DBUS_TYPE_INVALID))
458 appname = NULL;
459 else {
460 if (strlen(appname) == 0) {
461 appname = NULL;
462 } else {
463 appname = strdup(appname);
464 }
465 }
466 ipcic->pid = icpid;
467 ((FcitxInputContext2*)context)->prgname = appname;
468
469 if (config->shareState == ShareState_PerProgram) {
470 FcitxInstanceSetICStateFromSameApplication(ipc->owner, ipc->frontendid, context);
471 }
472
473 boolean arg0 = context->state != IS_CLOSED;
474
475 dbus_error_free(&error);
476 dbus_message_append_args(reply,
477 DBUS_TYPE_INT32, &ipcic->id,
478 DBUS_TYPE_BOOLEAN, &arg0,
479 DBUS_TYPE_UINT32, &arg1,
480 DBUS_TYPE_UINT32, &arg2,
481 DBUS_TYPE_UINT32, &arg3,
482 DBUS_TYPE_UINT32, &arg4,
483 DBUS_TYPE_INVALID);
484 }
485 dbus_connection_send(ipcpriv->conn, reply, NULL);
486 dbus_message_unref(reply);
487
488 DBusObjectPathVTable vtable = {NULL, &IPCICDBusEventHandler, NULL, NULL, NULL, NULL };
489 if (!ipcic->isPriv) {
490 if (ipc->_conn) {
491 dbus_connection_register_object_path(ipc->_conn, ipcic->path, &vtable, ipc);
492 dbus_connection_flush(ipc->_conn);
493 }
494 }
495 else {
496 if (ipc->_privconn) {
497 dbus_connection_register_object_path(ipc->_privconn, ipcic->path, &vtable, ipc);
498 dbus_connection_flush(ipc->_privconn);
499 }
500 }
501 }
502
IPCCheckIC(void * arg,FcitxInputContext * context,void * priv)503 boolean IPCCheckIC(void* arg, FcitxInputContext* context, void* priv)
504 {
505 FCITX_UNUSED(arg);
506 int *id = (int*)priv;
507 if (GetIPCIC(context)->id == *id)
508 return true;
509 return false;
510 }
511
IPCDestroyIC(void * arg,FcitxInputContext * context)512 void IPCDestroyIC(void* arg, FcitxInputContext* context)
513 {
514 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
515 FcitxIPCIC* ipcic = GetIPCIC(context);
516
517 if (!ipcic->isPriv) {
518 if (ipc->_conn)
519 dbus_connection_unregister_object_path(ipc->_conn, GetIPCIC(context)->path);
520 }
521 else {
522 if (ipc->_privconn)
523 dbus_connection_unregister_object_path(ipc->_privconn, GetIPCIC(context)->path);
524 }
525 fcitx_utils_free(ipcic->lastSentIMInfo.name);
526 fcitx_utils_free(ipcic->lastSentIMInfo.uniqueName);
527 fcitx_utils_free(ipcic->lastSentIMInfo.langCode);
528 fcitx_utils_free(ipcic->surroundingText);
529 fcitx_utils_free(ipcic->sender);
530 free(context->privateic);
531 context->privateic = NULL;
532 }
533
IPCSendSignal(FcitxIPCFrontend * ipc,FcitxIPCIC * ipcic,DBusMessage * msg)534 void IPCSendSignal(FcitxIPCFrontend* ipc, FcitxIPCIC* ipcic, DBusMessage* msg)
535 {
536 if (!ipcic || !ipcic->isPriv) {
537 if (ipc->_conn) {
538 dbus_connection_send(ipc->_conn, msg, NULL);
539 dbus_connection_flush(ipc->_conn);
540 }
541 }
542 if (!ipcic || ipcic->isPriv) {
543 if (ipc->_privconn) {
544 dbus_connection_send(ipc->_privconn, msg, NULL);
545 dbus_connection_flush(ipc->_privconn);
546 }
547 }
548 dbus_message_unref(msg);
549 }
550
IPCEnableIM(void * arg,FcitxInputContext * ic)551 void IPCEnableIM(void* arg, FcitxInputContext* ic)
552 {
553 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
554 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
555 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
556 "EnableIM"); // name of the signal
557
558 IPCSendSignal(ipc, GetIPCIC(ic), msg);
559 }
560
IPCCloseIM(void * arg,FcitxInputContext * ic)561 void IPCCloseIM(void* arg, FcitxInputContext* ic)
562 {
563 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
564 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
565 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
566 "CloseIM"); // name of the signal
567 IPCSendSignal(ipc, GetIPCIC(ic), msg);
568 }
569
IPCCommitString(void * arg,FcitxInputContext * ic,const char * str)570 void IPCCommitString(void* arg, FcitxInputContext* ic, const char* str)
571 {
572 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
573
574 if (!fcitx_utf8_check_string(str))
575 return;
576 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
577 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
578 "CommitString"); // name of the signal
579
580 dbus_message_append_args(msg, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID);
581 IPCSendSignal(ipc, GetIPCIC(ic), msg);
582 }
583
IPCForwardKey(void * arg,FcitxInputContext * ic,FcitxKeyEventType event,FcitxKeySym sym,unsigned int state)584 void IPCForwardKey(void* arg, FcitxInputContext* ic, FcitxKeyEventType event, FcitxKeySym sym, unsigned int state)
585 {
586 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
587 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
588 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
589 "ForwardKey"); // name of the signal
590
591 uint32_t keyval = (uint32_t) sym;
592 uint32_t keystate = (uint32_t) state;
593 int32_t type = (int) event;
594 dbus_message_append_args(msg, DBUS_TYPE_UINT32, &keyval, DBUS_TYPE_UINT32, &keystate, DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID);
595 IPCSendSignal(ipc, GetIPCIC(ic), msg);
596 }
597
IPCSetWindowOffset(void * arg,FcitxInputContext * ic,int x,int y)598 void IPCSetWindowOffset(void* arg, FcitxInputContext* ic, int x, int y)
599 {
600 FCITX_UNUSED(arg);
601 ic->offset_x = x;
602 ic->offset_y = y - GetIPCIC(ic)->height;
603 }
604
IPCGetWindowRect(void * arg,FcitxInputContext * ic,int * x,int * y,int * w,int * h)605 void IPCGetWindowRect(void* arg, FcitxInputContext* ic, int* x, int* y, int* w, int* h)
606 {
607 FCITX_UNUSED(arg);
608 *x = ic->offset_x;
609 *y = ic->offset_y;
610 *w = GetIPCIC(ic)->width;
611 *h = GetIPCIC(ic)->height;
612 }
613
IPCDBusEventHandler(DBusConnection * connection,DBusMessage * msg,void * user_data)614 static DBusHandlerResult IPCDBusEventHandler(DBusConnection *connection, DBusMessage *msg, void *user_data)
615 {
616 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) user_data;
617 FcitxInstance* instance = ipc->owner;
618 DBusMessage* reply = NULL;
619 boolean flush = true;
620 DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
621
622 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) {
623 reply = dbus_message_new_method_return(msg);
624
625 dbus_message_append_args(reply, DBUS_TYPE_STRING, &im_introspection_xml, DBUS_TYPE_INVALID);
626 } else if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "Get")) {
627 reply = FcitxDBusPropertyGet(ipc, propertTable, msg);
628 } else if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "Set")) {
629 reply = FcitxDBusPropertySet(ipc, propertTable, msg);
630 } else if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "GetAll")) {
631 reply = FcitxDBusPropertyGetAll(ipc, propertTable, msg);
632 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "CreateIC")
633 || dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "CreateICv2")
634 || dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "CreateICv3")
635 ) {
636 /* we have no choice here, so just return */
637 FcitxIPCCreateICPriv ipcpriv;
638 ipcpriv.message = msg;
639 ipcpriv.conn = connection;
640 FcitxInstanceCreateIC(ipc->owner, ipc->frontendid, &ipcpriv);
641 return DBUS_HANDLER_RESULT_HANDLED;
642 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "Exit")) {
643 FcitxLog(INFO, "Receive message ask for quit");
644 reply = dbus_message_new_method_return(msg);
645 dbus_connection_send(connection, reply, NULL);
646 dbus_message_unref(reply);
647 dbus_connection_flush(connection);
648 FcitxInstanceEnd(instance);
649 return DBUS_HANDLER_RESULT_HANDLED;
650 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "GetCurrentIM")) {
651 reply = dbus_message_new_method_return(msg);
652 FcitxIM* im = FcitxInstanceGetCurrentIM(ipc->owner);
653 const char* name = "";
654 if (im) {
655 name = im->uniqueName;
656 }
657 dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
658 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "SetCurrentIM")) {
659 DBusError error;
660 dbus_error_init(&error);
661 char* imname = NULL;
662 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &imname, DBUS_TYPE_INVALID)) {
663 FcitxInstanceSwitchIMByName(instance, imname);
664 reply = dbus_message_new_method_return(msg);
665 } else {
666 reply = FcitxDBusPropertyUnknownMethod(msg);
667 }
668 dbus_error_free(&error);
669 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "GetIMAddon")) {
670 DBusError error;
671 dbus_error_init(&error);
672 char* imname = NULL;
673 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &imname, DBUS_TYPE_INVALID)) {
674 FcitxIM* im = FcitxInstanceGetIMFromIMList(instance, IMAS_Disable, imname);
675 const char* name = "";
676 if (im && im->owner)
677 name = im->owner->name;
678 reply = dbus_message_new_method_return(msg);
679 dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
680 } else {
681 reply = FcitxDBusPropertyUnknownMethod(msg);
682 }
683 dbus_error_free(&error);
684 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "GetCurrentUI")) {
685 const char* name = "";
686 FcitxAddon* uiaddon = FcitxInstanceGetCurrentUI(instance);
687 if (uiaddon) {
688 name = uiaddon->name;
689 }
690 reply = dbus_message_new_method_return(msg);
691 dbus_message_append_args(reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
692 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "Configure")) {
693 reply = dbus_message_new_method_return(msg);
694 fcitx_utils_launch_configure_tool();
695 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "ActivateIM")) {
696 FcitxInstanceEnableIM(ipc->owner, FcitxInstanceGetCurrentIC(ipc->owner), false);
697 reply = dbus_message_new_method_return(msg);
698 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "InactivateIM")) {
699 FcitxInstanceCloseIM(ipc->owner, FcitxInstanceGetCurrentIC(ipc->owner));
700 reply = dbus_message_new_method_return(msg);
701 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "ToggleIM")) {
702 FcitxInstanceChangeIMState(ipc->owner, FcitxInstanceGetCurrentIC(ipc->owner));
703 reply = dbus_message_new_method_return(msg);
704 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "ResetIMList")) {
705 FcitxProfile* profile = FcitxInstanceGetProfile(instance);
706 if (profile->imList)
707 free(profile->imList);
708 profile->imList = strdup("");;
709 FcitxInstanceUpdateIMList(instance);
710 reply = dbus_message_new_method_return(msg);
711 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "GetCurrentState")) {
712 int r = FcitxInstanceGetCurrentState(ipc->owner);
713 reply = dbus_message_new_method_return(msg);
714 dbus_message_append_args(reply,
715 DBUS_TYPE_INT32, &r,
716 DBUS_TYPE_INVALID);
717 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "ConfigureAddon")) {
718 DBusError error;
719 dbus_error_init(&error);
720 char* addonname = NULL;
721 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &addonname, DBUS_TYPE_INVALID)) {
722 if (addonname) {
723 fcitx_utils_launch_configure_tool_for_addon(addonname);
724 }
725 reply = dbus_message_new_method_return(msg);
726 } else {
727 reply = FcitxDBusPropertyUnknownMethod(msg);
728 }
729 dbus_error_free(&error);
730 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "ConfigureIM")) {
731 DBusError error;
732 dbus_error_init(&error);
733 char* imname = NULL;
734 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &imname, DBUS_TYPE_INVALID)) {
735 if (imname) {
736 fcitx_utils_launch_configure_tool_for_addon(imname);
737 }
738 reply = dbus_message_new_method_return(msg);
739 } else {
740 reply = FcitxDBusPropertyUnknownMethod(msg);
741 }
742 dbus_error_free(&error);
743 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "ReloadAddonConfig")) {
744 DBusError error;
745 dbus_error_init(&error);
746 char* addonname = NULL;
747 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &addonname, DBUS_TYPE_INVALID)) {
748 if (addonname) {
749 FcitxInstanceReloadAddonConfig(instance, addonname);
750 }
751 reply = dbus_message_new_method_return(msg);
752 } else {
753 reply = FcitxDBusPropertyUnknownMethod(msg);
754 }
755 dbus_error_free(&error);
756 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "ReloadConfig")) {
757 FcitxInstanceReloadConfig(instance);
758 reply = dbus_message_new_method_return(msg);
759 flush = true;
760 } else if (dbus_message_is_method_call(msg, FCITX_IM_DBUS_INTERFACE, "Restart")) {
761 FcitxInstanceRestart(instance);
762 reply = dbus_message_new_method_return(msg);
763 flush = true;
764 }
765
766 if (reply) {
767 dbus_connection_send(connection, reply, NULL);
768 dbus_message_unref(reply);
769 if (flush) {
770 dbus_connection_flush(connection);
771 }
772 result = DBUS_HANDLER_RESULT_HANDLED;
773 }
774
775 return result;
776 }
777
778
IPCICDBusEventHandler(DBusConnection * connection,DBusMessage * msg,void * user_data)779 static DBusHandlerResult IPCICDBusEventHandler(DBusConnection *connection, DBusMessage *msg, void *user_data)
780 {
781 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) user_data;
782 int id = -1;
783 sscanf(dbus_message_get_path(msg), FCITX_IC_DBUS_PATH, &id);
784 FcitxInputContext* ic = FcitxInstanceFindIC(ipc->owner, ipc->frontendid, &id);
785 DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
786 DBusMessage *reply = NULL;
787 boolean flush = false;
788
789 if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) {
790 reply = dbus_message_new_method_return(msg);
791 dbus_message_append_args(reply, DBUS_TYPE_STRING, &ic_introspection_xml, DBUS_TYPE_INVALID);
792 }
793
794 /* ic is not NULL */
795 if (!reply && ic) {
796 DBusError error;
797 dbus_error_init(&error);
798 if (strcmp(dbus_message_get_sender(msg), GetIPCIC(ic)->sender) != 0) {
799 reply = dbus_message_new_error(msg, "org.fcitx.Fcitx.Error", "Invalid sender");
800 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "EnableIC")) {
801 FcitxInstanceEnableIM(ipc->owner, ic, false);
802 reply = dbus_message_new_method_return(msg);
803 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "CloseIC")) {
804 FcitxInstanceCloseIM(ipc->owner, ic);
805 reply = dbus_message_new_method_return(msg);
806 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "FocusIn")) {
807 IPCICFocusIn(ipc, ic);
808 reply = dbus_message_new_method_return(msg);
809 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "FocusOut")) {
810 IPCICFocusOut(ipc, ic);
811 reply = dbus_message_new_method_return(msg);
812 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "Reset")) {
813 IPCICReset(ipc, ic);
814 reply = dbus_message_new_method_return(msg);
815 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "MouseEvent")) {
816 reply = dbus_message_new_method_return(msg);
817 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "SetCursorLocation")) {
818 int x, y;
819 if (dbus_message_get_args(msg, &error, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INVALID)) {
820 IPCICSetCursorRect(ipc, ic, x, y, 0, 0);
821 reply = dbus_message_new_method_return(msg);
822 } else {
823 reply = FcitxDBusPropertyUnknownMethod(msg);
824 }
825 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "SetCursorRect")) {
826 int x, y, w, h;
827 if (dbus_message_get_args(msg, &error,
828 DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
829 DBUS_TYPE_INT32, &w, DBUS_TYPE_INT32, &h,
830 DBUS_TYPE_INVALID)) {
831 IPCICSetCursorRect(ipc, ic, x, y, w, h);
832 reply = dbus_message_new_method_return(msg);
833 } else {
834 reply = FcitxDBusPropertyUnknownMethod(msg);
835 }
836 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "SetCapacity")) {
837 uint32_t flags;
838 if (dbus_message_get_args(msg, &error, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID)) {
839 ic->contextCaps = flags;
840 if (!(ic->contextCaps & CAPACITY_SURROUNDING_TEXT)) {
841 if (GetIPCIC(ic)->surroundingText)
842 free(GetIPCIC(ic)->surroundingText);
843 GetIPCIC(ic)->surroundingText = NULL;
844 }
845 if (ic->contextCaps & CAPACITY_GET_IM_INFO_ON_FOCUS) {
846 IPCUpdateIMInfoForIC(ipc);
847 }
848 reply = dbus_message_new_method_return(msg);
849 } else {
850 reply = FcitxDBusPropertyUnknownMethod(msg);
851 }
852 result = DBUS_HANDLER_RESULT_HANDLED;
853 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "SetSurroundingText")) {
854 char* text;
855 uint32_t cursor, anchor;
856 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &text, DBUS_TYPE_UINT32, &cursor, DBUS_TYPE_UINT32, &anchor, DBUS_TYPE_INVALID)) {
857 FcitxIPCIC* ipcic = GetIPCIC(ic);
858 if (!ipcic->surroundingText || strcmp(ipcic->surroundingText, text) != 0 || cursor != ipcic->cursor || anchor != ipcic->anchor)
859 {
860 fcitx_utils_free(ipcic->surroundingText);
861 ipcic->surroundingText = strdup(text);
862 ipcic->cursor = cursor;
863 ipcic->anchor = anchor;
864 FcitxInstanceNotifyUpdateSurroundingText(ipc->owner, ic);
865 }
866 reply = dbus_message_new_method_return(msg);
867 } else {
868 reply = FcitxDBusPropertyUnknownMethod(msg);
869 }
870 result = DBUS_HANDLER_RESULT_HANDLED;
871 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "SetSurroundingTextPosition")) {
872 uint32_t cursor, anchor;
873 if (dbus_message_get_args(msg, &error, DBUS_TYPE_UINT32, &cursor, DBUS_TYPE_UINT32, &anchor, DBUS_TYPE_INVALID)) {
874 FcitxIPCIC* ipcic = GetIPCIC(ic);
875 if (cursor != ipcic->cursor || anchor != ipcic->anchor)
876 {
877 ipcic->cursor = cursor;
878 ipcic->anchor = anchor;
879 FcitxInstanceNotifyUpdateSurroundingText(ipc->owner, ic);
880 }
881 reply = dbus_message_new_method_return(msg);
882 } else {
883 reply = FcitxDBusPropertyUnknownMethod(msg);
884 }
885 result = DBUS_HANDLER_RESULT_HANDLED;
886 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "DestroyIC")) {
887 FcitxInstanceDestroyIC(ipc->owner, ipc->frontendid, &id);
888 reply = dbus_message_new_method_return(msg);
889 result = DBUS_HANDLER_RESULT_HANDLED;
890 } else if (dbus_message_is_method_call(msg, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent")) {
891 uint32_t keyval, keycode, state, t;
892 int ret, itype;
893 FcitxKeyEventType type;
894 if (dbus_message_get_args(msg, &error,
895 DBUS_TYPE_UINT32, &keyval,
896 DBUS_TYPE_UINT32, &keycode,
897 DBUS_TYPE_UINT32, &state,
898 DBUS_TYPE_INT32, &itype,
899 DBUS_TYPE_UINT32, &t,
900 DBUS_TYPE_INVALID)) {
901 type = itype;
902 ret = IPCProcessKey(ipc, ic, keyval, keycode, state, t, type);
903
904 reply = dbus_message_new_method_return(msg);
905
906 dbus_message_append_args(reply, DBUS_TYPE_INT32, &ret, DBUS_TYPE_INVALID);
907 flush = true;
908 } else {
909 reply = FcitxDBusPropertyUnknownMethod(msg);
910 }
911 }
912 dbus_error_free(&error);
913 }
914
915 if (reply) {
916 dbus_connection_send(connection, reply, NULL);
917 dbus_message_unref(reply);
918 if (flush) {
919 dbus_connection_flush(connection);
920 }
921 result = DBUS_HANDLER_RESULT_HANDLED;
922 }
923
924 return result;
925 }
926
IPCProcessKey(FcitxIPCFrontend * ipc,FcitxInputContext * callic,const uint32_t originsym,const uint32_t keycode,const uint32_t originstate,uint32_t t,FcitxKeyEventType type)927 static int IPCProcessKey(FcitxIPCFrontend* ipc, FcitxInputContext* callic, const uint32_t originsym, const uint32_t keycode, const uint32_t originstate, uint32_t t, FcitxKeyEventType type)
928 {
929 FcitxInputContext* ic = FcitxInstanceGetCurrentIC(ipc->owner);
930 FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(ipc->owner);
931 FcitxInputState* input = FcitxInstanceGetInputState(ipc->owner);
932
933 if (ic == NULL || ic->frontendid != callic->frontendid || GetIPCIC(ic)->id != GetIPCIC(callic)->id) {
934 FcitxInstanceSetCurrentIC(ipc->owner, callic);
935 FcitxUIOnInputFocus(ipc->owner);
936 }
937 ic = callic;
938 FcitxKeySym sym;
939 unsigned int state;
940
941 state = originstate & FcitxKeyState_SimpleMask;
942 state &= FcitxKeyState_UsedMask;
943 FcitxHotkeyGetKey(originsym, state, &sym, &state);
944 FcitxLog(DEBUG,
945 "KeyRelease=%d state=%d KEYCODE=%d KEYSYM=%u ",
946 (type == FCITX_RELEASE_KEY), state, keycode, sym);
947
948 if (originsym == 0)
949 return 0;
950
951 if (ic->state == IS_CLOSED && type == FCITX_PRESS_KEY && FcitxHotkeyIsHotKey(sym, state, config->hkTrigger)) {
952 FcitxInstanceEnableIM(ipc->owner, ic, false);
953 return 1;
954 }
955 else if (ic->state == IS_CLOSED) {
956 return 0;
957 }
958
959 FcitxInputStateSetKeyCode(input, keycode);
960 FcitxInputStateSetKeySym(input, originsym);
961 FcitxInputStateSetKeyState(input, originstate);
962 INPUT_RETURN_VALUE retVal = FcitxInstanceProcessKey(ipc->owner, type,
963 t,
964 sym, state);
965 FcitxInputStateSetKeyCode(input, 0);
966 FcitxInputStateSetKeySym(input, 0);
967 FcitxInputStateSetKeyState(input, 0);
968
969 if (retVal & IRV_FLAG_FORWARD_KEY || retVal == IRV_TO_PROCESS)
970 return 0;
971 else
972 return 1;
973 }
974
IPCICFocusIn(FcitxIPCFrontend * ipc,FcitxInputContext * ic)975 static void IPCICFocusIn(FcitxIPCFrontend* ipc, FcitxInputContext* ic)
976 {
977 if (ic == NULL)
978 return;
979
980 FcitxInputContext* oldic = FcitxInstanceGetCurrentIC(ipc->owner);
981
982 if (oldic && oldic != ic)
983 FcitxUICommitPreedit(ipc->owner);
984
985 if (!FcitxInstanceSetCurrentIC(ipc->owner, ic))
986 return;
987
988
989 if (ic) {
990 FcitxUIOnInputFocus(ipc->owner);
991 } else {
992 FcitxUICloseInputWindow(ipc->owner);
993 FcitxUIMoveInputWindow(ipc->owner);
994 }
995
996 return;
997 }
998
IPCICFocusOut(FcitxIPCFrontend * ipc,FcitxInputContext * ic)999 static void IPCICFocusOut(FcitxIPCFrontend* ipc, FcitxInputContext* ic)
1000 {
1001 FcitxInputContext* currentic = FcitxInstanceGetCurrentIC(ipc->owner);
1002 if (ic && ic == currentic) {
1003 FcitxUICommitPreedit(ipc->owner);
1004 FcitxUICloseInputWindow(ipc->owner);
1005 FcitxInstanceSetCurrentIC(ipc->owner, NULL);
1006 FcitxUIOnInputUnFocus(ipc->owner);
1007 }
1008
1009 return;
1010 }
1011
IPCICReset(FcitxIPCFrontend * ipc,FcitxInputContext * ic)1012 static void IPCICReset(FcitxIPCFrontend* ipc, FcitxInputContext* ic)
1013 {
1014 FcitxInputContext* currentic = FcitxInstanceGetCurrentIC(ipc->owner);
1015 if (ic && ic == currentic) {
1016 FcitxUICloseInputWindow(ipc->owner);
1017 FcitxInstanceResetInput(ipc->owner);
1018 }
1019
1020 return;
1021 }
1022
IPCICSetCursorRect(FcitxIPCFrontend * ipc,FcitxInputContext * ic,int x,int y,int w,int h)1023 static void IPCICSetCursorRect(FcitxIPCFrontend* ipc, FcitxInputContext* ic, int x, int y, int w, int h)
1024 {
1025 ic->offset_x = x;
1026 ic->offset_y = y;
1027 GetIPCIC(ic)->width = w;
1028 GetIPCIC(ic)->height = h;
1029 FcitxUIMoveInputWindow(ipc->owner);
1030
1031 return;
1032 }
1033
IPCUpdatePreedit(void * arg,FcitxInputContext * ic)1034 void IPCUpdatePreedit(void* arg, FcitxInputContext* ic)
1035 {
1036 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1037 FcitxInputState* input = FcitxInstanceGetInputState(ipc->owner);
1038 FcitxMessages* clientPreedit = FcitxInputStateGetClientPreedit(input);
1039 int i = 0;
1040 for (i = 0; i < FcitxMessagesGetMessageCount(clientPreedit) ; i ++) {
1041 char* str = FcitxMessagesGetMessageString(clientPreedit, i);
1042 if (!fcitx_utf8_check_string(str))
1043 return;
1044 }
1045
1046 /* a small optimization, don't need to update empty preedit */
1047 FcitxIPCIC* ipcic = GetIPCIC(ic);
1048 if (ipcic->lastPreeditIsEmpty && FcitxMessagesGetMessageCount(clientPreedit) == 0)
1049 return;
1050
1051 ipcic->lastPreeditIsEmpty = (FcitxMessagesGetMessageCount(clientPreedit) == 0);
1052
1053 if (ic->contextCaps & CAPACITY_FORMATTED_PREEDIT) {
1054 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
1055 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
1056 "UpdateFormattedPreedit"); // name of the signal
1057
1058 DBusMessageIter args, array, sub;
1059 dbus_message_iter_init_append(msg, &args);
1060 dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "(si)", &array);
1061 int i = 0;
1062 for (i = 0; i < FcitxMessagesGetMessageCount(clientPreedit) ; i ++) {
1063 dbus_message_iter_open_container(&array, DBUS_TYPE_STRUCT, 0, &sub);
1064 char* str = FcitxMessagesGetMessageString(clientPreedit, i);
1065 char* needtofree = FcitxInstanceProcessOutputFilter(ipc->owner, str);
1066 if (needtofree) {
1067 str = needtofree;
1068 }
1069 int type = FcitxMessagesGetClientMessageType(clientPreedit, i);
1070 dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &str);
1071 dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &type);
1072 dbus_message_iter_close_container(&array, &sub);
1073 if (needtofree)
1074 free(needtofree);
1075 }
1076 dbus_message_iter_close_container(&args, &array);
1077
1078 int iCursorPos = FcitxInputStateGetClientCursorPos(input);
1079 dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &iCursorPos);
1080
1081 IPCSendSignal(ipc, GetIPCIC(ic), msg);
1082 }
1083 else {
1084 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1085 FcitxInputState* input = FcitxInstanceGetInputState(ipc->owner);
1086 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
1087 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
1088 "UpdatePreedit"); // name of the signal
1089
1090 char* strPreedit = FcitxUIMessagesToCString(FcitxInputStateGetClientPreedit(input));
1091 char* str = FcitxInstanceProcessOutputFilter(ipc->owner, strPreedit);
1092 if (str) {
1093 free(strPreedit);
1094 strPreedit = str;
1095 }
1096
1097 int iCursorPos = FcitxInputStateGetClientCursorPos(input);
1098
1099 dbus_message_append_args(msg, DBUS_TYPE_STRING, &strPreedit, DBUS_TYPE_INT32, &iCursorPos, DBUS_TYPE_INVALID);
1100
1101 IPCSendSignal(ipc, GetIPCIC(ic), msg);
1102 free(strPreedit);
1103 }
1104 }
1105
IPCDeleteSurroundingText(void * arg,FcitxInputContext * ic,int offset,unsigned int size)1106 void IPCDeleteSurroundingText(void* arg, FcitxInputContext* ic, int offset, unsigned int size)
1107 {
1108 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1109 FcitxIPCIC* ipcic = GetIPCIC(ic);
1110
1111 /*
1112 * do the real deletion here, and client might update it, but input method itself
1113 * would expect a up to date value after this call.
1114 *
1115 * Make their life easier.
1116 */
1117 if (ipcic->surroundingText) {
1118 int cursor_pos = ipcic->cursor + offset;
1119 size_t len = fcitx_utf8_strlen (ipcic->surroundingText);
1120 if (cursor_pos >= 0 && len - cursor_pos >= size) {
1121 /*
1122 * the original size must be larger, so we can do in-place copy here
1123 * without alloc new string
1124 */
1125 char* start = fcitx_utf8_get_nth_char(ipcic->surroundingText, cursor_pos);
1126 char* end = fcitx_utf8_get_nth_char(start, size);
1127
1128 int copylen = strlen(end);
1129
1130 memmove (start, end, sizeof(char) * copylen);
1131 start[copylen] = 0;
1132 ipcic->cursor = cursor_pos;
1133 } else {
1134 ipcic->surroundingText[0] = '\0';
1135 ipcic->cursor = 0;
1136 }
1137 ipcic->anchor = ipcic->cursor;
1138 }
1139
1140
1141 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
1142 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
1143 "DeleteSurroundingText"); // name of the signal
1144
1145 dbus_message_append_args(msg, DBUS_TYPE_INT32, &offset, DBUS_TYPE_UINT32, &size, DBUS_TYPE_INVALID);
1146
1147 IPCSendSignal(ipc, GetIPCIC(ic), msg);
1148 }
1149
1150
IPCGetSurroundingText(void * arg,FcitxInputContext * ic,char ** str,unsigned int * cursor,unsigned int * anchor)1151 boolean IPCGetSurroundingText(void* arg, FcitxInputContext* ic, char** str, unsigned int *cursor, unsigned int *anchor)
1152 {
1153 FCITX_UNUSED(arg);
1154 FcitxIPCIC* ipcic = GetIPCIC(ic);
1155
1156 if (!ipcic->surroundingText)
1157 return false;
1158
1159 if (str)
1160 *str = strdup(ipcic->surroundingText);
1161
1162 if (cursor)
1163 *cursor = ipcic->cursor;
1164
1165 if (anchor)
1166 *anchor = ipcic->anchor;
1167
1168 return true;
1169 }
1170
1171
IPCUpdateClientSideUI(void * arg,FcitxInputContext * ic)1172 void IPCUpdateClientSideUI(void* arg, FcitxInputContext* ic)
1173 {
1174 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1175 FcitxInputState* input = FcitxInstanceGetInputState(ipc->owner);
1176 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
1177 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
1178 "UpdateClientSideUI"); // name of the signal
1179
1180 char *str;
1181 char* strAuxUp = FcitxUIMessagesToCString(FcitxInputStateGetAuxUp(input));
1182 str = FcitxInstanceProcessOutputFilter(ipc->owner, strAuxUp);
1183 if (str) {
1184 free(strAuxUp);
1185 strAuxUp = str;
1186 }
1187 char* strAuxDown = FcitxUIMessagesToCString(FcitxInputStateGetAuxDown(input));
1188 str = FcitxInstanceProcessOutputFilter(ipc->owner, strAuxDown);
1189 if (str) {
1190 free(strAuxDown);
1191 strAuxDown = str;
1192 }
1193 char* strPreedit = FcitxUIMessagesToCString(FcitxInputStateGetPreedit(input));
1194 str = FcitxInstanceProcessOutputFilter(ipc->owner, strPreedit);
1195 if (str) {
1196 free(strPreedit);
1197 strPreedit = str;
1198 }
1199 char* candidateword = FcitxUICandidateWordToCString(ipc->owner);
1200 str = FcitxInstanceProcessOutputFilter(ipc->owner, candidateword);
1201 if (str) {
1202 free(candidateword);
1203 candidateword = str;
1204 }
1205 FcitxIM* im = FcitxInstanceGetCurrentIM(ipc->owner);
1206 char* imname = NULL;
1207 if (im == NULL)
1208 imname = "En";
1209 else
1210 imname = im->strName;
1211
1212 int iCursorPos = FcitxInputStateGetCursorPos(input);
1213
1214 dbus_message_append_args(msg,
1215 DBUS_TYPE_STRING, &strAuxUp,
1216 DBUS_TYPE_STRING, &strAuxDown,
1217 DBUS_TYPE_STRING, &strPreedit,
1218 DBUS_TYPE_STRING, &candidateword,
1219 DBUS_TYPE_STRING, &imname,
1220 DBUS_TYPE_INT32, &iCursorPos,
1221 DBUS_TYPE_INVALID);
1222
1223 IPCSendSignal(ipc, GetIPCIC(ic), msg);
1224 free(strAuxUp);
1225 free(strAuxDown);
1226 free(strPreedit);
1227 free(candidateword);
1228 }
1229
IPCCheckICFromSameApplication(void * arg,FcitxInputContext * icToCheck,FcitxInputContext * ic)1230 boolean IPCCheckICFromSameApplication(void* arg, FcitxInputContext* icToCheck, FcitxInputContext* ic)
1231 {
1232 FCITX_UNUSED(arg);
1233 FcitxInputContext2* ic2ToCheck = (FcitxInputContext2*)icToCheck;
1234 FcitxInputContext2* ic2 = (FcitxInputContext2*)ic;
1235 if (ic2->prgname == NULL || ic2ToCheck->prgname == NULL)
1236 return false;
1237 return strcmp(ic2ToCheck->prgname, ic2->prgname) == 0;
1238 }
1239
IPCEmitPropertiesChanged(void * arg,const char * const * properties)1240 void IPCEmitPropertiesChanged(void* arg, const char* const* properties)
1241 {
1242 if (!properties || !*properties)
1243 return;
1244
1245 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1246 DBusMessage* msg = dbus_message_new_signal(FCITX_IM_DBUS_PATH, // object name of the signal
1247 DBUS_INTERFACE_PROPERTIES, // interface name of the signal
1248 "PropertiesChanged"); // name of the signal
1249
1250 DBusMessageIter args;
1251 DBusMessageIter changed_properties, invalidated_properties;
1252 char sinterface[] = FCITX_IM_DBUS_INTERFACE;
1253 char* interface = sinterface;
1254 dbus_message_iter_init_append(msg, &args);
1255 dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &interface);
1256
1257 dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &changed_properties);
1258 dbus_message_iter_close_container(&args, &changed_properties);
1259
1260 dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &invalidated_properties);
1261 for (; *properties; properties++)
1262 dbus_message_iter_append_basic(&invalidated_properties, DBUS_TYPE_STRING, properties);
1263 dbus_message_iter_close_container(&args, &invalidated_properties);
1264
1265 IPCSendSignal(ipc, NULL, msg);
1266 }
1267
IPCEmitPropertyChanged(void * arg,const char * property)1268 void IPCEmitPropertyChanged(void* arg, const char* property)
1269 {
1270 const char* properties[] = { property, NULL };
1271 IPCEmitPropertiesChanged(arg, properties);
1272 }
1273
IPCGetPropertyIMList(void * arg,DBusMessageIter * args)1274 void IPCGetPropertyIMList(void* arg, DBusMessageIter* args)
1275 {
1276 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1277 FcitxInstance* instance = ipc->owner;
1278 DBusMessageIter sub, ssub;
1279 dbus_message_iter_open_container(args, DBUS_TYPE_ARRAY, "(sssb)", &sub);
1280 FcitxIM* ime;
1281 UT_array* imes = FcitxInstanceGetIMEs(instance);
1282 for (ime = (FcitxIM*) utarray_front(imes);
1283 ime != NULL;
1284 ime = (FcitxIM*) utarray_next(imes, ime)) {
1285 dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, 0, &ssub);
1286 boolean enable = true;
1287 char* name = ime->strName;
1288 char* uniqueName = ime->uniqueName;
1289 char* langCode = ime->langCode;
1290 dbus_message_iter_append_basic(&ssub, DBUS_TYPE_STRING, &name);
1291 dbus_message_iter_append_basic(&ssub, DBUS_TYPE_STRING, &uniqueName);
1292 dbus_message_iter_append_basic(&ssub, DBUS_TYPE_STRING, &langCode);
1293 dbus_message_iter_append_basic(&ssub, DBUS_TYPE_BOOLEAN, &enable);
1294 dbus_message_iter_close_container(&sub, &ssub);
1295 }
1296
1297 UT_array* availimes = FcitxInstanceGetAvailIMEs(instance);
1298 for (ime = (FcitxIM*) utarray_front(availimes);
1299 ime != NULL;
1300 ime = (FcitxIM*) utarray_next(availimes, ime)) {
1301 if (!FcitxInstanceGetIMFromIMList(instance, IMAS_Enable, ime->uniqueName)) {
1302 dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, 0, &ssub);
1303 boolean enable = false;
1304 char* name = ime->strName;
1305 char* uniqueName = ime->uniqueName;
1306 char* langCode = ime->langCode;
1307 dbus_message_iter_append_basic(&ssub, DBUS_TYPE_STRING, &name);
1308 dbus_message_iter_append_basic(&ssub, DBUS_TYPE_STRING, &uniqueName);
1309 dbus_message_iter_append_basic(&ssub, DBUS_TYPE_STRING, &langCode);
1310 dbus_message_iter_append_basic(&ssub, DBUS_TYPE_BOOLEAN, &enable);
1311 dbus_message_iter_close_container(&sub, &ssub);
1312 }
1313 }
1314 dbus_message_iter_close_container(args, &sub);
1315 }
1316
IPCSetPropertyIMList(void * arg,DBusMessageIter * args)1317 void IPCSetPropertyIMList(void* arg, DBusMessageIter* args)
1318 {
1319 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1320 FcitxInstance* instance = ipc->owner;
1321 DBusMessageIter sub, ssub;
1322
1323 if (dbus_message_iter_get_arg_type(args) != DBUS_TYPE_ARRAY)
1324 return;
1325
1326 dbus_message_iter_recurse(args, &sub);
1327
1328 char* result = NULL;
1329 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1330 dbus_message_iter_recurse(&sub, &ssub);
1331 char* name, *uniqueName, *langCode;
1332 boolean enable;
1333 if (dbus_message_iter_get_arg_type(&ssub) != DBUS_TYPE_STRING)
1334 goto ipc_set_imlist_end;
1335 dbus_message_iter_get_basic(&ssub, &name);
1336 dbus_message_iter_next(&ssub);
1337
1338 if (dbus_message_iter_get_arg_type(&ssub) != DBUS_TYPE_STRING)
1339 goto ipc_set_imlist_end;
1340 dbus_message_iter_get_basic(&ssub, &uniqueName);
1341 dbus_message_iter_next(&ssub);
1342
1343 if (dbus_message_iter_get_arg_type(&ssub) != DBUS_TYPE_STRING)
1344 goto ipc_set_imlist_end;
1345 dbus_message_iter_get_basic(&ssub, &langCode);
1346 dbus_message_iter_next(&ssub);
1347
1348 if (dbus_message_iter_get_arg_type(&ssub) != DBUS_TYPE_BOOLEAN)
1349 goto ipc_set_imlist_end;
1350 dbus_message_iter_get_basic(&ssub, &enable);
1351 dbus_message_iter_next(&ssub);
1352
1353 char* newresult;
1354 if (!result) {
1355 fcitx_utils_alloc_cat_str(newresult, uniqueName, ":",
1356 enable ? "True" : "False");
1357 } else {
1358 fcitx_utils_alloc_cat_str(newresult, result, ",", uniqueName, ":",
1359 enable ? "True" : "False");
1360 }
1361 if (result)
1362 free(result);
1363 result = newresult;
1364 ipc_set_imlist_end:
1365 dbus_message_iter_next(&sub);
1366 }
1367
1368 FcitxLog(DEBUG, "%s", result);
1369 if (result) {
1370 FcitxProfile* profile = FcitxInstanceGetProfile(instance);
1371 if (profile->imList)
1372 free(profile->imList);
1373 profile->imList = result;
1374 FcitxInstanceUpdateIMList(instance);
1375 }
1376 }
1377
IPCUpdateIMList(void * arg)1378 void IPCUpdateIMList(void* arg)
1379 {
1380 IPCEmitPropertyChanged(arg, "IMList");
1381 }
1382
IPCGetPropertyCurrentIM(void * arg,DBusMessageIter * args)1383 void IPCGetPropertyCurrentIM(void* arg, DBusMessageIter* args)
1384 {
1385 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1386 FcitxInstance* instance = ipc->owner;
1387 FcitxIM* im = FcitxInstanceGetCurrentIM(instance);
1388 const char* currentIM = im && im->uniqueName ? im->uniqueName : "";
1389
1390 dbus_message_iter_append_basic(args, DBUS_TYPE_STRING, ¤tIM);
1391 }
1392
IPCSetPropertyCurrentIM(void * arg,DBusMessageIter * args)1393 void IPCSetPropertyCurrentIM(void* arg, DBusMessageIter* args)
1394 {
1395 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1396 FcitxInstance* instance = ipc->owner;
1397 const char* currentIM;
1398
1399 if (dbus_message_iter_get_arg_type(args) != DBUS_TYPE_STRING)
1400 return;
1401
1402 dbus_message_iter_get_basic(args, ¤tIM);
1403 FcitxInstanceSwitchIMByName(instance, currentIM);
1404 }
1405
IPCUpdateCurrentIM(void * arg)1406 void IPCUpdateCurrentIM(void* arg)
1407 {
1408 IPCEmitPropertyChanged(arg, "CurrentIM");
1409 IPCUpdateIMInfoForIC(arg);
1410 }
1411
IPCUpdateIMInfoForIC(void * arg)1412 void IPCUpdateIMInfoForIC(void* arg)
1413 {
1414 FcitxIPCFrontend* ipc = (FcitxIPCFrontend*) arg;
1415 FcitxInputContext* ic = FcitxInstanceGetCurrentIC(ipc->owner);
1416 if (ic && (ic->contextCaps & CAPACITY_GET_IM_INFO_ON_FOCUS) && ic->frontendid == ipc->frontendid) {
1417 FcitxIM* im = FcitxInstanceGetCurrentIM(ipc->owner);
1418 const char* name = (im && im->strName && fcitx_utf8_check_string(im->strName)) ? im->strName : "";
1419 const char* uniqueName = (im && im->uniqueName && fcitx_utf8_check_string(im->uniqueName)) ? im->uniqueName : "";
1420 const char* langCode = (im && fcitx_utf8_check_string(im->langCode)) ? im->langCode : "";
1421
1422 if (fcitx_utils_strcmp0(GetIPCIC(ic)->lastSentIMInfo.name, name) == 0 &&
1423 fcitx_utils_strcmp0(GetIPCIC(ic)->lastSentIMInfo.uniqueName, uniqueName) == 0 &&
1424 fcitx_utils_strcmp0(GetIPCIC(ic)->lastSentIMInfo.langCode, langCode) == 0) {
1425 return;
1426 }
1427
1428 DBusMessage* msg = dbus_message_new_signal(GetIPCIC(ic)->path, // object name of the signal
1429 FCITX_IC_DBUS_INTERFACE, // interface name of the signal
1430 "CurrentIM"); // name of the signal
1431
1432 fcitx_utils_string_swap(&GetIPCIC(ic)->lastSentIMInfo.name, name);
1433 fcitx_utils_string_swap(&GetIPCIC(ic)->lastSentIMInfo.uniqueName, uniqueName);
1434 fcitx_utils_string_swap(&GetIPCIC(ic)->lastSentIMInfo.langCode, langCode);
1435
1436 dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &uniqueName, DBUS_TYPE_STRING, &langCode, DBUS_TYPE_INVALID);
1437 IPCSendSignal(ipc, GetIPCIC(ic), msg);
1438 }
1439 }
1440
IPCGetPid(void * arg,FcitxInputContext * ic)1441 pid_t IPCGetPid(void* arg, FcitxInputContext* ic)
1442 {
1443 FCITX_UNUSED(arg);
1444 return GetIPCIC(ic)->pid;
1445 }
1446
1447 // kate: indent-mode cstyle; space-indent on; indent-width 0;
1448