1 /* GTK - 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 GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25 #include "config.h"
26
27 #include <errno.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 "gtkimmodule.h"
35 #include "gtkimmoduleprivate.h"
36 #include "gtkimcontextsimple.h"
37 #include "gtkmodulesprivate.h"
38 #include "gtksettings.h"
39 #include "gtkprivate.h"
40 #include "gtkintl.h"
41
42 #ifdef GDK_WINDOWING_X11
43 #include "x11/gdkx.h"
44 #endif
45
46 #ifdef GDK_WINDOWING_WAYLAND
47 #include "wayland/gdkwayland.h"
48 #include "gtkimcontextwayland.h"
49 #endif
50
51 #ifdef GDK_WINDOWING_BROADWAY
52 #include "broadway/gdkbroadway.h"
53 #include "gtkimcontextbroadway.h"
54 #endif
55
56 #ifdef GDK_WINDOWING_WIN32
57 #include "win32/gdkwin32.h"
58 #include "gtkimcontextime.h"
59 #endif
60
61 #ifdef GDK_WINDOWING_MACOS
62 #include "macos/gdkmacos.h"
63 #include "gtkimcontextquartz.h"
64 #endif
65
66 #ifdef G_OS_WIN32
67 #include <windows.h>
68 #endif
69
70 #define SIMPLE_ID "gtk-im-context-simple"
71 #define NONE_ID "gtk-im-context-none"
72
73 /**
74 * _gtk_im_module_create:
75 * @context_id: the context ID for the context type to create
76 *
77 * Create an IM context of a type specified by the string
78 * ID @context_id.
79 *
80 * Returns: a newly created input context of or @context_id, or
81 * if that could not be created, a newly created `GtkIMContextSimple`
82 */
83 GtkIMContext *
_gtk_im_module_create(const char * context_id)84 _gtk_im_module_create (const char *context_id)
85 {
86 GIOExtensionPoint *ep;
87 GIOExtension *ext;
88 GType type;
89 GtkIMContext *context = NULL;
90
91 if (strcmp (context_id, NONE_ID) == 0)
92 return NULL;
93
94 ep = g_io_extension_point_lookup (GTK_IM_MODULE_EXTENSION_POINT_NAME);
95 ext = g_io_extension_point_get_extension_by_name (ep, context_id);
96 if (ext)
97 {
98 type = g_io_extension_get_type (ext);
99 context = g_object_new (type, NULL);
100 }
101
102 return context;
103 }
104
105 static gboolean
match_backend(GdkDisplay * display,const char * context_id)106 match_backend (GdkDisplay *display,
107 const char *context_id)
108 {
109 if (g_strcmp0 (context_id, "wayland") == 0)
110 {
111 #ifdef GDK_WINDOWING_WAYLAND
112 return GDK_IS_WAYLAND_DISPLAY (display) &&
113 gdk_wayland_display_query_registry (display,
114 "zwp_text_input_manager_v3");
115 #else
116 return FALSE;
117 #endif
118 }
119
120 if (g_strcmp0 (context_id, "broadway") == 0)
121 #ifdef GDK_WINDOWING_BROADWAY
122 return GDK_IS_BROADWAY_DISPLAY (display);
123 #else
124 return FALSE;
125 #endif
126
127 if (g_strcmp0 (context_id, "ime") == 0)
128 #ifdef GDK_WINDOWING_WIN32
129 return GDK_IS_WIN32_DISPLAY (display);
130 #else
131 return FALSE;
132 #endif
133
134 if (g_strcmp0 (context_id, "quartz") == 0)
135 #ifdef GDK_WINDOWING_MACOS
136 return GDK_IS_MACOS_DISPLAY (display);
137 #else
138 return FALSE;
139 #endif
140
141 return TRUE;
142 }
143
144 static const char *
lookup_immodule(GdkDisplay * display,char ** immodules_list)145 lookup_immodule (GdkDisplay *display,
146 char **immodules_list)
147 {
148 guint i;
149
150 for (i = 0; immodules_list[i]; i++)
151 {
152 if (!match_backend (display, immodules_list[i]))
153 continue;
154
155 if (g_strcmp0 (immodules_list[i], SIMPLE_ID) == 0)
156 return SIMPLE_ID;
157 else if (g_strcmp0 (immodules_list[i], NONE_ID) == 0)
158 return NONE_ID;
159 else
160 {
161 GIOExtensionPoint *ep;
162 GIOExtension *ext;
163
164 ep = g_io_extension_point_lookup (GTK_IM_MODULE_EXTENSION_POINT_NAME);
165 ext = g_io_extension_point_get_extension_by_name (ep, immodules_list[i]);
166 if (ext)
167 return g_io_extension_get_name (ext);
168 }
169 }
170
171 return NULL;
172 }
173
174 /**
175 * _gtk_im_module_get_default_context_id:
176 * @display: The display to look up the module for
177 *
178 * Return the context_id of the best IM context type
179 * for the given window.
180 *
181 * Returns: the context ID (will never be %NULL)
182 */
183 const char *
_gtk_im_module_get_default_context_id(GdkDisplay * display)184 _gtk_im_module_get_default_context_id (GdkDisplay *display)
185 {
186 const char *context_id = NULL;
187 const char *envvar;
188 GtkSettings *settings;
189 GIOExtensionPoint *ep;
190 GList *l;
191 char *tmp;
192
193 envvar = g_getenv ("GTK_IM_MODULE");
194 if (envvar)
195 {
196 char **immodules;
197 immodules = g_strsplit (envvar, ":", 0);
198 context_id = lookup_immodule (display, immodules);
199 g_strfreev (immodules);
200
201 if (context_id)
202 return context_id;
203 }
204
205 /* Check if the certain immodule is set in XSETTINGS. */
206 settings = gtk_settings_get_for_display (display);
207 g_object_get (G_OBJECT (settings), "gtk-im-module", &tmp, NULL);
208 if (tmp)
209 {
210 char **immodules;
211
212 immodules = g_strsplit (tmp, ":", 0);
213 context_id = lookup_immodule (display, immodules);
214 g_strfreev (immodules);
215 g_free (tmp);
216
217 if (context_id)
218 return context_id;
219 }
220
221 ep = g_io_extension_point_lookup (GTK_IM_MODULE_EXTENSION_POINT_NAME);
222 for (l = g_io_extension_point_get_extensions (ep); l; l = l->next)
223 {
224 GIOExtension *ext = l->data;
225
226 context_id = g_io_extension_get_name (ext);
227 if (match_backend (display, context_id))
228 return context_id;
229 }
230
231 g_error ("GTK was run without any IM module being present. This must not happen.");
232
233 return SIMPLE_ID;
234 }
235
236 void
gtk_im_module_ensure_extension_point(void)237 gtk_im_module_ensure_extension_point (void)
238 {
239 GIOExtensionPoint *ep;
240 static gboolean registered = FALSE;
241
242 if (registered)
243 return;
244
245 GTK_NOTE (MODULES,
246 g_print ("Registering extension point %s\n", GTK_IM_MODULE_EXTENSION_POINT_NAME));
247
248 ep = g_io_extension_point_register (GTK_IM_MODULE_EXTENSION_POINT_NAME);
249 g_io_extension_point_set_required_type (ep, GTK_TYPE_IM_CONTEXT);
250
251 registered = TRUE;
252 }
253
254 void
gtk_im_modules_init(void)255 gtk_im_modules_init (void)
256 {
257 GIOModuleScope *scope;
258 char **paths;
259 int i;
260
261 gtk_im_module_ensure_extension_point ();
262
263 g_type_ensure (gtk_im_context_simple_get_type ());
264 #ifdef GDK_WINDOWING_WAYLAND
265 g_type_ensure (gtk_im_context_wayland_get_type ());
266 #endif
267 #ifdef GDK_WINDOWING_BROADWAY
268 g_type_ensure (gtk_im_context_broadway_get_type ());
269 #endif
270 #ifdef GDK_WINDOWING_WIN32
271 g_type_ensure (gtk_im_context_ime_get_type ());
272 #endif
273 #ifdef GDK_WINDOWING_MACOS
274 g_type_ensure (gtk_im_context_quartz_get_type ());
275 #endif
276
277 scope = g_io_module_scope_new (G_IO_MODULE_SCOPE_BLOCK_DUPLICATES);
278
279 paths = _gtk_get_module_path ("immodules");
280 for (i = 0; paths[i]; i++)
281 {
282 GTK_NOTE (MODULES,
283 g_print ("Scanning io modules in %s\n", paths[i]));
284 g_io_modules_scan_all_in_directory_with_scope (paths[i], scope);
285 }
286 g_strfreev (paths);
287
288 g_io_module_scope_free (scope);
289
290 if (GTK_DEBUG_CHECK (MODULES))
291 {
292 GIOExtensionPoint *ep;
293 GList *list, *l;
294
295 ep = g_io_extension_point_lookup (GTK_IM_MODULE_EXTENSION_POINT_NAME);
296 list = g_io_extension_point_get_extensions (ep);
297 for (l = list; l; l = l->next)
298 {
299 GIOExtension *ext = l->data;
300 g_print ("extension: %s: type %s\n",
301 g_io_extension_get_name (ext),
302 g_type_name (g_io_extension_get_type (ext)));
303 }
304 }
305 }
306