1706f2543Smrg/************************************************************
2706f2543SmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3706f2543Smrg
4706f2543SmrgPermission to use, copy, modify, and distribute this
5706f2543Smrgsoftware and its documentation for any purpose and without
6706f2543Smrgfee is hereby granted, provided that the above copyright
7706f2543Smrgnotice appear in all copies and that both that copyright
8706f2543Smrgnotice and this permission notice appear in supporting
9706f2543Smrgdocumentation, and that the name of Silicon Graphics not be
10706f2543Smrgused in advertising or publicity pertaining to distribution
11706f2543Smrgof the software without specific prior written permission.
12706f2543SmrgSilicon Graphics makes no representation about the suitability
13706f2543Smrgof this software for any purpose. It is provided "as is"
14706f2543Smrgwithout any express or implied warranty.
15706f2543Smrg
16706f2543SmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17706f2543SmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18706f2543SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19706f2543SmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20706f2543SmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21706f2543SmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22706f2543SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23706f2543SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
24706f2543Smrg
25706f2543Smrg********************************************************/
26706f2543Smrg
27706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
28706f2543Smrg#include <dix-config.h>
29706f2543Smrg#endif
30706f2543Smrg
31706f2543Smrg#include <xkb-config.h>
32706f2543Smrg
33706f2543Smrg#include <stdio.h>
34706f2543Smrg#include <ctype.h>
35706f2543Smrg#include <X11/X.h>
36706f2543Smrg#include <X11/Xos.h>
37706f2543Smrg#include <X11/Xproto.h>
38706f2543Smrg#include <X11/keysym.h>
39706f2543Smrg#include <X11/extensions/XKM.h>
40706f2543Smrg#include "inputstr.h"
41706f2543Smrg#include "scrnintstr.h"
42706f2543Smrg#include "windowstr.h"
43706f2543Smrg#define	XKBSRV_NEED_FILE_FUNCS
44706f2543Smrg#include <xkbsrv.h>
45706f2543Smrg#include <X11/extensions/XI.h>
46706f2543Smrg#include "xkb.h"
47706f2543Smrg
48706f2543Smrg	/*
49706f2543Smrg	 * If XKM_OUTPUT_DIR specifies a path without a leading slash, it is
50706f2543Smrg	 * relative to the top-level XKB configuration directory.
51706f2543Smrg	 * Making the server write to a subdirectory of that directory
52706f2543Smrg	 * requires some work in the general case (install procedure
53706f2543Smrg	 * has to create links to /var or somesuch on many machines),
54706f2543Smrg	 * so we just compile into /usr/tmp for now.
55706f2543Smrg	 */
56706f2543Smrg#ifndef XKM_OUTPUT_DIR
57706f2543Smrg#define	XKM_OUTPUT_DIR	"compiled/"
58706f2543Smrg#endif
59706f2543Smrg
60706f2543Smrg#define	PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\""
61706f2543Smrg#define	ERROR_PREFIX	"\"> \""
62706f2543Smrg#define	POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\""
63706f2543Smrg#define	POST_ERROR_MSG2 "\"End of messages from xkbcomp\""
64706f2543Smrg
65706f2543Smrg#if defined(WIN32)
66706f2543Smrg#define PATHSEPARATOR "\\"
67706f2543Smrg#else
68706f2543Smrg#define PATHSEPARATOR "/"
69706f2543Smrg#endif
70706f2543Smrg
71706f2543Smrg#ifdef WIN32
72706f2543Smrg
73706f2543Smrg#include <X11/Xwindows.h>
74706f2543Smrgconst char*
75706f2543SmrgWin32TempDir()
76706f2543Smrg{
77706f2543Smrg    static char buffer[PATH_MAX];
78706f2543Smrg    if (GetTempPath(sizeof(buffer), buffer))
79706f2543Smrg    {
80706f2543Smrg        int len;
81706f2543Smrg        buffer[sizeof(buffer)-1] = 0;
82706f2543Smrg        len = strlen(buffer);
83706f2543Smrg        if (len > 0)
84706f2543Smrg            if (buffer[len-1] == '\\')
85706f2543Smrg                buffer[len-1] = 0;
86706f2543Smrg        return buffer;
87706f2543Smrg    }
88706f2543Smrg    if (getenv("TEMP") != NULL)
89706f2543Smrg        return getenv("TEMP");
90706f2543Smrg    else if (getenv("TMP") != NULL)
91706f2543Smrg        return getenv("TEMP");
92706f2543Smrg    else
93706f2543Smrg        return "/tmp";
94706f2543Smrg}
95706f2543Smrg
96706f2543Smrgint
97706f2543SmrgWin32System(const char *cmdline)
98706f2543Smrg{
99706f2543Smrg    STARTUPINFO si;
100706f2543Smrg    PROCESS_INFORMATION pi;
101706f2543Smrg    DWORD dwExitCode;
102706f2543Smrg    char *cmd = strdup(cmdline);
103706f2543Smrg
104706f2543Smrg    ZeroMemory( &si, sizeof(si) );
105706f2543Smrg    si.cb = sizeof(si);
106706f2543Smrg    ZeroMemory( &pi, sizeof(pi) );
107706f2543Smrg
108706f2543Smrg    if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
109706f2543Smrg    {
110706f2543Smrg	LPVOID buffer;
111706f2543Smrg	if (!FormatMessage(
112706f2543Smrg		    FORMAT_MESSAGE_ALLOCATE_BUFFER |
113706f2543Smrg		    FORMAT_MESSAGE_FROM_SYSTEM |
114706f2543Smrg		    FORMAT_MESSAGE_IGNORE_INSERTS,
115706f2543Smrg		    NULL,
116706f2543Smrg		    GetLastError(),
117706f2543Smrg		    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
118706f2543Smrg		    (LPTSTR) &buffer,
119706f2543Smrg		    0,
120706f2543Smrg		    NULL ))
121706f2543Smrg	{
122706f2543Smrg	    ErrorF("[xkb] Starting '%s' failed!\n", cmdline);
123706f2543Smrg	}
124706f2543Smrg	else
125706f2543Smrg	{
126706f2543Smrg	    ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *)buffer);
127706f2543Smrg	    LocalFree(buffer);
128706f2543Smrg	}
129706f2543Smrg
130706f2543Smrg	free(cmd);
131706f2543Smrg	return -1;
132706f2543Smrg    }
133706f2543Smrg    /* Wait until child process exits. */
134706f2543Smrg    WaitForSingleObject( pi.hProcess, INFINITE );
135706f2543Smrg
136706f2543Smrg    GetExitCodeProcess( pi.hProcess, &dwExitCode);
137706f2543Smrg
138706f2543Smrg    /* Close process and thread handles. */
139706f2543Smrg    CloseHandle( pi.hProcess );
140706f2543Smrg    CloseHandle( pi.hThread );
141706f2543Smrg    free(cmd);
142706f2543Smrg
143706f2543Smrg    return dwExitCode;
144706f2543Smrg}
145706f2543Smrg#undef System
146706f2543Smrg#define System(x) Win32System(x)
147706f2543Smrg#endif
148706f2543Smrg
149706f2543Smrgstatic void
150706f2543SmrgOutputDirectory(
151706f2543Smrg    char* outdir,
152706f2543Smrg    size_t size)
153706f2543Smrg{
154706f2543Smrg#ifndef WIN32
155706f2543Smrg    /* Can we write an xkm and then open it too? */
156706f2543Smrg    if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0 && (strlen(XKM_OUTPUT_DIR) < size))
157706f2543Smrg    {
158706f2543Smrg	(void) strcpy (outdir, XKM_OUTPUT_DIR);
159706f2543Smrg    } else
160706f2543Smrg#else
161706f2543Smrg    if (strlen(Win32TempDir()) + 1 < size)
162706f2543Smrg    {
163706f2543Smrg	(void) strcpy(outdir, Win32TempDir());
164706f2543Smrg	(void) strcat(outdir, "\\");
165706f2543Smrg    } else
166706f2543Smrg#endif
167706f2543Smrg    if (strlen("/tmp/") < size)
168706f2543Smrg    {
169706f2543Smrg	(void) strcpy (outdir, "/tmp/");
170706f2543Smrg    }
171706f2543Smrg}
172706f2543Smrg
173706f2543Smrgstatic Bool
174706f2543SmrgXkbDDXCompileKeymapByNames(	XkbDescPtr		xkb,
175706f2543Smrg				XkbComponentNamesPtr	names,
176706f2543Smrg				unsigned		want,
177706f2543Smrg				unsigned		need,
178706f2543Smrg				char *			nameRtrn,
179706f2543Smrg				int			nameRtrnLen)
180706f2543Smrg{
181706f2543Smrg    FILE *	out;
182706f2543Smrg    char	*buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX];
183706f2543Smrg
184706f2543Smrg    const char	*emptystring = "";
185706f2543Smrg    char *xkbbasedirflag = NULL;
186706f2543Smrg    const char	*xkbbindir = emptystring;
187706f2543Smrg    const char	*xkbbindirsep = emptystring;
188706f2543Smrg
189706f2543Smrg#ifdef WIN32
190706f2543Smrg    /* WIN32 has no popen. The input must be stored in a file which is
191706f2543Smrg       used as input for xkbcomp. xkbcomp does not read from stdin. */
192706f2543Smrg    char tmpname[PATH_MAX];
193706f2543Smrg    const char *xkmfile = tmpname;
194706f2543Smrg#else
195706f2543Smrg    const char *xkmfile = "-";
196706f2543Smrg#endif
197706f2543Smrg
198706f2543Smrg    snprintf(keymap, sizeof(keymap), "server-%s", display);
199706f2543Smrg
200706f2543Smrg    OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
201706f2543Smrg
202706f2543Smrg#ifdef WIN32
203706f2543Smrg    strcpy(tmpname, Win32TempDir());
204706f2543Smrg    strcat(tmpname, "\\xkb_XXXXXX");
205706f2543Smrg    (void) mktemp(tmpname);
206706f2543Smrg#endif
207706f2543Smrg
208706f2543Smrg    if (XkbBaseDirectory != NULL) {
209706f2543Smrg	if (asprintf(&xkbbasedirflag, "\"-R%s\"", XkbBaseDirectory) == -1)
210706f2543Smrg	    xkbbasedirflag = NULL;
211706f2543Smrg    }
212706f2543Smrg
213706f2543Smrg    if (XkbBinDirectory != NULL) {
214706f2543Smrg	int ld = strlen(XkbBinDirectory);
215706f2543Smrg	int lps = strlen(PATHSEPARATOR);
216706f2543Smrg
217706f2543Smrg	xkbbindir = XkbBinDirectory;
218706f2543Smrg
219706f2543Smrg	if ((ld >= lps) &&
220706f2543Smrg	    (strcmp(xkbbindir + ld - lps, PATHSEPARATOR) != 0)) {
221706f2543Smrg	    xkbbindirsep = PATHSEPARATOR;
222706f2543Smrg	}
223706f2543Smrg    }
224706f2543Smrg
225706f2543Smrg    if (asprintf(&buf,
226706f2543Smrg		 "\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" "
227706f2543Smrg		  "-em1 %s -emp %s -eml %s \"%s%s.xkm\"",
228706f2543Smrg		 xkbbindir, xkbbindirsep,
229706f2543Smrg		 ((xkbDebugFlags < 2) ? 1 :
230706f2543Smrg		  ((xkbDebugFlags > 10) ? 10 : (int) xkbDebugFlags)),
231706f2543Smrg		 xkbbasedirflag ? xkbbasedirflag : "", xkmfile,
232706f2543Smrg		 PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1,
233706f2543Smrg		 xkm_output_dir, keymap) == -1)
234706f2543Smrg	buf = NULL;
235706f2543Smrg
236706f2543Smrg    free(xkbbasedirflag);
237706f2543Smrg
238706f2543Smrg    if (!buf) {
239706f2543Smrg        LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp: not enough memory\n");
240706f2543Smrg        return FALSE;
241706f2543Smrg    }
242706f2543Smrg
243706f2543Smrg#ifndef WIN32
244706f2543Smrg    out= Popen(buf,"w");
245706f2543Smrg#else
246706f2543Smrg    out= fopen(tmpname, "w");
247706f2543Smrg#endif
248706f2543Smrg
249706f2543Smrg    if (out!=NULL) {
250706f2543Smrg#ifdef DEBUG
251706f2543Smrg    if (xkbDebugFlags) {
252706f2543Smrg       ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
253706f2543Smrg       XkbWriteXKBKeymapForNames(stderr,names,xkb,want,need);
254706f2543Smrg    }
255706f2543Smrg#endif
256706f2543Smrg	XkbWriteXKBKeymapForNames(out,names,xkb,want,need);
257706f2543Smrg#ifndef WIN32
258706f2543Smrg	if (Pclose(out)==0)
259706f2543Smrg#else
260706f2543Smrg	if (fclose(out)==0 && System(buf) >= 0)
261706f2543Smrg#endif
262706f2543Smrg	{
263706f2543Smrg            if (xkbDebugFlags)
264706f2543Smrg                DebugF("[xkb] xkb executes: %s\n",buf);
265706f2543Smrg	    if (nameRtrn) {
266706f2543Smrg		strncpy(nameRtrn,keymap,nameRtrnLen);
267706f2543Smrg		nameRtrn[nameRtrnLen-1]= '\0';
268706f2543Smrg	    }
269706f2543Smrg            free(buf);
270706f2543Smrg	    return TRUE;
271706f2543Smrg	}
272706f2543Smrg	else
273706f2543Smrg	    LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap);
274706f2543Smrg#ifdef WIN32
275706f2543Smrg        /* remove the temporary file */
276706f2543Smrg        unlink(tmpname);
277706f2543Smrg#endif
278706f2543Smrg    }
279706f2543Smrg    else {
280706f2543Smrg#ifndef WIN32
281706f2543Smrg	LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp\n");
282706f2543Smrg#else
283706f2543Smrg	LogMessage(X_ERROR, "Could not open file %s\n", tmpname);
284706f2543Smrg#endif
285706f2543Smrg    }
286706f2543Smrg    if (nameRtrn)
287706f2543Smrg	nameRtrn[0]= '\0';
288706f2543Smrg    free(buf);
289706f2543Smrg    return FALSE;
290706f2543Smrg}
291706f2543Smrg
292706f2543Smrgstatic FILE *
293706f2543SmrgXkbDDXOpenConfigFile(char *mapName,char *fileNameRtrn,int fileNameRtrnLen)
294706f2543Smrg{
295706f2543Smrgchar	buf[PATH_MAX],xkm_output_dir[PATH_MAX];
296706f2543SmrgFILE *	file;
297706f2543Smrg
298706f2543Smrg    buf[0]= '\0';
299706f2543Smrg    if (mapName!=NULL) {
300706f2543Smrg	OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
301706f2543Smrg	if ((XkbBaseDirectory!=NULL)&&(xkm_output_dir[0]!='/')
302706f2543Smrg#ifdef WIN32
303706f2543Smrg                &&(!isalpha(xkm_output_dir[0]) || xkm_output_dir[1]!=':')
304706f2543Smrg#endif
305706f2543Smrg                ) {
306706f2543Smrg	    if (strlen(XkbBaseDirectory)+strlen(xkm_output_dir)
307706f2543Smrg		     +strlen(mapName)+6 <= PATH_MAX)
308706f2543Smrg	    {
309706f2543Smrg	        sprintf(buf,"%s/%s%s.xkm",XkbBaseDirectory,
310706f2543Smrg					xkm_output_dir,mapName);
311706f2543Smrg	    }
312706f2543Smrg	}
313706f2543Smrg	else if (strlen(xkm_output_dir)+strlen(mapName)+5 <= PATH_MAX)
314706f2543Smrg	    sprintf(buf,"%s%s.xkm",xkm_output_dir,mapName);
315706f2543Smrg	if (buf[0] != '\0')
316706f2543Smrg	    file= fopen(buf,"rb");
317706f2543Smrg	else file= NULL;
318706f2543Smrg    }
319706f2543Smrg    else file= NULL;
320706f2543Smrg    if ((fileNameRtrn!=NULL)&&(fileNameRtrnLen>0)) {
321706f2543Smrg	strncpy(fileNameRtrn,buf,fileNameRtrnLen);
322706f2543Smrg	buf[fileNameRtrnLen-1]= '\0';
323706f2543Smrg    }
324706f2543Smrg    return file;
325706f2543Smrg}
326706f2543Smrg
327706f2543Smrgunsigned
328706f2543SmrgXkbDDXLoadKeymapByNames(	DeviceIntPtr		keybd,
329706f2543Smrg				XkbComponentNamesPtr	names,
330706f2543Smrg				unsigned		want,
331706f2543Smrg				unsigned		need,
332706f2543Smrg				XkbDescPtr *		xkbRtrn,
333706f2543Smrg				char *			nameRtrn,
334706f2543Smrg				int 			nameRtrnLen)
335706f2543Smrg{
336706f2543SmrgXkbDescPtr      xkb;
337706f2543SmrgFILE	*	file;
338706f2543Smrgchar		fileName[PATH_MAX];
339706f2543Smrgunsigned	missing;
340706f2543Smrg
341706f2543Smrg    *xkbRtrn = NULL;
342706f2543Smrg    if ((keybd==NULL)||(keybd->key==NULL)||(keybd->key->xkbInfo==NULL))
343706f2543Smrg	 xkb= NULL;
344706f2543Smrg    else xkb= keybd->key->xkbInfo->desc;
345706f2543Smrg    if ((names->keycodes==NULL)&&(names->types==NULL)&&
346706f2543Smrg	(names->compat==NULL)&&(names->symbols==NULL)&&
347706f2543Smrg	(names->geometry==NULL)) {
348706f2543Smrg        LogMessage(X_ERROR, "XKB: No components provided for device %s\n",
349706f2543Smrg                   keybd->name ? keybd->name : "(unnamed keyboard)");
350706f2543Smrg        return 0;
351706f2543Smrg    }
352706f2543Smrg    else if (!XkbDDXCompileKeymapByNames(xkb,names,want,need,
353706f2543Smrg                                         nameRtrn,nameRtrnLen)){
354706f2543Smrg	LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
355706f2543Smrg	return 0;
356706f2543Smrg    }
357706f2543Smrg    file= XkbDDXOpenConfigFile(nameRtrn,fileName,PATH_MAX);
358706f2543Smrg    if (file==NULL) {
359706f2543Smrg	LogMessage(X_ERROR, "Couldn't open compiled keymap file %s\n",fileName);
360706f2543Smrg	return 0;
361706f2543Smrg    }
362706f2543Smrg    missing= XkmReadFile(file,need,want,xkbRtrn);
363706f2543Smrg    if (*xkbRtrn==NULL) {
364706f2543Smrg	LogMessage(X_ERROR, "Error loading keymap %s\n",fileName);
365706f2543Smrg	fclose(file);
366706f2543Smrg	(void) unlink (fileName);
367706f2543Smrg	return 0;
368706f2543Smrg    }
369706f2543Smrg    else {
370706f2543Smrg	DebugF("Loaded XKB keymap %s, defined=0x%x\n",fileName,(*xkbRtrn)->defined);
371706f2543Smrg    }
372706f2543Smrg    fclose(file);
373706f2543Smrg    (void) unlink (fileName);
374706f2543Smrg    return (need|want)&(~missing);
375706f2543Smrg}
376706f2543Smrg
377706f2543SmrgBool
378706f2543SmrgXkbDDXNamesFromRules(	DeviceIntPtr		keybd,
379706f2543Smrg			char *			rules_name,
380706f2543Smrg			XkbRF_VarDefsPtr	defs,
381706f2543Smrg			XkbComponentNamesPtr	names)
382706f2543Smrg{
383706f2543Smrgchar 		buf[PATH_MAX];
384706f2543SmrgFILE *		file;
385706f2543SmrgBool		complete;
386706f2543SmrgXkbRF_RulesPtr	rules;
387706f2543Smrg
388706f2543Smrg    if (!rules_name)
389706f2543Smrg	return FALSE;
390706f2543Smrg
391706f2543Smrg    if (strlen(XkbBaseDirectory) + strlen(rules_name) + 8 > PATH_MAX) {
392706f2543Smrg        LogMessage(X_ERROR, "XKB: Rules name is too long\n");
393706f2543Smrg        return FALSE;
394706f2543Smrg    }
395706f2543Smrg    sprintf(buf,"%s/rules/%s", XkbBaseDirectory, rules_name);
396706f2543Smrg
397706f2543Smrg    file = fopen(buf, "r");
398706f2543Smrg    if (!file) {
399706f2543Smrg        LogMessage(X_ERROR, "XKB: Couldn't open rules file %s\n", buf);
400706f2543Smrg	return FALSE;
401706f2543Smrg    }
402706f2543Smrg
403706f2543Smrg    rules = XkbRF_Create();
404706f2543Smrg    if (!rules) {
405706f2543Smrg        LogMessage(X_ERROR, "XKB: Couldn't create rules struct\n");
406706f2543Smrg	fclose(file);
407706f2543Smrg	return FALSE;
408706f2543Smrg    }
409706f2543Smrg
410706f2543Smrg    if (!XkbRF_LoadRules(file, rules)) {
411706f2543Smrg        LogMessage(X_ERROR, "XKB: Couldn't parse rules file %s\n", rules_name);
412706f2543Smrg	fclose(file);
413706f2543Smrg	XkbRF_Free(rules,TRUE);
414706f2543Smrg	return FALSE;
415706f2543Smrg    }
416706f2543Smrg
417706f2543Smrg    memset(names, 0, sizeof(*names));
418706f2543Smrg    complete = XkbRF_GetComponents(rules,defs,names);
419706f2543Smrg    fclose(file);
420706f2543Smrg    XkbRF_Free(rules, TRUE);
421706f2543Smrg
422706f2543Smrg    if (!complete)
423706f2543Smrg        LogMessage(X_ERROR, "XKB: Rules returned no components\n");
424706f2543Smrg
425706f2543Smrg    return complete;
426706f2543Smrg}
427706f2543Smrg
428706f2543Smrgstatic Bool
429706f2543SmrgXkbRMLVOtoKcCGST(DeviceIntPtr dev, XkbRMLVOSet *rmlvo, XkbComponentNamesPtr kccgst)
430706f2543Smrg{
431706f2543Smrg    XkbRF_VarDefsRec mlvo;
432706f2543Smrg
433706f2543Smrg    mlvo.model = rmlvo->model;
434706f2543Smrg    mlvo.layout = rmlvo->layout;
435706f2543Smrg    mlvo.variant = rmlvo->variant;
436706f2543Smrg    mlvo.options = rmlvo->options;
437706f2543Smrg
438706f2543Smrg    return XkbDDXNamesFromRules(dev, rmlvo->rules, &mlvo, kccgst);
439706f2543Smrg}
440706f2543Smrg
441706f2543Smrg/**
442706f2543Smrg * Compile the given RMLVO keymap and return it. Returns the XkbDescPtr on
443706f2543Smrg * success or NULL on failure. If the components compiled are not a superset
444706f2543Smrg * or equal to need, the compiliation is treated as failure.
445706f2543Smrg */
446706f2543Smrgstatic XkbDescPtr
447706f2543SmrgXkbCompileKeymapForDevice(DeviceIntPtr dev, XkbRMLVOSet *rmlvo, int need)
448706f2543Smrg{
449706f2543Smrg    XkbDescPtr xkb = NULL;
450706f2543Smrg    unsigned int provided;
451706f2543Smrg    XkbComponentNamesRec kccgst = {0};
452706f2543Smrg    char name[PATH_MAX];
453706f2543Smrg
454706f2543Smrg    if (XkbRMLVOtoKcCGST(dev, rmlvo, &kccgst)) {
455706f2543Smrg        provided = XkbDDXLoadKeymapByNames(dev, &kccgst, XkmAllIndicesMask, need,
456706f2543Smrg                                           &xkb, name, PATH_MAX);
457706f2543Smrg        if ((need & provided) != need) {
458706f2543Smrg            if (xkb) {
459706f2543Smrg                XkbFreeKeyboard(xkb, 0, TRUE);
460706f2543Smrg                xkb = NULL;
461706f2543Smrg            }
462706f2543Smrg        }
463706f2543Smrg    }
464706f2543Smrg
465706f2543Smrg    XkbFreeComponentNames(&kccgst, FALSE);
466706f2543Smrg    return xkb;
467706f2543Smrg}
468706f2543Smrg
469706f2543SmrgXkbDescPtr
470706f2543SmrgXkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet *rmlvo)
471706f2543Smrg{
472706f2543Smrg    XkbDescPtr xkb;
473706f2543Smrg    unsigned int need;
474706f2543Smrg
475706f2543Smrg    if (!dev || !rmlvo) {
476706f2543Smrg        LogMessage(X_ERROR, "XKB: No device or RMLVO specified\n");
477706f2543Smrg        return NULL;
478706f2543Smrg    }
479706f2543Smrg
480706f2543Smrg    /* These are the components we really really need */
481706f2543Smrg    need = XkmSymbolsMask | XkmCompatMapMask | XkmTypesMask |
482706f2543Smrg           XkmKeyNamesMask | XkmVirtualModsMask;
483706f2543Smrg
484706f2543Smrg
485706f2543Smrg    xkb = XkbCompileKeymapForDevice(dev, rmlvo, need);
486706f2543Smrg
487706f2543Smrg    if (!xkb) {
488706f2543Smrg        XkbRMLVOSet dflts;
489706f2543Smrg
490706f2543Smrg        /* we didn't get what we really needed. And that will likely leave
491706f2543Smrg         * us with a keyboard that doesn't work. Use the defaults instead */
492706f2543Smrg        LogMessage(X_ERROR, "XKB: Failed to load keymap. Loading default "
493706f2543Smrg                   "keymap instead.\n");
494706f2543Smrg
495706f2543Smrg        XkbGetRulesDflts(&dflts);
496706f2543Smrg
497706f2543Smrg        xkb = XkbCompileKeymapForDevice(dev, &dflts, 0);
498706f2543Smrg
499706f2543Smrg        XkbFreeRMLVOSet(&dflts, FALSE);
500706f2543Smrg    }
501706f2543Smrg
502706f2543Smrg    return xkb;
503706f2543Smrg}
504