Initial git import
[sxemacs] / src / intl.c
1 /* Various functions for internationalizing SXEmacs
2    Copyright (C) 1993, 1994, 1995 Board of Trustees, University of Illinois.
3
4 This file is part of SXEmacs
5
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19
20 /* Synched up with: Not in FSF. */
21
22 /* This stuff is far, far from working. */
23
24 #include <config.h>
25 #include "lisp.h"
26
27 #include "bytecode.h"
28 #include "ui/device.h"
29
30 #if defined (HAVE_X_WINDOWS) && defined (HAVE_X11_XLOCALE_H)
31 #include <X11/Xlocale.h>
32 #else
33 #ifdef HAVE_LOCALE_H
34 #include <locale.h>
35 #endif
36 #endif
37
38 #ifdef I18N4
39 #include <X11/Xlib.h>
40
41 unsigned long input_method_event_mask;
42 Atom wc_atom;
43
44 /* init_input -- Set things up for i18n level 4 input.
45 */
46 void init_input(const char *res_name, const char *res_class, Display * display)
47 {
48         XIMStyles *styles;
49         unsigned short i;
50
51         input_method = 0;
52         input_method_style = 0;
53         initial_input_context = 0;
54         input_method_event_mask = 0;
55
56         input_method = XOpenIM(display, NULL,
57                                (char *)res_name, (char *)res_class);
58
59         if (!input_method) {
60                 stderr_out("WARNING: XOpenIM() failed...no input server\n");
61                 return;
62         }
63
64         /* Query input method for supported input styles and pick one.
65            Right now, we choose a style which supports root-window preediting. */
66         XGetIMValues(input_method, XNQueryInputStyle, &styles, NULL);
67         for (i = 0; i < styles->count_styles; i++) {
68                 if (styles->supported_styles[i] ==
69                     (XIMPreeditNothing | XIMStatusNothing)) {
70                         input_method_style = styles->supported_styles[i];
71                         break;
72                 }
73         }
74
75         if (!input_method_style) {
76                 stderr_out("WARNING: Could not find suitable input style.\n");
77                 return;
78         }
79
80         initial_input_context = XCreateIC(input_method,
81                                           XNInputStyle, input_method_style,
82                                           NULL);
83         if (!initial_input_context) {
84                 stderr_out("WARNING: Could not create input context.\n");
85                 return;
86         }
87
88         XGetICValues(initial_input_context,
89                      XNFilterEvents, &input_method_event_mask, NULL);
90
91         /* Get a new atom for wide character client messages. */
92         wc_atom = XInternAtom(display, "Wide Character Event", False);
93 }
94
95 /*static widechar_string composed_input_buf = EMPTY_WIDECHAR_STRING;*/
96
97 #define XIM_Composed_Text_BUFSIZE 64
98 typedef struct XIM_Composed_Text {
99         int size;
100         wchar_t data[XIM_Composed_Text_BUFSIZE];
101 } XIM_Composed_Text;
102 static XIM_Composed_Text composed_input_buf =
103     { XIM_Composed_Text_BUFSIZE, {0} };
104 /*static wcidechar composed_input_buf [64] = {0};*/
105 Window main_window;             /* Convenient way to refer to main Era window. */
106
107 /* x_get_composed_input -- Process results of input method composition.
108
109    This function copies the results of the input method composition to
110    composed_input_buf.  Then for each character, a custom event of type
111    wc_atom is sent with the character as its data.
112
113    It is probably more efficient to copy the composition results to some
114    allocated memory and send a single event pointing to that memory.
115    That would cut down on the event processing as well as allow quick
116    insertion into the buffer of the whole string.  It might require some
117    care, though, to avoid fragmenting memory through the allocation and
118    freeing of many small chunks.  Maybe the existing system for
119    (single-byte) string allocation can be used, multiplying the length by
120    sizeof (wchar_t) to get the right size.
121 */
122 void
123 x_get_composed_input(XKeyPressedEvent * x_key_event, XIC context,
124                      Display * display)
125 {
126         KeySym keysym;
127         Status status;
128         int len;
129         int i;
130         XClientMessageEvent new_event;
131
132       retry:
133         len = XwcLookupString(context, x_key_event, composed_input_buf.data,
134                               composed_input_buf.size, &keysym, &status);
135         switch (status) {
136         case XBufferOverflow:
137                 /* GROW_WC_STRING (&composed_input_buf, 32); mrb */
138                 goto retry;
139         case XLookupChars:
140                 break;
141         default:
142                 abort();
143         }
144
145         new_event.type = ClientMessage;
146         new_event.display = x_key_event->display;
147         new_event.window = x_key_event->window;
148         new_event.message_type = wc_atom;
149         new_event.format = 32;  /* 32-bit wide data */
150         new_event.data.l[2] = new_event.data.l[3] = new_event.data.l[4] = 0L;
151         new_event.data.l[0] = x_key_event->time;
152         for (i = 0; i < len; i++) {
153                 new_event.data.l[1] = ((wchar_t *) composed_input_buf.data)[i];
154                 XSendEvent(display, main_window, False, 0L,
155                            (XEvent *) & new_event);
156         }
157 }
158 #endif                          /* I18N4 */
159
160 Lisp_Object Qdefer_gettext;
161
162 DEFUN("ignore-defer-gettext", Fignore_defer_gettext, 1, 1, 0,   /*
163 If OBJECT is of the form (defer-gettext "string"), return the string.
164 The purpose of the defer-gettext symbol is to identify strings which
165 are translated when they are referenced instead of when they are defined.
166 */
167       (object))
168 {
169         if (CONSP(object)) {
170                 Lisp_Object tmp = Fcar(object);
171                 if (SYMBOLP(tmp) && EQ(tmp, Qdefer_gettext)) {
172                         return Fcar(Fcdr(object));
173                 }
174         }
175         return object;
176 }
177
178 DEFUN("gettext", Fgettext, 1, 1, 0,     /*
179 Look up STRING in the default message domain and return its translation.
180 This function does nothing if I18N3 was not enabled when Emacs was compiled.
181 */
182       (string))
183 {
184 #ifdef I18N3
185         /* #### What should happen here is:
186
187            1) If the string has no `string-translatable' property or its value
188            is nil, no translation takes place.  The `string-translatable' property
189            only gets added when a constant string is read in from a .el or .elc
190            file, to avoid excessive translation.  (The user can also explicitly
191            add this property to a string.)
192            2) If the string's `string-translatable' property is a string,
193            that string should be returned.  `format' add this property.
194            This allows translation to take place at the proper time but
195            avoids excessive translation if the string is not destined for
196            a translating stream.  (See print_internal().)
197            3) If gettext() returns the same string, then Fgettext() should return
198            the same object, minus the 'string-translatable' property. */
199
200         if (STRINGP(string)) {
201 #ifdef DEBUG_SXEMACS
202                 stderr_out("\nFgettext (%s) called.\n", XSTRING_DATA(string));
203 #endif
204                 return build_string(gettext((char *)XSTRING_DATA(string)));
205         } else {
206                 return string;
207         }
208 #else
209         return string;
210 #endif
211 }
212
213 #ifdef I18N3
214
215 /* #### add the function `force-gettext', perhaps in Lisp.  This
216    ignores the `string-translatable' property and simply calls gettext()
217    on the string.  Add the functions `set-string-translatable' and
218    `set-stream-translating'. */
219
220 #endif
221
222 DEFUN("dgettext", Fdgettext, 2, 2, 0,   /*
223 Look up STRING in the specified message domain and return its translation.
224 This function does nothing if I18N3 was not enabled when Emacs was compiled.
225 */
226       (domain, string))
227 {
228         CHECK_STRING(domain);
229         CHECK_STRING(string);
230 #ifdef I18N3
231         return build_string(dgettext((char *)XSTRING_DATA(domain),
232                                      (char *)XSTRING_DATA(string)));
233 #else
234         return string;
235 #endif
236 }
237
238 DEFUN("bind-text-domain", Fbind_text_domain, 2, 2, 0,   /*
239 Associate a pathname with a message domain.
240 Here's how the path to message files is constructed under SunOS 5.0:
241 {pathname}/{LANG}/LC_MESSAGES/{domain}.mo
242 This function does nothing if I18N3 was not enabled when Emacs was compiled.
243 */
244       (domain, pathname))
245 {
246         CHECK_STRING(domain);
247         CHECK_STRING(pathname);
248 #ifdef I18N3
249         return build_string(bindtextdomain((char *)XSTRING_DATA(domain),
250                                            (char *)XSTRING_DATA(pathname)));
251 #else
252         return Qnil;
253 #endif
254 }
255
256 extern int load_in_progress;
257
258 DEFUN("set-domain", Fset_domain, 1, 1, 0,       /*
259 Specify the domain used for translating messages in this source file.
260 The domain declaration may only appear at top-level, and should precede
261 all function and variable definitions.
262
263 The presence of this declaration in a compiled file effectively sets the
264 domain of all functions and variables which are defined in that file.
265 Bug: it has no effect on source (.el) files, only compiled (.elc) files.
266 */
267       (domain_name))
268 {
269         CHECK_STRING(domain_name);
270         if (load_in_progress)
271                 return (domain_name);
272         else
273                 return Qnil;
274 }
275 \f
276 /************************************************************************/
277 /*                            initialization                            */
278 /************************************************************************/
279
280 void init_intl_very_early(void)
281 {
282 #if defined (I18N2) || defined (I18N3) || defined (I18N4)
283         setlocale(LC_ALL, "");
284         setlocale(LC_NUMERIC, "C");
285 #endif
286
287 #ifdef I18N3
288         textdomain("emacs");
289 #endif
290 }
291
292 void syms_of_intl(void)
293 {
294         /* defer-gettext is defined as a symbol because when it is used in menu
295            specification strings, it is not evaluated as a function by
296            menu_item_descriptor_to_widget_value(). */
297         defsymbol(&Qdefer_gettext, "defer-gettext");
298
299         DEFSUBR(Fignore_defer_gettext);
300         DEFSUBR(Fgettext);
301         DEFSUBR(Fdgettext);
302         DEFSUBR(Fbind_text_domain);
303         DEFSUBR(Fset_domain);
304 }
305
306 void vars_of_intl(void)
307 {
308 #ifdef I18N2
309         Fprovide(intern("i18n2"));
310 #endif
311 #ifdef I18N3
312         Fprovide(intern("i18n3"));
313 #endif
314 }