File: | ctk/ctkimmodule.c |
Warning: | line 499, column 4 Potential leak of memory pointed to by 'info' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* CTK - The GIMP Toolkit | ||||
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald | ||||
3 | * | ||||
4 | * This library is free software; you can redistribute it and/or | ||||
5 | * modify it under the terms of the GNU Lesser General Public | ||||
6 | * License as published by the Free Software Foundation; either | ||||
7 | * version 2 of the License, or (at your option) any later version. | ||||
8 | * | ||||
9 | * This library 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 GNU | ||||
12 | * Lesser General Public License for more details. | ||||
13 | * | ||||
14 | * You should have received a copy of the GNU Lesser General Public | ||||
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free | ||||
16 | */ | ||||
17 | |||||
18 | /* | ||||
19 | * Modified by the CTK+ Team and others 1997-2000. See the AUTHORS | ||||
20 | * file for a list of people on the CTK+ Team. See the ChangeLog | ||||
21 | * files for a list of changes. These files are distributed with | ||||
22 | * CTK+ at ftp://ftp.ctk.org/pub/ctk/. | ||||
23 | */ | ||||
24 | |||||
25 | #include "config.h" | ||||
26 | |||||
27 | #include <errno(*__errno_location ()).h> | ||||
28 | #include <stdio.h> | ||||
29 | #include <stdlib.h> | ||||
30 | #include <string.h> | ||||
31 | |||||
32 | #include <glib/gstdio.h> | ||||
33 | #include <gmodule.h> | ||||
34 | #include "ctkimmoduleprivate.h" | ||||
35 | #include "ctkimcontextsimple.h" | ||||
36 | #include "ctksettings.h" | ||||
37 | #include "ctkprivate.h" | ||||
38 | #include "ctkutilsprivate.h" | ||||
39 | #include "ctkintl.h" | ||||
40 | |||||
41 | #ifdef CDK_WINDOWING_X11 | ||||
42 | #include "x11/cdkx.h" | ||||
43 | #endif | ||||
44 | |||||
45 | #ifdef CDK_WINDOWING_WAYLAND | ||||
46 | #include "wayland/cdkwayland.h" | ||||
47 | #endif | ||||
48 | |||||
49 | #ifdef CDK_WINDOWING_BROADWAY | ||||
50 | #include "broadway/cdkbroadway.h" | ||||
51 | #endif | ||||
52 | |||||
53 | #ifdef CDK_WINDOWING_WIN32 | ||||
54 | #include "win32/cdkwin32.h" | ||||
55 | #endif | ||||
56 | |||||
57 | #ifdef G_OS_WIN32 | ||||
58 | #include <windows.h> | ||||
59 | #endif | ||||
60 | |||||
61 | #undef CDK_DEPRECATED | ||||
62 | #undef CDK_DEPRECATED_FOR | ||||
63 | #define CDK_DEPRECATED | ||||
64 | #define CDK_DEPRECATED_FOR(f) | ||||
65 | |||||
66 | #include "ctkrc.h" | ||||
67 | |||||
68 | /* We need to call getc() a lot in a loop. This is suboptimal, | ||||
69 | * as getc() does thread locking on the FILE it is given. | ||||
70 | * To optimize that, lock the file first, then call getc(), | ||||
71 | * then unlock. | ||||
72 | * If locking functions are not present in libc, fall back | ||||
73 | * to the suboptimal getc(). | ||||
74 | */ | ||||
75 | #if !defined(HAVE_FLOCKFILE1) && !defined(HAVE__LOCK_FILE) | ||||
76 | # define flockfile(f) (void)1 | ||||
77 | # define funlockfile(f) (void)1 | ||||
78 | # define getc_unlocked(f) getc(f) | ||||
79 | #elif !defined(HAVE_FLOCKFILE1) && defined(HAVE__LOCK_FILE) | ||||
80 | # define flockfile(f) _lock_file(f) | ||||
81 | # define funlockfile(f) _unlock_file(f) | ||||
82 | # define getc_unlocked(f) _getc_nolock(f) | ||||
83 | #endif | ||||
84 | |||||
85 | #define SIMPLE_ID"ctk-im-context-simple" "ctk-im-context-simple" | ||||
86 | #define NONE_ID"ctk-im-context-none" "ctk-im-context-none" | ||||
87 | |||||
88 | /** | ||||
89 | * CtkIMContextInfo: | ||||
90 | * @context_id: The unique identification string of the input method. | ||||
91 | * @context_name: The human-readable name of the input method. | ||||
92 | * @domain: Translation domain to be used with dgettext() | ||||
93 | * @domain_dirname: Name of locale directory for use with bindtextdomain() | ||||
94 | * @default_locales: A colon-separated list of locales where this input method | ||||
95 | * should be the default. The asterisk “*” sets the default for all locales. | ||||
96 | * | ||||
97 | * Bookkeeping information about a loadable input method. | ||||
98 | */ | ||||
99 | |||||
100 | typedef struct _CtkIMModule CtkIMModule; | ||||
101 | typedef struct _CtkIMModuleClass CtkIMModuleClass; | ||||
102 | |||||
103 | #define CTK_TYPE_IM_MODULE(ctk_im_module_get_type ()) (ctk_im_module_get_type ()) | ||||
104 | #define CTK_IM_MODULE(im_module)((((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((im_module)), ((ctk_im_module_get_type ())))))) (G_TYPE_CHECK_INSTANCE_CAST ((im_module), CTK_TYPE_IM_MODULE, CtkIMModule)(((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((im_module)), ((ctk_im_module_get_type ())))))) | ||||
105 | #define CTK_IS_IM_MODULE(im_module)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (im_module)); GType __t = ((ctk_im_module_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))) (G_TYPE_CHECK_INSTANCE_TYPE ((im_module), CTK_TYPE_IM_MODULE)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (im_module)); GType __t = ((ctk_im_module_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))) | ||||
106 | |||||
107 | struct _CtkIMModule | ||||
108 | { | ||||
109 | GTypeModule parent_instance; | ||||
110 | |||||
111 | gboolean builtin; | ||||
112 | |||||
113 | GModule *library; | ||||
114 | |||||
115 | void (*list) (const CtkIMContextInfo ***contexts, | ||||
116 | guint *n_contexts); | ||||
117 | void (*init) (GTypeModule *module); | ||||
118 | void (*exit) (void); | ||||
119 | CtkIMContext *(*create) (const gchar *context_id); | ||||
120 | |||||
121 | CtkIMContextInfo **contexts; | ||||
122 | guint n_contexts; | ||||
123 | |||||
124 | gchar *path; | ||||
125 | }; | ||||
126 | |||||
127 | struct _CtkIMModuleClass | ||||
128 | { | ||||
129 | GTypeModuleClass parent_class; | ||||
130 | }; | ||||
131 | |||||
132 | static GType ctk_im_module_get_type (void); | ||||
133 | |||||
134 | static gint n_loaded_contexts = 0; | ||||
135 | static GHashTable *contexts_hash = NULL((void*)0); | ||||
136 | static GSList *modules_list = NULL((void*)0); | ||||
137 | |||||
138 | static gboolean | ||||
139 | ctk_im_module_load (GTypeModule *module) | ||||
140 | { | ||||
141 | CtkIMModule *im_module = CTK_IM_MODULE (module)((((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((module)), ((ctk_im_module_get_type ())))))); | ||||
142 | |||||
143 | if (!im_module->builtin) | ||||
144 | { | ||||
145 | im_module->library = g_module_open (im_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); | ||||
146 | if (!im_module->library) | ||||
147 | { | ||||
148 | g_warning ("%s", g_module_error()); | ||||
149 | return FALSE(0); | ||||
150 | } | ||||
151 | |||||
152 | /* extract symbols from the lib */ | ||||
153 | if (!g_module_symbol (im_module->library, "im_module_init", | ||||
154 | (gpointer *)&im_module->init) || | ||||
155 | !g_module_symbol (im_module->library, "im_module_exit", | ||||
156 | (gpointer *)&im_module->exit) || | ||||
157 | !g_module_symbol (im_module->library, "im_module_list", | ||||
158 | (gpointer *)&im_module->list) || | ||||
159 | !g_module_symbol (im_module->library, "im_module_create", | ||||
160 | (gpointer *)&im_module->create)) | ||||
161 | { | ||||
162 | g_warning ("%s", g_module_error()); | ||||
163 | g_module_close (im_module->library); | ||||
164 | |||||
165 | return FALSE(0); | ||||
166 | } | ||||
167 | } | ||||
168 | |||||
169 | /* call the module's init function to let it */ | ||||
170 | /* setup anything it needs to set up. */ | ||||
171 | im_module->init (module); | ||||
172 | |||||
173 | return TRUE(!(0)); | ||||
174 | } | ||||
175 | |||||
176 | static void | ||||
177 | ctk_im_module_unload (GTypeModule *module) | ||||
178 | { | ||||
179 | CtkIMModule *im_module = CTK_IM_MODULE (module)((((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((module)), ((ctk_im_module_get_type ())))))); | ||||
180 | |||||
181 | im_module->exit(); | ||||
182 | |||||
183 | if (!im_module->builtin) | ||||
184 | { | ||||
185 | g_module_close (im_module->library); | ||||
186 | im_module->library = NULL((void*)0); | ||||
187 | |||||
188 | im_module->init = NULL((void*)0); | ||||
189 | im_module->exit = NULL((void*)0); | ||||
190 | im_module->list = NULL((void*)0); | ||||
191 | im_module->create = NULL((void*)0); | ||||
192 | } | ||||
193 | } | ||||
194 | |||||
195 | G_DEFINE_TYPE (CtkIMModule, ctk_im_module, G_TYPE_TYPE_MODULE)static void ctk_im_module_init (CtkIMModule *self); static void ctk_im_module_class_init (CtkIMModuleClass *klass); static GType ctk_im_module_get_type_once (void); static gpointer ctk_im_module_parent_class = ((void*)0); static gint CtkIMModule_private_offset; static void ctk_im_module_class_intern_init (gpointer klass) { ctk_im_module_parent_class = g_type_class_peek_parent (klass); if (CtkIMModule_private_offset != 0) g_type_class_adjust_private_offset (klass, &CtkIMModule_private_offset ); ctk_im_module_class_init ((CtkIMModuleClass*) klass); } __attribute__ ((__unused__)) static inline gpointer ctk_im_module_get_instance_private (CtkIMModule *self) { return (((gpointer) ((guint8*) (self) + (glong) (CtkIMModule_private_offset)))); } GType ctk_im_module_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); (void) ( 0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0)) ; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = ctk_im_module_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id ) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer ((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id )); })) ; } return static_g_define_type_id; } __attribute__ ( (__noinline__)) static GType ctk_im_module_get_type_once (void ) { GType g_define_type_id = g_type_register_static_simple (( g_type_module_get_type ()), g_intern_static_string ("CtkIMModule" ), sizeof (CtkIMModuleClass), (GClassInitFunc)(void (*)(void) ) ctk_im_module_class_intern_init, sizeof (CtkIMModule), (GInstanceInitFunc )(void (*)(void)) ctk_im_module_init, (GTypeFlags) 0); { {{}; } } return g_define_type_id; } | ||||
196 | |||||
197 | /* This only will ever be called if an error occurs during | ||||
198 | * initialization | ||||
199 | */ | ||||
200 | static void | ||||
201 | ctk_im_module_finalize (GObject *object) | ||||
202 | { | ||||
203 | CtkIMModule *module = CTK_IM_MODULE (object)((((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((ctk_im_module_get_type ())))))); | ||||
204 | |||||
205 | g_free (module->path); | ||||
206 | |||||
207 | G_OBJECT_CLASS (ctk_im_module_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((ctk_im_module_parent_class)), (((GType) ((20) << ( 2))))))))->finalize (object); | ||||
208 | } | ||||
209 | |||||
210 | static void | ||||
211 | ctk_im_module_class_init (CtkIMModuleClass *class) | ||||
212 | { | ||||
213 | GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class)((((GTypeModuleClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((class)), ((g_type_module_get_type ())))))); | ||||
214 | GObjectClass *gobject_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((class)), (((GType) ((20) << (2)))))))); | ||||
215 | |||||
216 | module_class->load = ctk_im_module_load; | ||||
217 | module_class->unload = ctk_im_module_unload; | ||||
218 | |||||
219 | gobject_class->finalize = ctk_im_module_finalize; | ||||
220 | } | ||||
221 | |||||
222 | static void | ||||
223 | ctk_im_module_init (CtkIMModule* object G_GNUC_UNUSED__attribute__ ((__unused__))) | ||||
224 | { | ||||
225 | } | ||||
226 | |||||
227 | static void | ||||
228 | free_info (CtkIMContextInfo *info) | ||||
229 | { | ||||
230 | g_free ((char *)info->context_id); | ||||
231 | g_free ((char *)info->context_name); | ||||
232 | g_free ((char *)info->domain); | ||||
233 | g_free ((char *)info->domain_dirname); | ||||
234 | g_free ((char *)info->default_locales); | ||||
235 | g_free (info); | ||||
236 | } | ||||
237 | |||||
238 | static void | ||||
239 | add_module (CtkIMModule *module, GSList *infos) | ||||
240 | { | ||||
241 | GSList *tmp_list = infos; | ||||
242 | gint i = 0; | ||||
243 | gint n = g_slist_length (infos); | ||||
244 | module->contexts = g_new (CtkIMContextInfo *, n)((CtkIMContextInfo * *) g_malloc_n ((n), sizeof (CtkIMContextInfo *))); | ||||
245 | |||||
246 | while (tmp_list) | ||||
247 | { | ||||
248 | CtkIMContextInfo *info = tmp_list->data; | ||||
249 | |||||
250 | if (g_hash_table_lookup (contexts_hash, info->context_id)) | ||||
251 | { | ||||
252 | free_info (info); /* Duplicate */ | ||||
253 | } | ||||
254 | else | ||||
255 | { | ||||
256 | g_hash_table_insert (contexts_hash, (char *)info->context_id, module); | ||||
257 | module->contexts[i++] = tmp_list->data; | ||||
258 | n_loaded_contexts++; | ||||
259 | } | ||||
260 | |||||
261 | tmp_list = tmp_list->next; | ||||
262 | } | ||||
263 | g_slist_free (infos); | ||||
264 | module->n_contexts = i; | ||||
265 | |||||
266 | modules_list = g_slist_prepend (modules_list, module); | ||||
267 | } | ||||
268 | |||||
269 | #ifdef G_OS_WIN32 | ||||
270 | |||||
271 | static void | ||||
272 | correct_libdir_prefix (gchar **path) | ||||
273 | { | ||||
274 | /* CTK_LIBDIR is the build-time libdir */ | ||||
275 | if (strncmp (*path, CTK_LIBDIR"/usr/lib", strlen (CTK_LIBDIR"/usr/lib")) == 0) | ||||
276 | { | ||||
277 | /* This is an entry put there by make install on the | ||||
278 | * packager's system. On Windows a prebuilt CTK+ | ||||
279 | * package can be installed in a random | ||||
280 | * location. The ctk.immodules file distributed in | ||||
281 | * such a package contains paths from the package | ||||
282 | * builder's machine. Replace the path with the real | ||||
283 | * one on this machine. | ||||
284 | */ | ||||
285 | gchar *tem = *path; | ||||
286 | *path = g_strconcat (_ctk_get_libdir (), tem + strlen (CTK_LIBDIR"/usr/lib"), NULL((void*)0)); | ||||
287 | g_free (tem); | ||||
288 | } | ||||
289 | } | ||||
290 | |||||
291 | static void | ||||
292 | correct_localedir_prefix (gchar **path) | ||||
293 | { | ||||
294 | /* See above */ | ||||
295 | if (strncmp (*path, CTK_LOCALEDIR"/usr/share/locale", strlen (CTK_LOCALEDIR"/usr/share/locale")) == 0) | ||||
296 | { | ||||
297 | gchar *tem = *path; | ||||
298 | *path = g_strconcat (_ctk_get_localedir (), tem + strlen (CTK_LOCALEDIR"/usr/share/locale"), NULL((void*)0)); | ||||
299 | g_free (tem); | ||||
300 | } | ||||
301 | } | ||||
302 | #endif | ||||
303 | |||||
304 | |||||
305 | G_GNUC_UNUSED__attribute__ ((__unused__)) static CtkIMModule * | ||||
306 | add_builtin_module (const gchar *module_name, | ||||
307 | const CtkIMContextInfo **contexts, | ||||
308 | int n_contexts) | ||||
309 | { | ||||
310 | CtkIMModule *module = g_object_new (CTK_TYPE_IM_MODULE(ctk_im_module_get_type ()), NULL((void*)0)); | ||||
311 | GSList *infos = NULL((void*)0); | ||||
312 | int i; | ||||
313 | |||||
314 | for (i = 0; i < n_contexts; i++) | ||||
315 | { | ||||
316 | CtkIMContextInfo *info = g_new (CtkIMContextInfo, 1)((CtkIMContextInfo *) g_malloc_n ((1), sizeof (CtkIMContextInfo ))); | ||||
317 | info->context_id = g_strdup (contexts[i]->context_id)g_strdup_inline (contexts[i]->context_id); | ||||
318 | info->context_name = g_strdup (contexts[i]->context_name)g_strdup_inline (contexts[i]->context_name); | ||||
319 | info->domain = g_strdup (contexts[i]->domain)g_strdup_inline (contexts[i]->domain); | ||||
320 | info->domain_dirname = g_strdup (contexts[i]->domain_dirname)g_strdup_inline (contexts[i]->domain_dirname); | ||||
321 | #ifdef G_OS_WIN32 | ||||
322 | correct_localedir_prefix ((char **) &info->domain_dirname); | ||||
323 | #endif | ||||
324 | info->default_locales = g_strdup (contexts[i]->default_locales)g_strdup_inline (contexts[i]->default_locales); | ||||
325 | infos = g_slist_prepend (infos, info); | ||||
326 | } | ||||
327 | |||||
328 | module->builtin = TRUE(!(0)); | ||||
329 | g_type_module_set_name (G_TYPE_MODULE (module)((((GTypeModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((module)), ((g_type_module_get_type ())))))), module_name); | ||||
330 | add_module (module, infos); | ||||
331 | |||||
332 | return module; | ||||
333 | } | ||||
334 | |||||
335 | static void | ||||
336 | ctk_im_module_initialize (void) | ||||
337 | { | ||||
338 | GString *line_buf = g_string_new (NULL((void*)0)); | ||||
339 | GString *tmp_buf = g_string_new (NULL((void*)0)); | ||||
340 | gchar *filename = ctk_rc_get_im_module_file(); | ||||
341 | FILE *file; | ||||
342 | gboolean have_error = FALSE(0); | ||||
343 | |||||
344 | CtkIMModule *module = NULL((void*)0); | ||||
345 | GSList *infos = NULL((void*)0); | ||||
346 | |||||
347 | contexts_hash = g_hash_table_new (g_str_hash, g_str_equal); | ||||
348 | |||||
349 | #define do_builtin(m) \ | ||||
350 | { \ | ||||
351 | const CtkIMContextInfo **contexts; \ | ||||
352 | int n_contexts; \ | ||||
353 | extern void _ctk_immodule_ ## m ## _list (const CtkIMContextInfo ***contexts, \ | ||||
354 | int *n_contexts); \ | ||||
355 | extern void _ctk_immodule_ ## m ## _init (GTypeModule *module); \ | ||||
356 | extern void _ctk_immodule_ ## m ## _exit (void); \ | ||||
357 | extern CtkIMContext *_ctk_immodule_ ## m ## _create (const gchar *context_id); \ | ||||
358 | \ | ||||
359 | _ctk_immodule_ ## m ## _list (&contexts, &n_contexts); \ | ||||
360 | module = add_builtin_module (#m, contexts, n_contexts); \ | ||||
361 | module->init = _ctk_immodule_ ## m ## _init; \ | ||||
362 | module->exit = _ctk_immodule_ ## m ## _exit; \ | ||||
363 | module->create = _ctk_immodule_ ## m ## _create; \ | ||||
364 | module = NULL((void*)0); \ | ||||
365 | } | ||||
366 | |||||
367 | #ifdef INCLUDE_IM_am_et | ||||
368 | do_builtin (am_et); | ||||
369 | #endif | ||||
370 | #ifdef INCLUDE_IM_cedilla | ||||
371 | do_builtin (cedilla); | ||||
372 | #endif | ||||
373 | #ifdef INCLUDE_IM_cyrillic_translit | ||||
374 | do_builtin (cyrillic_translit); | ||||
375 | #endif | ||||
376 | #ifdef INCLUDE_IM_ime | ||||
377 | do_builtin (ime); | ||||
378 | #endif | ||||
379 | #ifdef INCLUDE_IM_inuktitut | ||||
380 | do_builtin (inuktitut); | ||||
381 | #endif | ||||
382 | #ifdef INCLUDE_IM_ipa | ||||
383 | do_builtin (ipa); | ||||
384 | #endif | ||||
385 | #ifdef INCLUDE_IM_multipress | ||||
386 | do_builtin (multipress); | ||||
387 | #endif | ||||
388 | #ifdef INCLUDE_IM_thai | ||||
389 | do_builtin (thai); | ||||
390 | #endif | ||||
391 | #ifdef INCLUDE_IM_ti_er | ||||
392 | do_builtin (ti_er); | ||||
393 | #endif | ||||
394 | #ifdef INCLUDE_IM_ti_et | ||||
395 | do_builtin (ti_et); | ||||
396 | #endif | ||||
397 | #ifdef INCLUDE_IM_viqr | ||||
398 | do_builtin (viqr); | ||||
399 | #endif | ||||
400 | #ifdef INCLUDE_IM_xim | ||||
401 | do_builtin (xim); | ||||
402 | #endif | ||||
403 | #ifdef INCLUDE_IM_broadway | ||||
404 | do_builtin (broadway); | ||||
405 | #endif | ||||
406 | #ifdef INCLUDE_IM_wayland | ||||
407 | do_builtin (wayland); | ||||
408 | #endif | ||||
409 | |||||
410 | #undef do_builtin | ||||
411 | |||||
412 | file = g_fopenfopen (filename, "r"); | ||||
413 | if (!file
| ||||
414 | { | ||||
415 | /* In case someone wants only the default input method, | ||||
416 | * we allow no file at all. | ||||
417 | */ | ||||
418 | g_string_free (line_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (line_buf), ((!(0)))) : g_string_free_and_steal (line_buf)) : (g_string_free) ((line_buf), ((!(0))))); | ||||
419 | g_string_free (tmp_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (tmp_buf), ((!(0)))) : g_string_free_and_steal (tmp_buf)) : ( g_string_free) ((tmp_buf), ((!(0))))); | ||||
420 | g_free (filename); | ||||
421 | return; | ||||
422 | } | ||||
423 | |||||
424 | while (!have_error
| ||||
425 | { | ||||
426 | const char *p; | ||||
427 | |||||
428 | p = line_buf->str; | ||||
429 | |||||
430 | if (!ctk_skip_space (&p)) | ||||
431 | { | ||||
432 | /* Blank line marking the end of a module | ||||
433 | */ | ||||
434 | if (module && *p != '#') | ||||
435 | { | ||||
436 | add_module (module, infos); | ||||
437 | module = NULL((void*)0); | ||||
438 | infos = NULL((void*)0); | ||||
439 | } | ||||
440 | |||||
441 | continue; | ||||
442 | } | ||||
443 | |||||
444 | if (!module
| ||||
445 | { | ||||
446 | /* Read a module location | ||||
447 | */ | ||||
448 | module = g_object_new (CTK_TYPE_IM_MODULE(ctk_im_module_get_type ()), NULL((void*)0)); | ||||
449 | |||||
450 | if (!ctk_scan_string (&p, tmp_buf) || ctk_skip_space (&p)) | ||||
451 | { | ||||
452 | g_warning ("Error parsing context info in '%s'\n %s", filename, line_buf->str); | ||||
453 | have_error = TRUE(!(0)); | ||||
454 | } | ||||
455 | |||||
456 | module->path = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str); | ||||
457 | #ifdef G_OS_WIN32 | ||||
458 | correct_libdir_prefix (&module->path); | ||||
459 | #endif | ||||
460 | g_type_module_set_name (G_TYPE_MODULE (module)((((GTypeModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((module)), ((g_type_module_get_type ())))))), module->path); | ||||
461 | } | ||||
462 | else | ||||
463 | { | ||||
464 | CtkIMContextInfo *info = g_new0 (CtkIMContextInfo, 1)((CtkIMContextInfo *) g_malloc0_n ((1), sizeof (CtkIMContextInfo ))); | ||||
465 | |||||
466 | /* Read information about a context type | ||||
467 | */ | ||||
468 | if (!ctk_scan_string (&p, tmp_buf)) | ||||
469 | goto context_error; | ||||
470 | info->context_id = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str); | ||||
471 | |||||
472 | if (!ctk_scan_string (&p, tmp_buf)) | ||||
473 | goto context_error; | ||||
474 | info->context_name = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str); | ||||
475 | |||||
476 | if (!ctk_scan_string (&p, tmp_buf)) | ||||
477 | goto context_error; | ||||
478 | info->domain = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str); | ||||
479 | |||||
480 | if (!ctk_scan_string (&p, tmp_buf)) | ||||
481 | goto context_error; | ||||
482 | |||||
483 | info->domain_dirname = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str); | ||||
484 | #ifdef G_OS_WIN32 | ||||
485 | correct_localedir_prefix ((char **) &info->domain_dirname); | ||||
486 | #endif | ||||
487 | |||||
488 | if (!ctk_scan_string (&p, tmp_buf)) | ||||
489 | goto context_error; | ||||
490 | info->default_locales = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str); | ||||
491 | |||||
492 | if (ctk_skip_space (&p)) | ||||
493 | goto context_error; | ||||
494 | |||||
495 | infos = g_slist_prepend (infos, info); | ||||
496 | continue; | ||||
497 | |||||
498 | context_error: | ||||
499 | g_warning ("Error parsing context info in '%s'\n %s", filename, line_buf->str); | ||||
| |||||
500 | have_error = TRUE(!(0)); | ||||
501 | } | ||||
502 | } | ||||
503 | |||||
504 | if (have_error) | ||||
505 | { | ||||
506 | g_slist_free_full (infos, (GDestroyNotify)free_info); | ||||
507 | g_object_unref (module); | ||||
508 | } | ||||
509 | else if (module) | ||||
510 | add_module (module, infos); | ||||
511 | |||||
512 | fclose (file); | ||||
513 | g_string_free (line_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (line_buf), ((!(0)))) : g_string_free_and_steal (line_buf)) : (g_string_free) ((line_buf), ((!(0))))); | ||||
514 | g_string_free (tmp_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (tmp_buf), ((!(0)))) : g_string_free_and_steal (tmp_buf)) : ( g_string_free) ((tmp_buf), ((!(0))))); | ||||
515 | g_free (filename); | ||||
516 | } | ||||
517 | |||||
518 | static gint | ||||
519 | compare_ctkimcontextinfo_name (const CtkIMContextInfo **a, | ||||
520 | const CtkIMContextInfo **b) | ||||
521 | { | ||||
522 | return g_utf8_collate ((*a)->context_name, (*b)->context_name); | ||||
523 | } | ||||
524 | |||||
525 | /** | ||||
526 | * _ctk_im_module_list: | ||||
527 | * @contexts: location to store an array of pointers to #CtkIMContextInfo | ||||
528 | * this array should be freed with g_free() when you are finished. | ||||
529 | * The structures it points are statically allocated and should | ||||
530 | * not be modified or freed. | ||||
531 | * @n_contexts: the length of the array stored in @contexts | ||||
532 | * | ||||
533 | * List all available types of input method context | ||||
534 | */ | ||||
535 | void | ||||
536 | _ctk_im_module_list (const CtkIMContextInfo ***contexts, | ||||
537 | guint *n_contexts) | ||||
538 | { | ||||
539 | int n = 0; | ||||
540 | |||||
541 | static | ||||
542 | #ifndef G_OS_WIN32 | ||||
543 | const | ||||
544 | #endif | ||||
545 | CtkIMContextInfo simple_context_info = { | ||||
546 | SIMPLE_ID"ctk-im-context-simple", | ||||
547 | NC_("input method menu", "Simple")("Simple"), | ||||
548 | GETTEXT_PACKAGE"ctk30", | ||||
549 | #ifdef CTK_LOCALEDIR"/usr/share/locale" | ||||
550 | CTK_LOCALEDIR"/usr/share/locale", | ||||
551 | #else | ||||
552 | "", | ||||
553 | #endif | ||||
554 | "" | ||||
555 | }; | ||||
556 | |||||
557 | static | ||||
558 | #ifndef G_OS_WIN32 | ||||
559 | const | ||||
560 | #endif | ||||
561 | CtkIMContextInfo none_context_info = { | ||||
562 | NONE_ID"ctk-im-context-none", | ||||
563 | NC_("input method menu", "None")("None"), | ||||
564 | GETTEXT_PACKAGE"ctk30", | ||||
565 | #ifdef CTK_LOCALEDIR"/usr/share/locale" | ||||
566 | CTK_LOCALEDIR"/usr/share/locale", | ||||
567 | #else | ||||
568 | "", | ||||
569 | #endif | ||||
570 | "" | ||||
571 | }; | ||||
572 | |||||
573 | #ifdef G_OS_WIN32 | ||||
574 | static gboolean beenhere = FALSE(0); | ||||
575 | #endif | ||||
576 | |||||
577 | if (!contexts_hash) | ||||
578 | ctk_im_module_initialize (); | ||||
579 | |||||
580 | #ifdef G_OS_WIN32 | ||||
581 | if (!beenhere) | ||||
582 | { | ||||
583 | beenhere = TRUE(!(0)); | ||||
584 | /* correct_localedir_prefix() requires its parameter to be a | ||||
585 | * malloced string | ||||
586 | */ | ||||
587 | simple_context_info.domain_dirname = g_strdup (simple_context_info.domain_dirname)g_strdup_inline (simple_context_info.domain_dirname); | ||||
588 | correct_localedir_prefix ((char **) &simple_context_info.domain_dirname); | ||||
589 | none_context_info.domain_dirname = g_strdup (none_context_info.domain_dirname)g_strdup_inline (none_context_info.domain_dirname); | ||||
590 | correct_localedir_prefix ((char **) &none_context_info.domain_dirname); | ||||
591 | } | ||||
592 | #endif | ||||
593 | |||||
594 | if (n_contexts) | ||||
595 | *n_contexts = n_loaded_contexts + 2; | ||||
596 | |||||
597 | if (contexts) | ||||
598 | { | ||||
599 | GSList *tmp_list; | ||||
600 | int i; | ||||
601 | |||||
602 | *contexts = g_new (const CtkIMContextInfo *, n_loaded_contexts + 2)((const CtkIMContextInfo * *) g_malloc_n ((n_loaded_contexts + 2), sizeof (const CtkIMContextInfo *))); | ||||
603 | |||||
604 | (*contexts)[n++] = &none_context_info; | ||||
605 | (*contexts)[n++] = &simple_context_info; | ||||
606 | |||||
607 | tmp_list = modules_list; | ||||
608 | while (tmp_list) | ||||
609 | { | ||||
610 | CtkIMModule *module = tmp_list->data; | ||||
611 | |||||
612 | for (i=0; i<module->n_contexts; i++) | ||||
613 | (*contexts)[n++] = module->contexts[i]; | ||||
614 | |||||
615 | tmp_list = tmp_list->next; | ||||
616 | } | ||||
617 | |||||
618 | /* first elements (Simple and None) should always be at top */ | ||||
619 | qsort ((*contexts)+2, n-2, sizeof (CtkIMContextInfo *), (GCompareFunc)compare_ctkimcontextinfo_name); | ||||
620 | } | ||||
621 | } | ||||
622 | |||||
623 | /** | ||||
624 | * _ctk_im_module_create: | ||||
625 | * @context_id: the context ID for the context type to create | ||||
626 | * | ||||
627 | * Create an IM context of a type specified by the string | ||||
628 | * ID @context_id. | ||||
629 | * | ||||
630 | * Returns: a newly created input context of or @context_id, or | ||||
631 | * if that could not be created, a newly created CtkIMContextSimple. | ||||
632 | */ | ||||
633 | CtkIMContext * | ||||
634 | _ctk_im_module_create (const gchar *context_id) | ||||
635 | { | ||||
636 | CtkIMModule *im_module; | ||||
637 | CtkIMContext *context = NULL((void*)0); | ||||
638 | |||||
639 | if (strcmp (context_id, NONE_ID"ctk-im-context-none") == 0) | ||||
640 | return NULL((void*)0); | ||||
641 | |||||
642 | if (!contexts_hash) | ||||
643 | ctk_im_module_initialize (); | ||||
644 | |||||
645 | if (strcmp (context_id, SIMPLE_ID"ctk-im-context-simple") != 0) | ||||
646 | { | ||||
647 | im_module = g_hash_table_lookup (contexts_hash, context_id); | ||||
648 | if (!im_module) | ||||
649 | { | ||||
650 | g_warning ("Attempt to load unknown IM context type '%s'", context_id); | ||||
651 | } | ||||
652 | else | ||||
653 | { | ||||
654 | if (g_type_module_use (G_TYPE_MODULE (im_module)((((GTypeModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((im_module)), ((g_type_module_get_type ())))))))) | ||||
655 | { | ||||
656 | context = im_module->create (context_id); | ||||
657 | g_type_module_unuse (G_TYPE_MODULE (im_module)((((GTypeModule*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((im_module)), ((g_type_module_get_type ()))))))); | ||||
658 | } | ||||
659 | |||||
660 | if (!context) | ||||
661 | g_warning ("Loading IM context type '%s' failed", context_id); | ||||
662 | } | ||||
663 | } | ||||
664 | |||||
665 | if (!context) | ||||
666 | return ctk_im_context_simple_new (); | ||||
667 | else | ||||
668 | return context; | ||||
669 | } | ||||
670 | |||||
671 | /* Match @locale against @against. | ||||
672 | * | ||||
673 | * 'en_US' against “en_US” => 4 | ||||
674 | * 'en_US' against “en” => 3 | ||||
675 | * 'en', “en_UK” against “en_US” => 2 | ||||
676 | * all locales, against “*” => 1 | ||||
677 | */ | ||||
678 | static gint | ||||
679 | match_locale (const gchar *locale, | ||||
680 | const gchar *against, | ||||
681 | gint against_len) | ||||
682 | { | ||||
683 | if (strcmp (against, "*") == 0) | ||||
684 | return 1; | ||||
685 | |||||
686 | if (g_ascii_strcasecmp (locale, against) == 0) | ||||
687 | return 4; | ||||
688 | |||||
689 | if (g_ascii_strncasecmp (locale, against, 2) == 0) | ||||
690 | return (against_len == 2) ? 3 : 2; | ||||
691 | |||||
692 | return 0; | ||||
693 | } | ||||
694 | |||||
695 | static gboolean | ||||
696 | match_backend (CtkIMContextInfo *context) | ||||
697 | { | ||||
698 | #ifdef CDK_WINDOWING_WAYLAND | ||||
699 | if (g_strcmp0 (context->context_id, "wayland") == 0) | ||||
700 | { | ||||
701 | CdkDisplay *display = cdk_display_get_default (); | ||||
702 | |||||
703 | return CDK_IS_WAYLAND_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (display)); GType __t = ((cdk_wayland_display_get_type())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))) && | ||||
704 | cdk_wayland_display_query_registry (display, | ||||
705 | "zwp_text_input_manager_v3"); | ||||
706 | } | ||||
707 | if (g_strcmp0 (context->context_id, "waylandctk") == 0) | ||||
708 | { | ||||
709 | CdkDisplay *display = cdk_display_get_default (); | ||||
710 | |||||
711 | return CDK_IS_WAYLAND_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (display)); GType __t = ((cdk_wayland_display_get_type())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))) && | ||||
712 | cdk_wayland_display_query_registry (display, | ||||
713 | "ctk_text_input_manager"); | ||||
714 | } | ||||
715 | #endif | ||||
716 | |||||
717 | #ifdef CDK_WINDOWING_BROADWAY | ||||
718 | if (g_strcmp0 (context->context_id, "broadway") == 0) | ||||
719 | return CDK_IS_BROADWAY_DISPLAY (cdk_display_get_default ())(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (cdk_display_get_default ())); GType __t = ((cdk_broadway_display_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))); | ||||
720 | #endif | ||||
721 | |||||
722 | #ifdef CDK_WINDOWING_X11 | ||||
723 | if (g_strcmp0 (context->context_id, "xim") == 0) | ||||
724 | return CDK_IS_X11_DISPLAY (cdk_display_get_default ())(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (cdk_display_get_default ())); GType __t = ((cdk_x11_display_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))); | ||||
725 | #endif | ||||
726 | |||||
727 | #ifdef CDK_WINDOWING_WIN32 | ||||
728 | if (g_strcmp0 (context->context_id, "ime") == 0) | ||||
729 | return CDK_IS_WIN32_DISPLAY (cdk_display_get_default ()); | ||||
730 | #endif | ||||
731 | |||||
732 | return TRUE(!(0)); | ||||
733 | } | ||||
734 | |||||
735 | static const gchar * | ||||
736 | lookup_immodule (gchar **immodules_list) | ||||
737 | { | ||||
738 | while (immodules_list && *immodules_list) | ||||
739 | { | ||||
740 | if (g_strcmp0 (*immodules_list, SIMPLE_ID"ctk-im-context-simple") == 0) | ||||
741 | return SIMPLE_ID"ctk-im-context-simple"; | ||||
742 | else if (g_strcmp0 (*immodules_list, NONE_ID"ctk-im-context-none") == 0) | ||||
743 | return NONE_ID"ctk-im-context-none"; | ||||
744 | else | ||||
745 | { | ||||
746 | gboolean found; | ||||
747 | gchar *context_id; | ||||
748 | found = g_hash_table_lookup_extended (contexts_hash, *immodules_list, | ||||
749 | (gpointer *) &context_id, NULL((void*)0)); | ||||
750 | if (found) | ||||
751 | return context_id; | ||||
752 | } | ||||
753 | immodules_list++; | ||||
754 | } | ||||
755 | |||||
756 | return NULL((void*)0); | ||||
757 | } | ||||
758 | |||||
759 | #ifdef G_OS_WIN32 | ||||
760 | |||||
761 | /* max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9 */ | ||||
762 | #define MAX_NAME_SIZE 9 | ||||
763 | |||||
764 | static gchar * | ||||
765 | get_current_input_language (void) | ||||
766 | { | ||||
767 | LCID lcid; | ||||
768 | LANGID langid; | ||||
769 | HKL kblayout; | ||||
770 | int name_size; | ||||
771 | wchar_t name[MAX_NAME_SIZE]; | ||||
772 | gchar *language; | ||||
773 | gchar *country; | ||||
774 | gchar *full; | ||||
775 | |||||
776 | /* Current thread's keyboard layout */ | ||||
777 | kblayout = GetKeyboardLayout(0); | ||||
778 | /* lowest word in the HKL is the LANGID */ | ||||
779 | langid = LOWORD (kblayout); | ||||
780 | /* LCID is the LANGID without order */ | ||||
781 | lcid = langid; | ||||
782 | |||||
783 | /* Get Language ID */ | ||||
784 | name_size = GetLocaleInfoW (lcid, LOCALE_SISO639LANGNAME, NULL((void*)0), 0); | ||||
785 | if (name_size <= 1) | ||||
786 | return NULL((void*)0); | ||||
787 | |||||
788 | g_assert (name_size <= MAX_NAME_SIZE)do { if (name_size <= MAX_NAME_SIZE) ; else g_assertion_message_expr ("Ctk", "ctkimmodule.c", 788, ((const char*) (__func__)), "name_size <= MAX_NAME_SIZE" ); } while (0); | ||||
789 | GetLocaleInfoW (lcid, LOCALE_SISO639LANGNAME, name, name_size); | ||||
790 | |||||
791 | language = g_utf16_to_utf8 (name, name_size, NULL((void*)0), NULL((void*)0), NULL((void*)0)); | ||||
792 | if (!language) | ||||
793 | return NULL((void*)0); | ||||
794 | |||||
795 | if (SUBLANGID (langid) == SUBLANG_NEUTRAL) | ||||
796 | return language; | ||||
797 | |||||
798 | /* Get Country ID */ | ||||
799 | name_size = GetLocaleInfoW (lcid, LOCALE_SISO3166CTRYNAME, NULL((void*)0), 0); | ||||
800 | if (name_size <= 1) | ||||
801 | return language; | ||||
802 | |||||
803 | g_assert (name_size <= MAX_NAME_SIZE)do { if (name_size <= MAX_NAME_SIZE) ; else g_assertion_message_expr ("Ctk", "ctkimmodule.c", 803, ((const char*) (__func__)), "name_size <= MAX_NAME_SIZE" ); } while (0); | ||||
804 | GetLocaleInfoW (lcid, LOCALE_SISO3166CTRYNAME, name, name_size); | ||||
805 | |||||
806 | country = g_utf16_to_utf8 (name, name_size, NULL((void*)0), NULL((void*)0), NULL((void*)0)); | ||||
807 | if (!country) | ||||
808 | return language; | ||||
809 | |||||
810 | full = g_strdup_printf ("%s_%s", language, country); | ||||
811 | |||||
812 | g_free (language); | ||||
813 | g_free (country); | ||||
814 | |||||
815 | return full; | ||||
816 | } | ||||
817 | |||||
818 | #endif | ||||
819 | |||||
820 | /** | ||||
821 | * _ctk_im_module_get_default_context_id: | ||||
822 | * | ||||
823 | * Return the context_id of the best IM context type | ||||
824 | * for the given window. | ||||
825 | * | ||||
826 | * Returns: the context ID (will never be %NULL) | ||||
827 | */ | ||||
828 | const gchar * | ||||
829 | _ctk_im_module_get_default_context_id (void) | ||||
830 | { | ||||
831 | GSList *tmp_list; | ||||
832 | const gchar *context_id = NULL((void*)0); | ||||
833 | gint best_goodness = 0; | ||||
834 | gint i; | ||||
835 | gchar *tmp_locale, *tmp, **immodules; | ||||
836 | const gchar *envvar; | ||||
837 | CdkScreen *screen; | ||||
838 | CtkSettings *settings; | ||||
839 | |||||
840 | if (!contexts_hash) | ||||
| |||||
841 | ctk_im_module_initialize (); | ||||
842 | |||||
843 | envvar = g_getenv ("CTK_IM_MODULE"); | ||||
844 | if (envvar) | ||||
845 | { | ||||
846 | immodules = g_strsplit (envvar, ":", 0); | ||||
847 | context_id = lookup_immodule (immodules); | ||||
848 | g_strfreev (immodules); | ||||
849 | |||||
850 | if (context_id) | ||||
851 | return context_id; | ||||
852 | } | ||||
853 | |||||
854 | /* Check if the certain immodule is set in XSETTINGS. | ||||
855 | */ | ||||
856 | screen = cdk_screen_get_default (); | ||||
857 | settings = ctk_settings_get_for_screen (screen); | ||||
858 | g_object_get (G_OBJECT (settings)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((settings)), (((GType) ((20) << (2)))))))), "ctk-im-module", &tmp, NULL((void*)0)); | ||||
859 | if (tmp) | ||||
860 | { | ||||
861 | immodules = g_strsplit (tmp, ":", 0); | ||||
862 | context_id = lookup_immodule (immodules); | ||||
863 | g_strfreev (immodules); | ||||
864 | g_free (tmp); | ||||
865 | |||||
866 | if (context_id) | ||||
867 | return context_id; | ||||
868 | } | ||||
869 | |||||
870 | #ifdef G_OS_WIN32 | ||||
871 | /* Read current input locale from the current keyboard info */ | ||||
872 | tmp_locale = get_current_input_language (); | ||||
873 | if (!tmp_locale) | ||||
874 | /* Default to system locale when input language is unknown */ | ||||
875 | tmp_locale = _ctk_get_lc_ctype (); | ||||
876 | #else | ||||
877 | tmp_locale = _ctk_get_lc_ctype (); | ||||
878 | #endif | ||||
879 | |||||
880 | /* Strip the locale code down to the essentials | ||||
881 | */ | ||||
882 | tmp = strchr (tmp_locale, '.'); | ||||
883 | if (tmp) | ||||
884 | *tmp = '\0'; | ||||
885 | tmp = strchr (tmp_locale, '@'); | ||||
886 | if (tmp) | ||||
887 | *tmp = '\0'; | ||||
888 | |||||
889 | tmp_list = modules_list; | ||||
890 | while (tmp_list) | ||||
891 | { | ||||
892 | CtkIMModule *module = tmp_list->data; | ||||
893 | |||||
894 | for (i = 0; i < module->n_contexts; i++) | ||||
895 | { | ||||
896 | const gchar *p; | ||||
897 | |||||
898 | if (!match_backend (module->contexts[i])) | ||||
899 | continue; | ||||
900 | |||||
901 | p = module->contexts[i]->default_locales; | ||||
902 | while (p) | ||||
903 | { | ||||
904 | const gchar *q = strchr (p, ':'); | ||||
905 | gint goodness = match_locale (tmp_locale, p, q ? q - p : strlen (p)); | ||||
906 | |||||
907 | if (goodness > best_goodness) | ||||
908 | { | ||||
909 | context_id = module->contexts[i]->context_id; | ||||
910 | best_goodness = goodness; | ||||
911 | } | ||||
912 | |||||
913 | p = q ? q + 1 : NULL((void*)0); | ||||
914 | } | ||||
915 | } | ||||
916 | |||||
917 | tmp_list = tmp_list->next; | ||||
918 | } | ||||
919 | |||||
920 | g_free (tmp_locale); | ||||
921 | |||||
922 | return context_id ? context_id : SIMPLE_ID"ctk-im-context-simple"; | ||||
923 | } |