Cleanup invalid mirrors
[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                 char *envvar = getenv("LANG");
86                 if (envvar) {
87                   stderr_out("LANG=");
88                   stderr_out(envvar);
89                 }
90                 envvar = getenv("XMODIFIERS");
91                 if (envvar) {
92                   stderr_out("XMODIFIERS=");
93                   stderr_out(envvar);
94                 }
95                 return;
96         }
97
98         XGetICValues(initial_input_context,
99                      XNFilterEvents, &input_method_event_mask, NULL);
100
101         /* Get a new atom for wide character client messages. */
102         wc_atom = XInternAtom(display, "Wide Character Event", False);
103 }
104
105 /*static widechar_string composed_input_buf = EMPTY_WIDECHAR_STRING;*/
106
107 #define XIM_Composed_Text_BUFSIZE 64
108 typedef struct XIM_Composed_Text {
109         int size;
110         wchar_t data[XIM_Composed_Text_BUFSIZE];
111 } XIM_Composed_Text;
112 static XIM_Composed_Text composed_input_buf =
113     { XIM_Composed_Text_BUFSIZE, {0} };
114 /*static wcidechar composed_input_buf [64] = {0};*/
115 Window main_window;             /* Convenient way to refer to main Era window. */
116
117 /* x_get_composed_input -- Process results of input method composition.
118
119    This function copies the results of the input method composition to
120    composed_input_buf.  Then for each character, a custom event of type
121    wc_atom is sent with the character as its data.
122
123    It is probably more efficient to copy the composition results to some
124    allocated memory and send a single event pointing to that memory.
125    That would cut down on the event processing as well as allow quick
126    insertion into the buffer of the whole string.  It might require some
127    care, though, to avoid fragmenting memory through the allocation and
128    freeing of many small chunks.  Maybe the existing system for
129    (single-byte) string allocation can be used, multiplying the length by
130    sizeof (wchar_t) to get the right size.
131 */
132 void
133 x_get_composed_input(XKeyPressedEvent * x_key_event, XIC context,
134                      Display * display)
135 {
136         KeySym keysym;
137         Status status;
138         int len;
139         int i;
140         XClientMessageEvent new_event;
141
142       retry:
143         len = XwcLookupString(context, x_key_event, composed_input_buf.data,
144                               composed_input_buf.size, &keysym, &status);
145         switch (status) {
146         case XBufferOverflow:
147                 /* GROW_WC_STRING (&composed_input_buf, 32); mrb */
148                 goto retry;
149         case XLookupChars:
150                 break;
151         default:
152                 abort();
153         }
154
155         new_event.type = ClientMessage;
156         new_event.display = x_key_event->display;
157         new_event.window = x_key_event->window;
158         new_event.message_type = wc_atom;
159         new_event.format = 32;  /* 32-bit wide data */
160         new_event.data.l[2] = new_event.data.l[3] = new_event.data.l[4] = 0L;
161         new_event.data.l[0] = x_key_event->time;
162         for (i = 0; i < len; i++) {
163                 new_event.data.l[1] = ((wchar_t *) composed_input_buf.data)[i];
164                 XSendEvent(display, main_window, False, 0L,
165                            (XEvent *) & new_event);
166         }
167 }
168 #endif                          /* I18N4 */
169
170 Lisp_Object Qdefer_gettext;
171
172 DEFUN("ignore-defer-gettext", Fignore_defer_gettext, 1, 1, 0,   /*
173 If OBJECT is of the form (defer-gettext "string"), return the string.
174 The purpose of the defer-gettext symbol is to identify strings which
175 are translated when they are referenced instead of when they are defined.
176 */
177       (object))
178 {
179         if (CONSP(object)) {
180                 Lisp_Object tmp = Fcar(object);
181                 if (SYMBOLP(tmp) && EQ(tmp, Qdefer_gettext)) {
182                         return Fcar(Fcdr(object));
183                 }
184         }
185         return object;
186 }
187
188 DEFUN("gettext", Fgettext, 1, 1, 0,     /*
189 Look up STRING in the default message domain and return its translation.
190 This function does nothing if I18N3 was not enabled when Emacs was compiled.
191 */
192       (string))
193 {
194 #ifdef I18N3
195         /* #### What should happen here is:
196
197            1) If the string has no `string-translatable' property or its value
198            is nil, no translation takes place.  The `string-translatable' property
199            only gets added when a constant string is read in from a .el or .elc
200            file, to avoid excessive translation.  (The user can also explicitly
201            add this property to a string.)
202            2) If the string's `string-translatable' property is a string,
203            that string should be returned.  `format' add this property.
204            This allows translation to take place at the proper time but
205            avoids excessive translation if the string is not destined for
206            a translating stream.  (See print_internal().)
207            3) If gettext() returns the same string, then Fgettext() should return
208            the same object, minus the 'string-translatable' property. */
209
210         if (STRINGP(string)) {
211 #ifdef DEBUG_SXEMACS
212                 stderr_out("\nFgettext (%s) called.\n", XSTRING_DATA(string));
213 #endif
214                 return build_string(gettext((char *)XSTRING_DATA(string)));
215         } else {
216                 return string;
217         }
218 #else
219         return string;
220 #endif
221 }
222
223 #ifdef I18N3
224
225 /* #### add the function `force-gettext', perhaps in Lisp.  This
226    ignores the `string-translatable' property and simply calls gettext()
227    on the string.  Add the functions `set-string-translatable' and
228    `set-stream-translating'. */
229
230 #endif
231
232 DEFUN("dgettext", Fdgettext, 2, 2, 0,   /*
233 Look up STRING in the specified message domain and return its translation.
234 This function does nothing if I18N3 was not enabled when Emacs was compiled.
235 */
236       (domain, string))
237 {
238         CHECK_STRING(domain);
239         CHECK_STRING(string);
240 #ifdef I18N3
241         return build_string(dgettext((char *)XSTRING_DATA(domain),
242                                      (char *)XSTRING_DATA(string)));
243 #else
244         return string;
245 #endif
246 }
247
248 DEFUN("bind-text-domain", Fbind_text_domain, 2, 2, 0,   /*
249 Associate a pathname with a message domain.
250 Here's how the path to message files is constructed under SunOS 5.0:
251 {pathname}/{LANG}/LC_MESSAGES/{domain}.mo
252 This function does nothing if I18N3 was not enabled when Emacs was compiled.
253 */
254       (domain, pathname))
255 {
256         CHECK_STRING(domain);
257         CHECK_STRING(pathname);
258 #ifdef I18N3
259         return build_string(bindtextdomain((char *)XSTRING_DATA(domain),
260                                            (char *)XSTRING_DATA(pathname)));
261 #else
262         return Qnil;
263 #endif
264 }
265
266 extern int load_in_progress;
267
268 DEFUN("set-domain", Fset_domain, 1, 1, 0,       /*
269 Specify the domain used for translating messages in this source file.
270 The domain declaration may only appear at top-level, and should precede
271 all function and variable definitions.
272
273 The presence of this declaration in a compiled file effectively sets the
274 domain of all functions and variables which are defined in that file.
275 Bug: it has no effect on source (.el) files, only compiled (.elc) files.
276 */
277       (domain_name))
278 {
279         CHECK_STRING(domain_name);
280         if (load_in_progress)
281                 return (domain_name);
282         else
283                 return Qnil;
284 }
285 \f
286 /************************************************************************/
287 /*                            initialization                            */
288 /************************************************************************/
289
290 void init_intl_very_early(void)
291 {
292 #if defined (I18N2) || defined (I18N3) || defined (I18N4)
293         setlocale(LC_ALL, "");
294         setlocale(LC_NUMERIC, "C");
295 #endif
296
297 #ifdef I18N3
298         textdomain("emacs");
299 #endif
300 }
301
302 void syms_of_intl(void)
303 {
304         /* defer-gettext is defined as a symbol because when it is used in menu
305            specification strings, it is not evaluated as a function by
306            menu_item_descriptor_to_widget_value(). */
307         defsymbol(&Qdefer_gettext, "defer-gettext");
308
309         DEFSUBR(Fignore_defer_gettext);
310         DEFSUBR(Fgettext);
311         DEFSUBR(Fdgettext);
312         DEFSUBR(Fbind_text_domain);
313         DEFSUBR(Fset_domain);
314 }
315
316 void vars_of_intl(void)
317 {
318 #ifdef I18N2
319         Fprovide(intern("i18n2"));
320 #endif
321 #ifdef I18N3
322         Fprovide(intern("i18n3"));
323 #endif
324 }