1 /************************************************************
2 Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 ********************************************************/
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
31 #include <xkb-config.h>
37 #include <X11/Xproto.h>
38 #include <X11/keysym.h>
39 #include <X11/extensions/XKM.h>
41 #include "scrnintstr.h"
42 #include "windowstr.h"
43 #define XKBSRV_NEED_FILE_FUNCS
45 #include <X11/extensions/XI.h>
49 * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is
50 * relative to the top-level XKB configuration directory.
51 * Making the server write to a subdirectory of that directory
52 * requires some work in the general case (install procedure
53 * has to create links to /var or somesuch on many machines),
54 * so we just compile into /usr/tmp for now.
56 #ifndef XKM_OUTPUT_DIR
57 #define XKM_OUTPUT_DIR "compiled/"
60 #define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\""
61 #define ERROR_PREFIX "\"> \""
62 #define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\""
63 #define POST_ERROR_MSG2 "\"End of messages from xkbcomp\""
66 #define PATHSEPARATOR "\\"
68 #define PATHSEPARATOR "/"
72 OutputDirectory(char *outdir
, size_t size
)
75 /* Can we write an xkm and then open it too? */
76 if (access(XKM_OUTPUT_DIR
, W_OK
| X_OK
) == 0 &&
77 (strlen(XKM_OUTPUT_DIR
) < size
)) {
78 (void) strcpy(outdir
, XKM_OUTPUT_DIR
);
82 if (strlen(Win32TempDir()) + 1 < size
) {
83 (void) strcpy(outdir
, Win32TempDir());
84 (void) strcat(outdir
, "\\");
88 if (strlen("/tmp/") < size
) {
89 (void) strcpy(outdir
, "/tmp/");
94 XkbDDXCompileKeymapByNames(XkbDescPtr xkb
,
95 XkbComponentNamesPtr names
,
97 unsigned need
, char *nameRtrn
, int nameRtrnLen
)
100 char *buf
= NULL
, keymap
[PATH_MAX
], xkm_output_dir
[PATH_MAX
];
102 const char *emptystring
= "";
103 char *xkbbasedirflag
= NULL
;
104 const char *xkbbindir
= emptystring
;
105 const char *xkbbindirsep
= emptystring
;
108 /* WIN32 has no popen. The input must be stored in a file which is
109 used as input for xkbcomp. xkbcomp does not read from stdin. */
110 char tmpname
[PATH_MAX
];
111 const char *xkmfile
= tmpname
;
113 const char *xkmfile
= "-";
116 snprintf(keymap
, sizeof(keymap
), "server-%s", display
);
118 OutputDirectory(xkm_output_dir
, sizeof(xkm_output_dir
));
121 strcpy(tmpname
, Win32TempDir());
122 strcat(tmpname
, "\\xkb_XXXXXX");
123 (void) mktemp(tmpname
);
126 if (XkbBaseDirectory
!= NULL
) {
127 if (asprintf(&xkbbasedirflag
, "\"-R%s\"", XkbBaseDirectory
) == -1)
128 xkbbasedirflag
= NULL
;
131 if (XkbBinDirectory
!= NULL
) {
132 int ld
= strlen(XkbBinDirectory
);
133 int lps
= strlen(PATHSEPARATOR
);
135 xkbbindir
= XkbBinDirectory
;
137 if ((ld
>= lps
) && (strcmp(xkbbindir
+ ld
- lps
, PATHSEPARATOR
) != 0)) {
138 xkbbindirsep
= PATHSEPARATOR
;
143 "\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" "
144 "-em1 %s -emp %s -eml %s \"%s%s.xkm\"",
145 xkbbindir
, xkbbindirsep
,
146 ((xkbDebugFlags
< 2) ? 1 :
147 ((xkbDebugFlags
> 10) ? 10 : (int) xkbDebugFlags
)),
148 xkbbasedirflag
? xkbbasedirflag
: "", xkmfile
,
149 PRE_ERROR_MSG
, ERROR_PREFIX
, POST_ERROR_MSG1
,
150 xkm_output_dir
, keymap
) == -1)
153 free(xkbbasedirflag
);
157 "XKB: Could not invoke xkbcomp: not enough memory\n");
162 out
= Popen(buf
, "w");
164 out
= fopen(tmpname
, "w");
170 ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
171 XkbWriteXKBKeymapForNames(stderr
, names
, xkb
, want
, need
);
174 XkbWriteXKBKeymapForNames(out
, names
, xkb
, want
, need
);
176 if (Pclose(out
) == 0)
178 if (fclose(out
) == 0 && System(buf
) >= 0)
182 DebugF("[xkb] xkb executes: %s\n", buf
);
184 strlcpy(nameRtrn
, keymap
, nameRtrnLen
);
193 LogMessage(X_ERROR
, "Error compiling keymap (%s)\n", keymap
);
195 /* remove the temporary file */
201 LogMessage(X_ERROR
, "XKB: Could not invoke xkbcomp\n");
203 LogMessage(X_ERROR
, "Could not open file %s\n", tmpname
);
213 XkbDDXOpenConfigFile(char *mapName
, char *fileNameRtrn
, int fileNameRtrnLen
)
215 char buf
[PATH_MAX
], xkm_output_dir
[PATH_MAX
];
219 if (mapName
!= NULL
) {
220 OutputDirectory(xkm_output_dir
, sizeof(xkm_output_dir
));
221 if ((XkbBaseDirectory
!= NULL
) && (xkm_output_dir
[0] != '/')
223 && (!isalpha(xkm_output_dir
[0]) || xkm_output_dir
[1] != ':')
226 if (snprintf(buf
, PATH_MAX
, "%s/%s%s.xkm", XkbBaseDirectory
,
227 xkm_output_dir
, mapName
) >= PATH_MAX
)
231 if (snprintf(buf
, PATH_MAX
, "%s%s.xkm", xkm_output_dir
, mapName
)
236 file
= fopen(buf
, "rb");
242 if ((fileNameRtrn
!= NULL
) && (fileNameRtrnLen
> 0)) {
243 strlcpy(fileNameRtrn
, buf
, fileNameRtrnLen
);
249 XkbDDXLoadKeymapByNames(DeviceIntPtr keybd
,
250 XkbComponentNamesPtr names
,
253 XkbDescPtr
*xkbRtrn
, char *nameRtrn
, int nameRtrnLen
)
257 char fileName
[PATH_MAX
];
261 if ((keybd
== NULL
) || (keybd
->key
== NULL
) ||
262 (keybd
->key
->xkbInfo
== NULL
))
265 xkb
= keybd
->key
->xkbInfo
->desc
;
266 if ((names
->keycodes
== NULL
) && (names
->types
== NULL
) &&
267 (names
->compat
== NULL
) && (names
->symbols
== NULL
) &&
268 (names
->geometry
== NULL
)) {
269 LogMessage(X_ERROR
, "XKB: No components provided for device %s\n",
270 keybd
->name
? keybd
->name
: "(unnamed keyboard)");
273 else if (!XkbDDXCompileKeymapByNames(xkb
, names
, want
, need
,
274 nameRtrn
, nameRtrnLen
)) {
275 LogMessage(X_ERROR
, "XKB: Couldn't compile keymap\n");
278 file
= XkbDDXOpenConfigFile(nameRtrn
, fileName
, PATH_MAX
);
280 LogMessage(X_ERROR
, "Couldn't open compiled keymap file %s\n",
284 missing
= XkmReadFile(file
, need
, want
, xkbRtrn
);
285 if (*xkbRtrn
== NULL
) {
286 LogMessage(X_ERROR
, "Error loading keymap %s\n", fileName
);
288 (void) unlink(fileName
);
292 DebugF("Loaded XKB keymap %s, defined=0x%x\n", fileName
,
293 (*xkbRtrn
)->defined
);
296 (void) unlink(fileName
);
297 return (need
| want
) & (~missing
);
301 XkbDDXNamesFromRules(DeviceIntPtr keybd
,
303 XkbRF_VarDefsPtr defs
, XkbComponentNamesPtr names
)
308 XkbRF_RulesPtr rules
;
313 if (snprintf(buf
, PATH_MAX
, "%s/rules/%s", XkbBaseDirectory
, rules_name
)
315 LogMessage(X_ERROR
, "XKB: Rules name is too long\n");
319 file
= fopen(buf
, "r");
321 LogMessage(X_ERROR
, "XKB: Couldn't open rules file %s\n", buf
);
325 rules
= XkbRF_Create();
327 LogMessage(X_ERROR
, "XKB: Couldn't create rules struct\n");
332 if (!XkbRF_LoadRules(file
, rules
)) {
333 LogMessage(X_ERROR
, "XKB: Couldn't parse rules file %s\n", rules_name
);
335 XkbRF_Free(rules
, TRUE
);
339 memset(names
, 0, sizeof(*names
));
340 complete
= XkbRF_GetComponents(rules
, defs
, names
);
342 XkbRF_Free(rules
, TRUE
);
345 LogMessage(X_ERROR
, "XKB: Rules returned no components\n");
351 XkbRMLVOtoKcCGST(DeviceIntPtr dev
, XkbRMLVOSet
* rmlvo
,
352 XkbComponentNamesPtr kccgst
)
354 XkbRF_VarDefsRec mlvo
;
356 mlvo
.model
= rmlvo
->model
;
357 mlvo
.layout
= rmlvo
->layout
;
358 mlvo
.variant
= rmlvo
->variant
;
359 mlvo
.options
= rmlvo
->options
;
361 return XkbDDXNamesFromRules(dev
, rmlvo
->rules
, &mlvo
, kccgst
);
365 * Compile the given RMLVO keymap and return it. Returns the XkbDescPtr on
366 * success or NULL on failure. If the components compiled are not a superset
367 * or equal to need, the compiliation is treated as failure.
370 XkbCompileKeymapForDevice(DeviceIntPtr dev
, XkbRMLVOSet
* rmlvo
, int need
)
372 XkbDescPtr xkb
= NULL
;
373 unsigned int provided
;
374 XkbComponentNamesRec kccgst
= { 0 };
377 if (XkbRMLVOtoKcCGST(dev
, rmlvo
, &kccgst
)) {
379 XkbDDXLoadKeymapByNames(dev
, &kccgst
, XkmAllIndicesMask
, need
, &xkb
,
381 if ((need
& provided
) != need
) {
383 XkbFreeKeyboard(xkb
, 0, TRUE
);
389 XkbFreeComponentNames(&kccgst
, FALSE
);
394 XkbCompileKeymap(DeviceIntPtr dev
, XkbRMLVOSet
* rmlvo
)
399 if (!dev
|| !rmlvo
) {
400 LogMessage(X_ERROR
, "XKB: No device or RMLVO specified\n");
404 /* These are the components we really really need */
405 need
= XkmSymbolsMask
| XkmCompatMapMask
| XkmTypesMask
|
406 XkmKeyNamesMask
| XkmVirtualModsMask
;
408 xkb
= XkbCompileKeymapForDevice(dev
, rmlvo
, need
);
413 /* we didn't get what we really needed. And that will likely leave
414 * us with a keyboard that doesn't work. Use the defaults instead */
415 LogMessage(X_ERROR
, "XKB: Failed to load keymap. Loading default "
416 "keymap instead.\n");
418 XkbGetRulesDflts(&dflts
);
420 xkb
= XkbCompileKeymapForDevice(dev
, &dflts
, 0);
422 XkbFreeRMLVOSet(&dflts
, FALSE
);