1
/***************************************************************************
2
* Copyright (C) 2010~2010 by CSSlayer *
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. *
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. *
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
***************************************************************************/
22
#include <dbus/dbus.h>
25
#include "fcitx/fcitx.h"
26
#include "fcitx/module.h"
27
#include "fcitx-utils/utarray.h"
28
#include "fcitx/instance.h"
29
#include "fcitx-utils/log.h"
30
#include "fcitx-utils/utils.h"
32
#include "frontend/ipc/ipc.h"
33
#include "dbusstuff.h"
36
typedef struct _FcitxDBusWatch {
38
struct _FcitxDBusWatch *next;
41
typedef struct _FcitxDBus {
44
FcitxDBusWatch* watches;
47
#define RETRY_INTERVAL 2
48
#define MAX_RETRY_TIMES 5
50
static void* DBusCreate(FcitxInstance* instance);
51
static void DBusSetFD(void* arg);
52
static void DBusProcessEvent(void* arg);
53
static void* DBusGetConnection(void* arg, FcitxModuleFunctionArg args);
54
static dbus_bool_t FcitxDBusAddWatch(DBusWatch *watch, void *data);
55
static void FcitxDBusRemoveWatch(DBusWatch *watch, void *data);
58
FcitxModule module = {
67
int ABI_VERSION = FCITX_ABI_VERSION;
69
void* DBusCreate(FcitxInstance* instance)
71
FcitxDBus *dbusmodule = (FcitxDBus*) fcitx_utils_malloc0(sizeof(FcitxDBus));
72
FcitxAddon* dbusaddon = FcitxAddonsGetAddonByName(FcitxInstanceGetAddons(instance), FCITX_DBUS_NAME);
75
dbus_threads_init_default();
78
dbus_error_init(&err);
81
DBusConnection* conn = NULL;
84
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
85
if (dbus_error_is_set(&err)) {
86
FcitxLog(WARNING, _("Connection Error (%s)"), err.message);
87
dbus_error_free(&err);
88
dbus_error_init(&err);
92
sleep(RETRY_INTERVAL * MAX_RETRY_TIMES);
95
} while (NULL == conn && retry < MAX_RETRY_TIMES);
102
if (!dbus_connection_set_watch_functions(conn, FcitxDBusAddWatch, FcitxDBusRemoveWatch,
103
NULL, dbusmodule, NULL)) {
104
FcitxLog(WARNING, _("Add Watch Function Error"));
105
dbus_error_free(&err);
110
dbusmodule->conn = conn;
111
dbusmodule->owner = instance;
113
boolean request_retry = false;
114
char* servicename = NULL;
115
asprintf(&servicename, "%s-%d", FCITX_DBUS_SERVICE, fcitx_utils_get_display_number());
117
request_retry = false;
119
// request a name on the bus
120
int ret = dbus_bus_request_name(conn, servicename,
121
DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE,
123
if (dbus_error_is_set(&err)) {
124
FcitxLog(WARNING, _("Name Error (%s)"), err.message);
125
dbus_error_free(&err);
130
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
131
FcitxLog(WARNING, "DBus Service Already Exists");
133
if (FcitxInstanceIsTryReplace(instance)) {
134
FcitxInstanceResetTryReplace(instance);
135
DBusMessage* message = dbus_message_new_method_call(servicename, FCITX_IM_DBUS_PATH, FCITX_IM_DBUS_INTERFACE, "Exit");
136
dbus_connection_send(dbusmodule->conn, message, NULL);
137
/* synchronize call here */
138
DBusMessage* reply = dbus_connection_send_with_reply_and_block(dbusmodule->conn, message, 0, &err);
140
if (dbus_error_is_set(&err)) {
141
dbus_error_free(&err);
142
dbus_error_init(&err);
146
dbus_message_unref(reply);
147
dbus_message_unref(message);
149
/* sleep for a while and retry */
152
request_retry = true;
156
dbus_error_free(&err);
161
} while (request_retry);
165
dbus_connection_flush(conn);
166
AddFunction(dbusaddon, DBusGetConnection);
167
dbus_error_free(&err);
172
void* DBusGetConnection(void* arg, FcitxModuleFunctionArg args)
174
FcitxDBus* dbusmodule = (FcitxDBus*)arg;
175
return dbusmodule->conn;
178
static dbus_bool_t FcitxDBusAddWatch(DBusWatch *watch, void *data)
181
FcitxDBus* dbusmodule = (FcitxDBus*) data;
183
for (w = dbusmodule->watches; w; w = w->next)
184
if (w->watch == watch)
187
if (!(w = fcitx_utils_malloc0(sizeof(FcitxDBusWatch))))
191
w->next = dbusmodule->watches;
192
dbusmodule->watches = w;
196
static void FcitxDBusRemoveWatch(DBusWatch *watch, void *data)
198
FcitxDBusWatch **up, *w;
199
FcitxDBus* dbusmodule = (FcitxDBus*) data;
201
for (up = &(dbusmodule->watches), w = dbusmodule->watches; w; w = w->next) {
202
if (w->watch == watch) {
210
void DBusSetFD(void* arg)
212
FcitxDBus* dbusmodule = (FcitxDBus*) arg;
214
FcitxInstance* instance = dbusmodule->owner;
216
for (w = dbusmodule->watches; w; w = w->next)
217
if (dbus_watch_get_enabled(w->watch)) {
218
unsigned int flags = dbus_watch_get_flags(w->watch);
219
int fd = dbus_watch_get_unix_fd(w->watch);
221
if (FcitxInstanceGetMaxFD(instance) < fd)
222
FcitxInstanceSetMaxFD(instance, fd);
224
if (flags & DBUS_WATCH_READABLE)
225
FD_SET(fd, FcitxInstanceGetReadFDSet(instance));
227
if (flags & DBUS_WATCH_WRITABLE)
228
FD_SET(fd, FcitxInstanceGetWriteFDSet(instance));
230
FD_SET(fd, FcitxInstanceGetExceptFDSet(instance));
235
void DBusProcessEvent(void* arg)
237
FcitxDBus* dbusmodule = (FcitxDBus*) arg;
238
DBusConnection *connection = (DBusConnection *)dbusmodule->conn;
239
FcitxInstance* instance = dbusmodule->owner;
242
for (w = dbusmodule->watches; w; w = w->next) {
243
if (dbus_watch_get_enabled(w->watch)) {
244
unsigned int flags = 0;
245
int fd = dbus_watch_get_unix_fd(w->watch);
247
if (FD_ISSET(fd, FcitxInstanceGetReadFDSet(instance)))
248
flags |= DBUS_WATCH_READABLE;
250
if (FD_ISSET(fd, FcitxInstanceGetWriteFDSet(instance)))
251
flags |= DBUS_WATCH_WRITABLE;
253
if (FD_ISSET(fd, FcitxInstanceGetExceptFDSet(instance)))
254
flags |= DBUS_WATCH_ERROR;
257
dbus_watch_handle(w->watch, flags);
262
dbus_connection_ref(connection);
263
while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
264
dbus_connection_unref(connection);
267
// kate: indent-mode cstyle; space-indent on; indent-width 0;