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>
48 #if defined(CSRG_BASED) || defined(linux) || defined(__GNU__)
53 * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is
54 * relative to the top-level XKB configuration directory.
55 * Making the server write to a subdirectory of that directory
56 * requires some work in the general case (install procedure
57 * has to create links to /var or somesuch on many machines),
58 * so we just compile into /usr/tmp for now.
60 #ifndef XKM_OUTPUT_DIR
61 #define XKM_OUTPUT_DIR "compiled/"
64 #define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\""
65 #define ERROR_PREFIX "\"> \""
66 #define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\""
67 #define POST_ERROR_MSG2 "\"End of messages from xkbcomp\""
70 #define PATHSEPARATOR "\\"
72 #define PATHSEPARATOR "/"
77 #include <X11/Xwindows.h>
81 static char buffer[PATH_MAX];
82 if (GetTempPath(sizeof(buffer), buffer))
85 buffer[sizeof(buffer)-1] = 0;
88 if (buffer[len-1] == '\\')
92 if (getenv("TEMP") != NULL)
93 return getenv("TEMP");
94 else if (getenv("TMP") != NULL)
95 return getenv("TEMP");
101 Win32System(const char *cmdline)
104 PROCESS_INFORMATION pi;
106 char *cmd = strdup(cmdline);
108 ZeroMemory( &si, sizeof(si) );
110 ZeroMemory( &pi, sizeof(pi) );
112 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
116 FORMAT_MESSAGE_ALLOCATE_BUFFER |
117 FORMAT_MESSAGE_FROM_SYSTEM |
118 FORMAT_MESSAGE_IGNORE_INSERTS,
121 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
126 ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
130 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *)buffer);
137 /* Wait until child process exits. */
138 WaitForSingleObject( pi.hProcess, INFINITE );
140 GetExitCodeProcess( pi.hProcess, &dwExitCode);
142 /* Close process and thread handles. */
143 CloseHandle( pi.hProcess );
144 CloseHandle( pi.hThread );
150 #define System(x) Win32System(x)
159 /* Can we write an xkm and then open it too? */
160 if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0 && (strlen(XKM_OUTPUT_DIR) < size))
162 (void) strcpy (outdir, XKM_OUTPUT_DIR);
165 if (strlen(Win32TempDir()) + 1 < size)
167 (void) strcpy(outdir, Win32TempDir());
168 (void) strcat(outdir, "\\");
171 if (strlen("/tmp/") < size)
173 (void) strcpy (outdir, "/tmp/");
178 XkbDDXCompileKeymapByNames( XkbDescPtr xkb,
179 XkbComponentNamesPtr names,
186 char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX];
188 const char *emptystring = "";
189 char *xkbbasedirflag = NULL;
190 const char *xkbbindir = emptystring;
191 const char *xkbbindirsep = emptystring;
194 /* WIN32 has no popen. The input must be stored in a file which is
195 used as input for xkbcomp. xkbcomp does not read from stdin. */
196 char tmpname[PATH_MAX];
197 const char *xkmfile = tmpname;
199 const char *xkmfile = "-";
202 snprintf(keymap, sizeof(keymap), "server-%s", display);
204 OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
207 strcpy(tmpname, Win32TempDir());
208 strcat(tmpname, "\\xkb_XXXXXX");
209 (void) mktemp(tmpname);
212 if (XkbBaseDirectory != NULL) {
213 xkbbasedirflag = Xprintf("\"-R%s\"", XkbBaseDirectory);
216 if (XkbBinDirectory != NULL) {
217 int ld = strlen(XkbBinDirectory);
218 int lps = strlen(PATHSEPARATOR);
220 xkbbindir = XkbBinDirectory;
223 (strcmp(xkbbindir + ld - lps, PATHSEPARATOR) != 0)) {
224 xkbbindirsep = PATHSEPARATOR;
228 buf = Xprintf("\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" "
229 "-em1 %s -emp %s -eml %s \"%s%s.xkm\"",
230 xkbbindir, xkbbindirsep,
231 ( (xkbDebugFlags < 2) ? 1 :
232 ((xkbDebugFlags > 10) ? 10 : (int)xkbDebugFlags) ),
233 xkbbasedirflag ? xkbbasedirflag : "", xkmfile,
234 PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1,
235 xkm_output_dir, keymap);
237 free(xkbbasedirflag);
240 LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp: not enough memory\n");
247 out= fopen(tmpname, "w");
253 ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
254 XkbWriteXKBKeymapForNames(stderr,names,xkb,want,need);
257 XkbWriteXKBKeymapForNames(out,names,xkb,want,need);
261 if (fclose(out)==0 && System(buf) >= 0)
265 DebugF("[xkb] xkb executes: %s\n",buf);
267 strncpy(nameRtrn,keymap,nameRtrnLen);
268 nameRtrn[nameRtrnLen-1]= '\0';
275 LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap);
277 /* remove the temporary file */
283 LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp\n");
285 LogMessage(X_ERROR, "Could not open file %s\n", tmpname);
296 XkbDDXOpenConfigFile(char *mapName,char *fileNameRtrn,int fileNameRtrnLen)
298 char buf[PATH_MAX],xkm_output_dir[PATH_MAX];
303 OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
304 if ((XkbBaseDirectory!=NULL)&&(xkm_output_dir[0]!='/')
306 &&(!isalpha(xkm_output_dir[0]) || xkm_output_dir[1]!=':')
309 if (strlen(XkbBaseDirectory)+strlen(xkm_output_dir)
310 +strlen(mapName)+6 <= PATH_MAX)
312 sprintf(buf,"%s/%s%s.xkm",XkbBaseDirectory,
313 xkm_output_dir,mapName);
316 else if (strlen(xkm_output_dir)+strlen(mapName)+5 <= PATH_MAX)
317 sprintf(buf,"%s%s.xkm",xkm_output_dir,mapName);
319 file= fopen(buf,"rb");
323 if ((fileNameRtrn!=NULL)&&(fileNameRtrnLen>0)) {
324 strncpy(fileNameRtrn,buf,fileNameRtrnLen);
325 buf[fileNameRtrnLen-1]= '\0';
331 XkbDDXLoadKeymapByNames( DeviceIntPtr keybd,
332 XkbComponentNamesPtr names,
335 XkbDescPtr * xkbRtrn,
341 char fileName[PATH_MAX];
345 if ((keybd==NULL)||(keybd->key==NULL)||(keybd->key->xkbInfo==NULL))
347 else xkb= keybd->key->xkbInfo->desc;
348 if ((names->keycodes==NULL)&&(names->types==NULL)&&
349 (names->compat==NULL)&&(names->symbols==NULL)&&
350 (names->geometry==NULL)) {
351 LogMessage(X_ERROR, "XKB: No components provided for device %s\n",
352 keybd->name ? keybd->name : "(unnamed keyboard)");
355 else if (!XkbDDXCompileKeymapByNames(xkb,names,want,need,
356 nameRtrn,nameRtrnLen)){
357 LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
360 file= XkbDDXOpenConfigFile(nameRtrn,fileName,PATH_MAX);
362 LogMessage(X_ERROR, "Couldn't open compiled keymap file %s\n",fileName);
365 missing= XkmReadFile(file,need,want,xkbRtrn);
366 if (*xkbRtrn==NULL) {
367 LogMessage(X_ERROR, "Error loading keymap %s\n",fileName);
369 (void) unlink (fileName);
373 DebugF("Loaded XKB keymap %s, defined=0x%x\n",fileName,(*xkbRtrn)->defined);
376 (void) unlink (fileName);
377 return (need|want)&(~missing);
381 XkbDDXNamesFromRules( DeviceIntPtr keybd,
383 XkbRF_VarDefsPtr defs,
384 XkbComponentNamesPtr names)
389 XkbRF_RulesPtr rules;
394 if (strlen(XkbBaseDirectory) + strlen(rules_name) + 8 > PATH_MAX) {
395 LogMessage(X_ERROR, "XKB: Rules name is too long\n");
398 sprintf(buf,"%s/rules/%s", XkbBaseDirectory, rules_name);
400 file = fopen(buf, "r");
402 LogMessage(X_ERROR, "XKB: Couldn't open rules file %s\n", buf);
406 rules = XkbRF_Create();
408 LogMessage(X_ERROR, "XKB: Couldn't create rules struct\n");
413 if (!XkbRF_LoadRules(file, rules)) {
414 LogMessage(X_ERROR, "XKB: Couldn't parse rules file %s\n", rules_name);
416 XkbRF_Free(rules,TRUE);
420 memset(names, 0, sizeof(*names));
421 complete = XkbRF_GetComponents(rules,defs,names);
423 XkbRF_Free(rules, TRUE);
426 LogMessage(X_ERROR, "XKB: Rules returned no components\n");
432 XkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet *rmlvo)
434 XkbComponentNamesRec kccgst;
435 XkbRF_VarDefsRec mlvo;
439 if (!dev || !rmlvo) {
440 LogMessage(X_ERROR, "XKB: No device or RMLVO specified\n");
444 mlvo.model = rmlvo->model;
445 mlvo.layout = rmlvo->layout;
446 mlvo.variant = rmlvo->variant;
447 mlvo.options = rmlvo->options;
449 /* XDNFR already logs for us. */
450 if (!XkbDDXNamesFromRules(dev, rmlvo->rules, &mlvo, &kccgst))
453 /* XDLKBN too, but it might return 0 as well as allocating. */
454 if (!XkbDDXLoadKeymapByNames(dev, &kccgst, XkmAllIndicesMask, 0, &xkb, name,
457 XkbFreeKeyboard(xkb, 0, TRUE);