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 * |
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 (s1: 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 (extension_point: ep, name: context_id); |
96 | if (ext) |
97 | { |
98 | type = g_io_extension_get_type (extension: ext); |
99 | context = g_object_new (object_type: type, NULL); |
100 | } |
101 | |
102 | return context; |
103 | } |
104 | |
105 | static gboolean |
106 | match_backend (GdkDisplay *display, |
107 | const char *context_id) |
108 | { |
109 | if (g_strcmp0 (str1: context_id, str2: "wayland" ) == 0) |
110 | { |
111 | #ifdef GDK_WINDOWING_WAYLAND |
112 | return GDK_IS_WAYLAND_DISPLAY (display) && |
113 | gdk_wayland_display_query_registry (display, |
114 | global: "zwp_text_input_manager_v3" ); |
115 | #else |
116 | return FALSE; |
117 | #endif |
118 | } |
119 | |
120 | if (g_strcmp0 (str1: context_id, str2: "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 (str1: context_id, str2: "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 (str1: context_id, str2: "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 * |
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, context_id: immodules_list[i])) |
153 | continue; |
154 | |
155 | if (g_strcmp0 (str1: immodules_list[i], SIMPLE_ID) == 0) |
156 | return SIMPLE_ID; |
157 | else if (g_strcmp0 (str1: 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 (extension_point: ep, name: immodules_list[i]); |
166 | if (ext) |
167 | return g_io_extension_get_name (extension: 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 * |
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 (variable: "GTK_IM_MODULE" ); |
194 | if (envvar) |
195 | { |
196 | char **immodules; |
197 | immodules = g_strsplit (string: envvar, delimiter: ":" , max_tokens: 0); |
198 | context_id = lookup_immodule (display, immodules_list: immodules); |
199 | g_strfreev (str_array: 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), first_property_name: "gtk-im-module" , &tmp, NULL); |
208 | if (tmp) |
209 | { |
210 | char **immodules; |
211 | |
212 | immodules = g_strsplit (string: tmp, delimiter: ":" , max_tokens: 0); |
213 | context_id = lookup_immodule (display, immodules_list: immodules); |
214 | g_strfreev (str_array: immodules); |
215 | g_free (mem: 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 (extension_point: ep); l; l = l->next) |
223 | { |
224 | GIOExtension *ext = l->data; |
225 | |
226 | context_id = g_io_extension_get_name (extension: 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 |
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 (extension_point: ep, GTK_TYPE_IM_CONTEXT); |
250 | |
251 | registered = TRUE; |
252 | } |
253 | |
254 | 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 (type: gtk_im_context_simple_get_type ()); |
264 | #ifdef GDK_WINDOWING_WAYLAND |
265 | g_type_ensure (type: 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 (flags: G_IO_MODULE_SCOPE_BLOCK_DUPLICATES); |
278 | |
279 | paths = _gtk_get_module_path (type: "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 (dirname: paths[i], scope); |
285 | } |
286 | g_strfreev (str_array: 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 (extension_point: ep); |
297 | for (l = list; l; l = l->next) |
298 | { |
299 | GIOExtension *ext = l->data; |
300 | g_print (format: "extension: %s: type %s\n" , |
301 | g_io_extension_get_name (extension: ext), |
302 | g_type_name (type: g_io_extension_get_type (extension: ext))); |
303 | } |
304 | } |
305 | } |
306 | |