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