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