Add action datatypes as defined in the server
[platform/upstream/libxkbcommon.git] / src / xkbcomp / vmod.c
1 /************************************************************
2  Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
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.
15
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.
24
25  ********************************************************/
26
27 #define DEBUG_VAR debugFlags
28 #include <stdio.h>
29 #include "xkbcomp.h"
30 #include "tokens.h"
31 #include "expr.h"
32 #include "misc.h"
33
34 #include <X11/extensions/XKB.h>
35 #include <X11/extensions/XKBstrcommon.h>
36
37 #include "vmod.h"
38
39 void
40 InitVModInfo(VModInfo * info, XkbcDescPtr xkb)
41 {
42     ClearVModInfo(info, xkb);
43     info->errorCount = 0;
44     return;
45 }
46
47 void
48 ClearVModInfo(VModInfo * info, XkbcDescPtr xkb)
49 {
50     register int i;
51
52     if (XkbcAllocNames(xkb, XkbVirtualModNamesMask, 0, 0) != Success)
53         return;
54     if (XkbcAllocServerMap(xkb, XkbVirtualModsMask, 0) != Success)
55         return;
56     info->xkb = xkb;
57     info->newlyDefined = info->defined = info->available = 0;
58     if (xkb && xkb->names)
59     {
60         register int bit;
61         for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1)
62         {
63             if (xkb->names->vmods[i] != None)
64                 info->defined |= bit;
65         }
66     }
67     return;
68 }
69
70 /***====================================================================***/
71
72 /**
73  * Handle one entry in the virtualModifiers line (e.g. NumLock).
74  * If the entry is e.g. NumLock=Mod1, stmt->value is not NULL, and the
75  * XkbServerMap's vmod is set to the given modifier. Otherwise, the vmod is 0.
76  *
77  * @param stmt The statement specifying the name and (if any the value).
78  * @param mergeMode Merge strategy (e.g. MergeOverride)
79  */
80 Bool
81 HandleVModDef(VModDef * stmt, unsigned mergeMode, VModInfo * info)
82 {
83     register int i, bit, nextFree;
84     ExprResult mod;
85     XkbcServerMapPtr srv;
86     XkbNamesPtr names;
87     Atom stmtName;
88
89     srv = info->xkb->server;
90     names = info->xkb->names;
91     stmtName = XkbcInternAtom(XkbcAtomGetString(stmt->name), False);
92     for (i = 0, bit = 1, nextFree = -1; i < XkbNumVirtualMods; i++, bit <<= 1)
93     {
94         if (info->defined & bit)
95         {
96             if (names->vmods[i] == stmtName)
97             {                   /* already defined */
98                 info->available |= bit;
99                 if (stmt->value == NULL)
100                     return True;
101                 else
102                 {
103                     char *str1;
104                     const char *str2 = "";
105                     if (!ExprResolveModMask(stmt->value, &mod, NULL, NULL))
106                     {
107                         str1 = XkbcAtomText(stmt->name);
108                         ACTION("Declaration of %s ignored\n", str1);
109                         return False;
110                     }
111                     if (mod.uval == srv->vmods[i])
112                         return True;
113
114                     str1 = XkbcAtomText(stmt->name);
115                     WARN("Virtual modifier %s multiply defined\n", str1);
116                     str1 = XkbcModMaskText(srv->vmods[i], True);
117                     if (mergeMode == MergeOverride)
118                     {
119                         str2 = str1;
120                         str1 = XkbcModMaskText(mod.uval, True);
121                     }
122                     ACTION("Using %s, ignoring %s\n", str1, str2);
123                     if (mergeMode == MergeOverride)
124                         srv->vmods[i] = mod.uval;
125                     return True;
126                 }
127             }
128         }
129         else if (nextFree < 0)
130             nextFree = i;
131     }
132     if (nextFree < 0)
133     {
134         ERROR("Too many virtual modifiers defined (maximum %d)\n",
135                XkbNumVirtualMods);
136         return False;
137     }
138     info->defined |= (1 << nextFree);
139     info->newlyDefined |= (1 << nextFree);
140     info->available |= (1 << nextFree);
141     names->vmods[nextFree] = stmtName;
142     if (stmt->value == NULL)
143         return True;
144     if (ExprResolveModMask(stmt->value, &mod, NULL, NULL))
145     {
146         srv->vmods[nextFree] = mod.uval;
147         return True;
148     }
149     ACTION("Declaration of %s ignored\n",
150             XkbcAtomText(stmt->name));
151     return False;
152 }
153
154 /**
155  * Returns the index of the given modifier in the xkb->names->vmods array.
156  *
157  * @param priv Pointer to the xkb data structure.
158  * @param elem Must be None, otherwise return False.
159  * @param field The Atom of the modifier's name (e.g. Atom for LAlt)
160  * @param type Must be TypeInt, otherwise return False.
161  * @param val_rtrn Set to the index of the modifier that matches.
162  *
163  * @return True on success, False otherwise. If False is returned, val_rtrn is
164  * undefined.
165  */
166 int
167 LookupVModIndex(char * priv,
168                 Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
169 {
170     register int i;
171     register char *fieldStr;
172     register char *modStr;
173     XkbcDescPtr xkb;
174
175     xkb = (XkbcDescPtr) priv;
176     if ((xkb == NULL) || (xkb->names == NULL) || (elem != None)
177         || (type != TypeInt))
178     {
179         return False;
180     }
181     /* get the actual name */
182     fieldStr = XkbcAtomGetString(field);
183     if (fieldStr == NULL)
184         return False;
185     /* For each named modifier, get the name and compare it to the one passed
186      * in. If we get a match, return the index of the modifier.
187      * The order of modifiers is the same as in the virtual_modifiers line in
188      * the xkb_types section.
189      */
190     for (i = 0; i < XkbNumVirtualMods; i++)
191     {
192         modStr = XkbcAtomGetString(xkb->names->vmods[i]);
193         if ((modStr != NULL) && (uStrCaseCmp(fieldStr, modStr) == 0))
194         {
195             val_rtrn->uval = i;
196             return True;
197         }
198     }
199     return False;
200 }
201
202 /**
203  * Get the mask for the given modifier and set val_rtrn.uval to the mask.
204  * Note that the mask returned is always > 512.
205  *
206  * @param priv Pointer to xkb data structure.
207  * @param val_rtrn Set to the mask returned.
208  *
209  * @return True on success, False otherwise. If False is returned, val_rtrn is
210  * undefined.
211  */
212 int
213 LookupVModMask(char * priv,
214                Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
215 {
216     if (LookupVModIndex(priv, elem, field, type, val_rtrn))
217     {
218         register unsigned ndx = val_rtrn->uval;
219         val_rtrn->uval = (1 << (XkbNumModifiers + ndx));
220         return True;
221     }
222     return False;
223 }
224
225 int
226 FindKeypadVMod(XkbcDescPtr xkb)
227 {
228     Atom name;
229     ExprResult rtrn;
230
231     name = XkbcInternAtom("NumLock", False);
232     if ((xkb) && LookupVModIndex((char *) xkb, None, name, TypeInt, &rtrn))
233     {
234         return rtrn.ival;
235     }
236     return -1;
237 }
238
239 Bool
240 ResolveVirtualModifier(ExprDef * def, ExprResult * val_rtrn, VModInfo * info)
241 {
242     XkbNamesPtr names;
243
244     names = info->xkb->names;
245     if (def->op == ExprIdent)
246     {
247         register int i, bit;
248         for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1)
249         {
250             char *str1, *str2;
251             str1 = XkbcAtomGetString(names->vmods[i]);
252             str2 = XkbcAtomGetString(def->value.str);
253             if ((info->available & bit) && (uStrCaseCmp(str1, str2) == Equal))
254             {
255                 val_rtrn->uval = i;
256                 return True;
257             }
258         }
259     }
260     if (ExprResolveInteger(def, val_rtrn, NULL, NULL))
261     {
262         if (val_rtrn->uval < XkbNumVirtualMods)
263             return True;
264         ERROR("Illegal virtual modifier %d (must be 0..%d inclusive)\n",
265                val_rtrn->uval, XkbNumVirtualMods - 1);
266     }
267     return False;
268 }