16 | 16 |
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
17 | 17 |
***************************************************************************/
|
18 | 18 |
|
19 | |
#include <fcitx/module/dbus/dbusstuff.h>
|
|
19 |
#include <dbus/dbus-glib.h>
|
20 | 20 |
#include <fcitx/module/ipc/ipc.h>
|
21 | |
|
22 | |
|
|
21 |
#include <string.h>
|
|
22 |
#include <stdio.h>
|
23 | 23 |
#include "im.h"
|
24 | 24 |
|
25 | |
static const gchar introspection_xml[] =
|
26 | |
"<node>"
|
27 | |
" <interface name=\"org.fcitx.Fcitx.InputMethod\">"
|
28 | |
" <property access=\"readwrite\" type=\"a(sssb)\" name=\"IMList\">"
|
29 | |
" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"true\"/>"
|
30 | |
" </property>"
|
31 | |
" </interface>"
|
32 | |
"</node>";
|
|
25 |
#define TYPE_IM \
|
|
26 |
dbus_g_type_get_struct("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID)
|
33 | 27 |
|
|
28 |
#define TYPE_ARRAY_IM \
|
|
29 |
dbus_g_type_get_collection("GPtrArray", TYPE_IM)
|
34 | 30 |
|
35 | |
enum {
|
36 | |
IMLIST_CHANGED_SIGNAL,
|
37 | |
LAST_SIGNAL
|
38 | |
};
|
|
31 |
static void _fcitx_inputmethod_item_foreach_cb(gpointer data,
|
|
32 |
gpointer user_data);
|
39 | 33 |
|
40 | |
static guint signals[LAST_SIGNAL] = {0};
|
|
34 |
static FcitxIMItem*
|
|
35 |
_value_to_item (const GValue *value)
|
|
36 |
{
|
|
37 |
const gchar *name, *unique_name, *langcode;
|
|
38 |
gboolean enable;
|
|
39 |
GType type;
|
41 | 40 |
|
|
41 |
type = G_VALUE_TYPE (value);
|
|
42 |
g_assert(dbus_g_type_is_struct (type));
|
|
43 |
g_assert(4 == dbus_g_type_get_struct_size (type));
|
|
44 |
g_assert(G_TYPE_STRING == dbus_g_type_get_struct_member_type (type, 0));
|
|
45 |
g_assert(G_TYPE_STRING == dbus_g_type_get_struct_member_type (type, 1));
|
|
46 |
g_assert(G_TYPE_STRING == dbus_g_type_get_struct_member_type (type, 2));
|
|
47 |
g_assert(G_TYPE_BOOLEAN == dbus_g_type_get_struct_member_type (type, 3));
|
42 | 48 |
|
43 | |
G_DEFINE_TYPE(FcitxInputMethod, fcitx_inputmethod, G_TYPE_DBUS_PROXY);
|
|
49 |
GValue cvalue;
|
|
50 |
memset(&cvalue, 0, sizeof(GValue));
|
44 | 51 |
|
|
52 |
FcitxIMItem* item = g_malloc0(sizeof(FcitxIMItem));
|
45 | 53 |
|
46 | |
static GDBusInterfaceInfo *
|
47 | |
fcitx_inputmethod_get_interface_info(void);
|
48 | |
static void _fcitx_inputmethod_item_foreach_cb(gpointer data, gpointer user_data);
|
|
54 |
g_value_init (&cvalue, dbus_g_type_get_struct_member_type (type, 0));
|
|
55 |
dbus_g_type_struct_get_member (value, 0, &cvalue);
|
|
56 |
name = g_value_get_string(&cvalue);
|
|
57 |
item->name = strdup(name);
|
|
58 |
g_value_unset (&cvalue);
|
49 | 59 |
|
50 | |
static GDBusInterfaceInfo *
|
51 | |
fcitx_inputmethod_get_interface_info(void)
|
52 | |
{
|
53 | |
static gsize has_info = 0;
|
54 | |
static GDBusInterfaceInfo *info = NULL;
|
55 | |
if (g_once_init_enter(&has_info)) {
|
56 | |
GDBusNodeInfo *introspection_data;
|
57 | |
introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
|
58 | |
info = introspection_data->interfaces[0];
|
59 | |
g_once_init_leave(&has_info, 1);
|
60 | |
}
|
61 | |
return info;
|
|
60 |
g_value_init (&cvalue, dbus_g_type_get_struct_member_type (type, 1));
|
|
61 |
dbus_g_type_struct_get_member (value, 1, &cvalue);
|
|
62 |
unique_name = g_value_get_string(&cvalue);
|
|
63 |
item->unique_name = strdup(unique_name);
|
|
64 |
g_value_unset (&cvalue);
|
|
65 |
|
|
66 |
g_value_init (&cvalue, dbus_g_type_get_struct_member_type (type, 2));
|
|
67 |
dbus_g_type_struct_get_member (value, 2, &cvalue);
|
|
68 |
langcode = g_value_get_string(&cvalue);
|
|
69 |
item->langcode = strdup(langcode);
|
|
70 |
g_value_unset (&cvalue);
|
|
71 |
|
|
72 |
g_value_init (&cvalue, dbus_g_type_get_struct_member_type (type, 3));
|
|
73 |
dbus_g_type_struct_get_member (value, 3, &cvalue);
|
|
74 |
enable = g_value_get_boolean(&cvalue);
|
|
75 |
item->enable = enable;
|
|
76 |
g_value_unset (&cvalue);
|
|
77 |
return item;
|
62 | 78 |
}
|
63 | 79 |
|
64 | 80 |
static void
|
65 | |
fcitx_inputmethod_finalize(GObject *object)
|
|
81 |
_item_to_value (FcitxIMItem* item, GValue *value)
|
66 | 82 |
{
|
67 | |
G_GNUC_UNUSED FcitxInputMethod *im = FCITX_INPUTMETHOD(object);
|
68 | |
|
69 | |
if (G_OBJECT_CLASS(fcitx_inputmethod_parent_class)->finalize != NULL)
|
70 | |
G_OBJECT_CLASS(fcitx_inputmethod_parent_class)->finalize(object);
|
|
83 |
g_value_init (value, TYPE_IM);
|
|
84 |
GValueArray *va = g_value_array_new (4);
|
|
85 |
g_value_array_append (va, NULL);
|
|
86 |
g_value_init(&va->values[0], G_TYPE_STRING);
|
|
87 |
g_value_set_string(&va->values[0], item->name);
|
|
88 |
g_value_array_append (va, NULL);
|
|
89 |
g_value_init(&va->values[1], G_TYPE_STRING);
|
|
90 |
g_value_set_string(&va->values[1], item->unique_name);
|
|
91 |
g_value_array_append (va, NULL);
|
|
92 |
g_value_init(&va->values[2], G_TYPE_STRING);
|
|
93 |
g_value_set_string(&va->values[2], item->langcode);
|
|
94 |
g_value_array_append (va, NULL);
|
|
95 |
g_value_init(&va->values[3], G_TYPE_BOOLEAN);
|
|
96 |
g_value_set_boolean(&va->values[3], item->enable);
|
|
97 |
g_value_take_boxed (value, va);
|
71 | 98 |
}
|
72 | 99 |
|
73 | 100 |
static void
|
74 | |
fcitx_inputmethod_init(FcitxInputMethod *im)
|
|
101 |
_collection_iterator (const GValue *value,
|
|
102 |
gpointer user_data)
|
75 | 103 |
{
|
76 | |
/* Sets the expected interface */
|
77 | |
g_dbus_proxy_set_interface_info(G_DBUS_PROXY(im), fcitx_inputmethod_get_interface_info());
|
|
104 |
GPtrArray *children = user_data;
|
|
105 |
|
|
106 |
g_ptr_array_add (children, _value_to_item (value));
|
78 | 107 |
}
|
79 | 108 |
|
80 | |
GPtrArray *
|
81 | |
fcitx_inputmethod_get_imlist(FcitxInputMethod* im)
|
|
109 |
void fcitx_inputmethod_set_imlist(DBusGProxy* proxy, GPtrArray* array)
|
|
110 |
{
|
|
111 |
GValue value;
|
|
112 |
memset(&value, 0, sizeof(GValue));
|
|
113 |
g_value_init(&value, TYPE_ARRAY_IM);
|
|
114 |
g_value_take_boxed (&value, dbus_g_type_specialized_construct (
|
|
115 |
G_VALUE_TYPE (&value)));
|
|
116 |
DBusGTypeSpecializedAppendContext ctx;
|
|
117 |
|
|
118 |
dbus_g_type_specialized_init_append (&value, &ctx);
|
|
119 |
g_ptr_array_foreach(array, _fcitx_inputmethod_item_foreach_cb, &ctx);
|
|
120 |
dbus_g_type_specialized_collection_end_append (&ctx);
|
|
121 |
dbus_g_proxy_call_no_reply(proxy, "Set", G_TYPE_STRING, FCITX_IM_DBUS_INTERFACE, G_TYPE_STRING, "IMList", G_TYPE_VALUE, &value, G_TYPE_INVALID);
|
|
122 |
g_value_unset(&value);
|
|
123 |
}
|
|
124 |
|
|
125 |
GPtrArray* fcitx_inputmethod_get_imlist(DBusGProxy* proxy)
|
82 | 126 |
{
|
83 | 127 |
GPtrArray *array = NULL;
|
84 | |
GVariant* value;
|
85 | |
GVariantIter *iter;
|
86 | |
gchar *name, *unique_name, *langcode;
|
87 | |
gboolean enable;
|
88 | |
value = g_dbus_proxy_get_cached_property(G_DBUS_PROXY(im), "IMList");
|
|
128 |
GValue value;
|
|
129 |
memset(&value, 0, sizeof(GValue));
|
89 | 130 |
|
90 | |
if (value == NULL) {
|
91 | |
GError* error = NULL;
|
92 | |
GVariant* result = g_dbus_connection_call_sync(g_dbus_proxy_get_connection(G_DBUS_PROXY(im)),
|
93 | |
g_dbus_proxy_get_name(G_DBUS_PROXY(im)),
|
94 | |
FCITX_IM_DBUS_PATH,
|
95 | |
"org.freedesktop.DBus.Properties",
|
96 | |
"Get",
|
97 | |
g_variant_new("(ss)", FCITX_IM_DBUS_INTERFACE, "IMList"),
|
98 | |
G_VARIANT_TYPE("(v)"),
|
99 | |
G_DBUS_CALL_FLAGS_NONE,
|
100 | |
-1, /* timeout */
|
101 | |
NULL,
|
102 | |
&error);
|
103 | |
|
104 | |
if (error) {
|
105 | |
g_warning("%s", error->message);
|
106 | |
g_error_free(error);
|
107 | |
} else if (result) {
|
108 | |
g_variant_get(result, "(v)", &value);
|
109 | |
}
|
110 | |
}
|
111 | |
|
112 | |
if (value) {
|
113 | |
array = g_ptr_array_new();
|
114 | |
g_variant_get(value, "a(sssb)", &iter);
|
115 | |
while (g_variant_iter_next(iter, "(sssb)", &name, &unique_name, &langcode, &enable, NULL)) {
|
116 | |
FcitxIMItem* item = g_malloc0(sizeof(FcitxIMItem));
|
117 | |
item->enable = enable;
|
118 | |
item->name = strdup(name);
|
119 | |
item->unique_name = strdup(unique_name);
|
120 | |
item->langcode = strdup(langcode);
|
121 | |
g_ptr_array_add(array, item);
|
122 | |
g_free(name);
|
123 | |
g_free(unique_name);
|
124 | |
g_free(langcode);
|
125 | |
}
|
126 | |
g_variant_iter_free(iter);
|
127 | |
|
128 | |
g_variant_unref(value);
|
129 | |
}
|
130 | |
|
131 | |
return array;
|
132 | |
}
|
133 | |
|
134 | |
|
135 | |
void
|
136 | |
fcitx_inputmethod_set_imlist(FcitxInputMethod *im, GPtrArray* array)
|
137 | |
{
|
138 | |
GVariantBuilder builder;
|
139 | |
g_variant_builder_init(&builder, G_VARIANT_TYPE("a(sssb)"));
|
140 | |
g_ptr_array_foreach(array, _fcitx_inputmethod_item_foreach_cb, &builder);
|
141 | |
GVariant* value = g_variant_builder_end(&builder);
|
142 | 131 |
GError* error = NULL;
|
143 | |
GVariant* result = g_dbus_connection_call_sync(g_dbus_proxy_get_connection(G_DBUS_PROXY(im)),
|
144 | |
g_dbus_proxy_get_name(G_DBUS_PROXY(im)),
|
145 | |
FCITX_IM_DBUS_PATH,
|
146 | |
"org.freedesktop.DBus.Properties",
|
147 | |
"Set",
|
148 | |
g_variant_new("(ssv)", FCITX_IM_DBUS_INTERFACE, "IMList", value),
|
149 | |
G_VARIANT_TYPE_UNIT,
|
150 | |
G_DBUS_CALL_FLAGS_NONE,
|
151 | |
-1, /* timeout */
|
152 | |
NULL,
|
153 | |
&error);
|
|
132 |
dbus_g_proxy_call(proxy, "Get", &error, G_TYPE_STRING, FCITX_IM_DBUS_INTERFACE, G_TYPE_STRING, "IMList", G_TYPE_INVALID, G_TYPE_VALUE, &value, G_TYPE_INVALID);
|
154 | 133 |
|
155 | 134 |
if (error) {
|
156 | 135 |
g_warning("%s", error->message);
|
157 | 136 |
g_error_free(error);
|
|
137 |
return NULL;
|
158 | 138 |
}
|
159 | 139 |
|
160 | |
g_variant_unref(result);
|
161 | |
g_variant_unref(value);
|
162 | |
}
|
|
140 |
array = g_ptr_array_new();
|
|
141 |
GType type = G_VALUE_TYPE (&value);
|
163 | 142 |
|
164 | |
static void
|
165 | |
fcitx_inputmethod_g_properties_changed(GDBusProxy *proxy,
|
166 | |
GVariant *changed_properties,
|
167 | |
const gchar* const *invalidated_properties)
|
168 | |
{
|
169 | |
FcitxInputMethod *user = FCITX_INPUTMETHOD(proxy);
|
170 | |
GVariantIter *iter;
|
171 | |
const gchar *key;
|
|
143 |
if (dbus_g_type_is_collection (type))
|
|
144 |
{
|
|
145 |
dbus_g_type_collection_value_iterate (&value, _collection_iterator,
|
|
146 |
array);
|
|
147 |
}
|
|
148 |
g_value_unset(&value);
|
172 | 149 |
|
173 | |
if (changed_properties != NULL) {
|
174 | |
g_variant_get(changed_properties, "a{sv}", &iter);
|
175 | |
while (g_variant_iter_next(iter, "{&sv}", &key, NULL)) {
|
176 | |
if (g_strcmp0(key, "IMList") == 0)
|
177 | |
g_signal_emit(user, signals[IMLIST_CHANGED_SIGNAL], 0);
|
178 | |
}
|
179 | |
g_variant_iter_free(iter);
|
180 | |
}
|
181 | |
|
182 | |
if (invalidated_properties != NULL) {
|
183 | |
const gchar*const* item = invalidated_properties;
|
184 | |
while (*item) {
|
185 | |
if (g_strcmp0(*item, "IMList") == 0)
|
186 | |
g_signal_emit(user, signals[IMLIST_CHANGED_SIGNAL], 0);
|
187 | |
item++;
|
188 | |
}
|
189 | |
}
|
190 | |
}
|
191 | |
|
192 | |
static void
|
193 | |
fcitx_inputmethod_g_signal(GDBusProxy *proxy,
|
194 | |
const gchar *sender_name,
|
195 | |
const gchar *signal_name,
|
196 | |
GVariant *parameters)
|
197 | |
{
|
198 | |
}
|
199 | |
|
200 | |
static void
|
201 | |
fcitx_inputmethod_class_init(FcitxInputMethodClass *klass)
|
202 | |
{
|
203 | |
GObjectClass *gobject_class;
|
204 | |
GDBusProxyClass *proxy_class;
|
205 | |
|
206 | |
gobject_class = G_OBJECT_CLASS(klass);
|
207 | |
gobject_class->finalize = fcitx_inputmethod_finalize;
|
208 | |
|
209 | |
proxy_class = G_DBUS_PROXY_CLASS(klass);
|
210 | |
proxy_class->g_signal = fcitx_inputmethod_g_signal;
|
211 | |
proxy_class->g_properties_changed = fcitx_inputmethod_g_properties_changed;
|
212 | |
|
213 | |
signals[IMLIST_CHANGED_SIGNAL] = g_signal_new("imlist-changed",
|
214 | |
FCITX_TYPE_INPUT_METHOD,
|
215 | |
G_SIGNAL_RUN_LAST,
|
216 | |
G_STRUCT_OFFSET(FcitxInputMethod, imlist_changed),
|
217 | |
NULL,
|
218 | |
NULL,
|
219 | |
g_cclosure_marshal_VOID__VOID,
|
220 | |
G_TYPE_NONE,
|
221 | |
0);
|
222 | |
}
|
223 | |
|
224 | |
FcitxInputMethod*
|
225 | |
fcitx_inputmethod_new(GBusType bus_type,
|
226 | |
GDBusProxyFlags flags,
|
227 | |
int display_number,
|
228 | |
GCancellable *cancellable,
|
229 | |
GError **error)
|
230 | |
{
|
231 | |
gchar servicename[64];
|
232 | |
sprintf(servicename, "%s-%d", FCITX_DBUS_SERVICE, display_number);
|
233 | |
|
234 | |
char* name = servicename;
|
235 | |
FcitxInputMethod* im = g_initable_new(FCITX_TYPE_INPUT_METHOD,
|
236 | |
cancellable,
|
237 | |
error,
|
238 | |
"g-flags", flags,
|
239 | |
"g-name", name,
|
240 | |
"g-bus-type", bus_type,
|
241 | |
"g-object-path", FCITX_IM_DBUS_PATH,
|
242 | |
"g-interface-name", FCITX_IM_DBUS_INTERFACE,
|
243 | |
NULL);
|
244 | |
|
245 | |
if (im != NULL)
|
246 | |
return FCITX_INPUTMETHOD(im);
|
247 | |
else
|
248 | |
return NULL;
|
249 | |
return im;
|
|
150 |
return array;
|
250 | 151 |
}
|
251 | 152 |
|
252 | 153 |
void fcitx_inputmethod_item_free(gpointer data)
|
|
262 | 163 |
gpointer user_data)
|
263 | 164 |
{
|
264 | 165 |
FcitxIMItem* item = data;
|
265 | |
GVariantBuilder* builder = user_data;
|
|
166 |
DBusGTypeSpecializedAppendContext* ctx = user_data;
|
266 | 167 |
|
267 | |
g_variant_builder_add(builder, "(sssb)", item->name, item->unique_name, item->langcode, item->enable);
|
268 | |
}⏎
|
|
168 |
GValue v;
|
|
169 |
memset(&v, 0, sizeof(GValue));
|
|
170 |
_item_to_value(item, &v);
|
|
171 |
dbus_g_type_specialized_collection_append (ctx, &v);
|
|
172 |
}
|