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