1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 
3 #include <string.h>
4 #include "ibus.h"
5 
6 static IBusBus *bus;
7 
8 #define BEFORE_ENGINE "xkb:us::eng"
9 #define AFTER_ENGINE "xkb:jp::jpn"
10 
11 static const gchar *engine_names[] = {
12     BEFORE_ENGINE,
13     AFTER_ENGINE
14 };
15 
16 static const gchar *engine_names2[] = {
17     AFTER_ENGINE,
18     BEFORE_ENGINE
19 };
20 
21 static void
change_global_engine(gboolean reverse)22 change_global_engine (gboolean reverse)
23 {
24     gint i;
25 
26     for (i = 0; i < G_N_ELEMENTS (engine_names); i++) {
27         const gchar *engine_name = engine_names[i];
28         if (reverse)
29             engine_name = engine_names2[i];
30         ibus_bus_set_global_engine (bus, engine_name);
31         IBusEngineDesc *engine_desc = ibus_bus_get_global_engine (bus);
32         g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc),
33                          ==,
34                          engine_name);
35         g_object_unref (G_OBJECT (engine_desc));
36     }
37 }
38 
39 static void
change_context_engine(IBusInputContext * context)40 change_context_engine (IBusInputContext *context)
41 {
42     gint i;
43 
44     for (i = 0; i < G_N_ELEMENTS (engine_names); i++) {
45         ibus_input_context_set_engine (context, engine_names[i]);
46         IBusEngineDesc *engine_desc = ibus_input_context_get_engine (context);
47         g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc),
48                          ==,
49                          engine_names[i]);
50     }
51 }
52 
53 typedef struct {
54     gint count;
55     guint timeout_id;
56     guint idle_id;
57     gboolean reverse;
58 } GlobalEngineChangedData;
59 
60 static void
global_engine_changed_cb(IBusBus * bus,gchar * name,gpointer user_data)61 global_engine_changed_cb (IBusBus *bus, gchar *name, gpointer user_data)
62 {
63     GlobalEngineChangedData *data = (GlobalEngineChangedData *) user_data;
64     if (data->count++ == 0)
65         ibus_quit ();
66 }
67 
68 static gboolean
timeout_cb(gpointer user_data)69 timeout_cb (gpointer user_data)
70 {
71     GlobalEngineChangedData *data = (GlobalEngineChangedData *) user_data;
72     if (data->count == 0)
73         ibus_quit ();
74     data->timeout_id = 0;
75     return FALSE;
76 }
77 
78 static gboolean
change_global_engine_cb(gpointer user_data)79 change_global_engine_cb (gpointer user_data)
80 {
81     GlobalEngineChangedData *data = (GlobalEngineChangedData *) user_data;
82     change_global_engine (data->reverse);
83     data->idle_id = 0;
84     return FALSE;
85 }
86 
87 static void
test_global_engine(void)88 test_global_engine (void)
89 {
90     GLogLevelFlags flags;
91     IBusEngineDesc *desc;
92     GlobalEngineChangedData data;
93     guint handler_id;
94 
95     if (!ibus_bus_get_use_global_engine (bus))
96         return;
97 
98     /* "No global engine." warning is not critical message. */
99     flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
100     desc = ibus_bus_get_global_engine (bus);
101     g_log_set_always_fatal (flags);
102     if (desc &&
103         !g_strcmp0 (BEFORE_ENGINE, ibus_engine_desc_get_name (desc))) {
104         data.reverse = TRUE;
105     } else {
106         data.reverse = FALSE;
107     }
108 
109     data.count = 0;
110 
111     handler_id = g_signal_connect (bus,
112                                    "global-engine-changed",
113                                    G_CALLBACK (global_engine_changed_cb),
114                                    &data);
115     data.timeout_id = g_timeout_add_seconds (1, timeout_cb, &data);
116     data.idle_id = g_idle_add ((GSourceFunc) change_global_engine_cb, &data);
117 
118     ibus_main ();
119 
120     g_assert_cmpint (data.count, ==, G_N_ELEMENTS (engine_names));
121 
122     if (data.idle_id > 0)
123         g_source_remove (data.idle_id);
124     if (data.timeout_id > 0)
125         g_source_remove (data.timeout_id);
126     g_signal_handler_disconnect (bus, handler_id);
127 }
128 
129 static void
test_context_engine(void)130 test_context_engine (void)
131 {
132     IBusEngineDesc *engine_desc;
133     IBusInputContext *context;
134 
135     if (ibus_bus_get_use_global_engine (bus))
136         return;
137 
138     context = ibus_bus_create_input_context (bus, "test");
139     ibus_input_context_set_capabilities (context, IBUS_CAP_FOCUS);
140 
141     /* ibus_bus_set_global_engine() changes focused context engine. */
142     ibus_input_context_focus_in (context);
143 
144     change_context_engine (context);
145     engine_desc = ibus_input_context_get_engine (context);
146     g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), ==, AFTER_ENGINE);
147 
148     g_object_unref (context);
149 }
150 
151 static void
test_context_engine_set_by_global(void)152 test_context_engine_set_by_global (void)
153 {
154     IBusEngineDesc *engine_desc;
155     IBusInputContext *context;
156 
157     if (!ibus_bus_get_use_global_engine (bus))
158         return;
159 
160     context = ibus_bus_create_input_context (bus, "test");
161     ibus_input_context_set_capabilities (context, IBUS_CAP_FOCUS);
162 
163     /* ibus_bus_set_global_engine() changes focused context engine. */
164     ibus_input_context_focus_in (context);
165 
166     change_global_engine (FALSE);
167 
168     /* ibus_input_context_set_engine() does not take effect when
169        global engine is used. */
170     ibus_input_context_set_engine (context, BEFORE_ENGINE);
171 
172     engine_desc = ibus_input_context_get_engine (context);
173     g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), ==, AFTER_ENGINE);
174 
175     g_object_unref (context);
176 }
177 
178 static void
test_context_engine_set_by_focus(void)179 test_context_engine_set_by_focus (void)
180 {
181     IBusEngineDesc *engine_desc;
182     IBusInputContext *context, *another_context;
183 
184     if (!ibus_bus_get_use_global_engine (bus))
185         return;
186 
187     context = ibus_bus_create_input_context (bus, "test");
188     ibus_input_context_set_capabilities (context, IBUS_CAP_FOCUS);
189 
190     another_context = ibus_bus_create_input_context (bus, "another");
191     ibus_input_context_set_capabilities (another_context, IBUS_CAP_FOCUS);
192 
193     ibus_input_context_focus_in (context);
194 
195     change_global_engine (FALSE);
196 
197     /* When focus is lost, context engine is set to "dummy". */
198     ibus_input_context_focus_in (another_context);
199 
200     engine_desc = ibus_input_context_get_engine (context);
201     g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), ==, "dummy");
202 
203     engine_desc = ibus_input_context_get_engine (another_context);
204     g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), ==, AFTER_ENGINE);
205 
206     g_object_unref (context);
207     g_object_unref (another_context);
208 }
209 
210 gint
main(gint argc,gchar ** argv)211 main (gint    argc,
212       gchar **argv)
213 {
214     gint result;
215     ibus_init ();
216     g_test_init (&argc, &argv, NULL);
217     bus = ibus_bus_new ();
218     g_object_unref (bus);
219     bus = ibus_bus_new (); // crosbug.com/17293
220 
221     ibus_bus_set_watch_ibus_signal (bus, TRUE);
222 
223     g_test_add_func ("/ibus/engine-switch/global-engine",
224                      test_global_engine);
225     g_test_add_func ("/ibus/engine-switch/context-engine",
226                      test_context_engine);
227     g_test_add_func ("/ibus/engine-switch/context-engine-set-by-global",
228                      test_context_engine_set_by_global);
229     g_test_add_func ("/ibus/engine-switch/context-engine-set-by-focus",
230                      test_context_engine_set_by_focus);
231 
232     result = g_test_run ();
233     g_object_unref (bus);
234 
235     return result;
236 }
237