Implement missing xkb_state_ref and add return value
[platform/upstream/libxkbcommon.git] / src / state.c
1 /************************************************************
2 Copyright (c) 1993 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 /*
28  * Copyright © 2012 Intel Corporation
29  *
30  * Permission is hereby granted, free of charge, to any person obtaining a
31  * copy of this software and associated documentation files (the "Software"),
32  * to deal in the Software without restriction, including without limitation
33  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34  * and/or sell copies of the Software, and to permit persons to whom the
35  * Software is furnished to do so, subject to the following conditions:
36  *
37  * The above copyright notice and this permission notice (including the next
38  * paragraph) shall be included in all copies or substantial portions of the
39  * Software.
40  *
41  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47  * DEALINGS IN THE SOFTWARE.
48  *
49  * Author: Daniel Stone <daniel@fooishbar.org>
50  */
51
52 /*
53  * This is a bastardised version of xkbActions.c from the X server which
54  * does not support, for the moment:
55  *   - AccessX sticky/debounce/etc (will come later)
56  *   - pointer keys (may come later)
57  *   - key redirects (unlikely)
58  *   - messages (very unlikely)
59  */
60
61 #ifdef HAVE_CONFIG_H
62 #include <config.h>
63 #endif
64
65 #include <assert.h>
66
67 #include "xkbcommon/xkbcommon.h"
68 #include "XKBcommonint.h"
69
70 struct xkb_filter {
71     struct xkb_state *state;
72     union xkb_action action;
73     xkb_keycode_t keycode;
74     uint32_t priv;
75     int (*func)(struct xkb_filter *filter, xkb_keycode_t key,
76                 enum xkb_key_direction direction);
77     int refcnt;
78     struct xkb_filter *next;
79 };
80
81 static union xkb_action *
82 xkb_key_get_action(struct xkb_state *state, xkb_keycode_t key)
83 {
84     int group, level;
85
86     if (!XkbKeyHasActions(state->xkb, key) ||
87         !XkbKeycodeInRange(state->xkb, key)) {
88         static union xkb_action fake;
89         memset(&fake, 0, sizeof(fake));
90         fake.type = XkbSA_NoAction;
91         return &fake;
92     }
93
94     group = xkb_key_get_group(state, key);
95     level = xkb_key_get_level(state, key, group);
96
97     return XkbKeyActionEntry(state->xkb, key, level, group);
98 }
99
100 static struct xkb_filter *
101 xkb_filter_new(struct xkb_state *state)
102 {
103     int i;
104     int old_size = state->num_filters;
105     struct xkb_filter *filters = state->filters;
106
107     for (i = 0; i < state->num_filters; i++) {
108         if (filters[i].func)
109             continue;
110         filters[i].state = state;
111         filters[i].refcnt = 1;
112         return &filters[i];
113     }
114
115     if (state->num_filters > 0)
116         state->num_filters *= 2;
117     else
118         state->num_filters = 4;
119     filters = realloc(filters, state->num_filters * sizeof(*filters));
120     if (!filters) { /* WSGO */
121         state->num_filters = old_size;
122         return NULL;
123     }
124     state->filters = filters;
125     memset(&filters[old_size], 0,
126            (state->num_filters - old_size) * sizeof(*filters));
127
128     filters[old_size].state = state;
129     filters[old_size].refcnt = 1;
130
131     return &filters[old_size];
132 }
133
134 /***====================================================================***/
135
136 static int
137 xkb_filter_group_set_func(struct xkb_filter *filter, xkb_keycode_t keycode,
138                           enum xkb_key_direction direction)
139 {
140     if (keycode != filter->keycode) {
141         filter->action.group.flags &= ~XkbSA_ClearLocks;
142         return 1;
143     }
144
145     if (direction == XKB_KEY_DOWN) {
146         filter->refcnt++;
147         return 0;
148     }
149     else if (--filter->refcnt > 0) {
150         return 0;
151     }
152
153     if (filter->action.group.flags & XkbSA_GroupAbsolute)
154         filter->state->base_group = filter->action.group.group;
155     else
156         filter->state->base_group = -filter->action.group.group;
157     if (filter->action.group.flags & XkbSA_ClearLocks)
158         filter->state->locked_group = 0;
159
160     filter->func = NULL;
161
162     return 1;
163 }
164
165 static int
166 xkb_filter_group_set_new(struct xkb_state *state, xkb_keycode_t keycode,
167                          union xkb_action *action)
168 {
169     struct xkb_filter *filter = xkb_filter_new(state);
170
171     if (!filter) /* WSGO */
172         return -1;
173     filter->keycode = keycode;
174     filter->func = xkb_filter_group_set_func;
175     filter->action = *action;
176
177     if (action->group.flags & XkbSA_GroupAbsolute) {
178         filter->action.group.group = filter->state->base_group;
179         filter->state->base_group = action->group.group;
180     }
181     else {
182         filter->state->base_group += action->group.group;
183     }
184
185     return 1;
186 }
187
188 static int
189 xkb_filter_group_lock_func(struct xkb_filter *filter, xkb_keycode_t keycode,
190                            enum xkb_key_direction direction)
191 {
192     if (keycode != filter->keycode)
193         return 1;
194
195     if (direction == XKB_KEY_DOWN) {
196         filter->refcnt++;
197         return 0;
198     }
199     if (--filter->refcnt > 0)
200         return 0;
201
202     filter->func = NULL;
203     return 1;
204 }
205
206 static int
207 xkb_filter_group_lock_new(struct xkb_state *state, xkb_keycode_t keycode,
208                           union xkb_action *action)
209 {
210     struct xkb_filter *filter = xkb_filter_new(state);
211
212     if (!filter)
213         return 0;
214
215     filter->keycode = keycode;
216     filter->func = xkb_filter_group_lock_func;
217     filter->action = *action;
218
219     if (action->group.flags & XkbSA_GroupAbsolute)
220         filter->state->locked_group = action->group.group;
221     else
222         filter->state->locked_group += action->group.group;
223
224     return 1;
225 }
226
227 static int
228 xkb_filter_mod_set_func(struct xkb_filter *filter, xkb_keycode_t keycode,
229                         enum xkb_key_direction direction)
230 {
231     if (keycode != filter->keycode) {
232         filter->action.mods.flags &= ~XkbSA_ClearLocks;
233         return 1;
234     }
235
236     if (direction == XKB_KEY_DOWN) {
237         filter->refcnt++;
238         return 0;
239     }
240     else if (--filter->refcnt > 0) {
241         return 0;
242     }
243
244     filter->state->base_mods &= ~(filter->action.mods.mask);
245     if (filter->action.mods.flags & XkbSA_ClearLocks)
246         filter->state->locked_mods &= ~filter->action.mods.mask;
247
248     filter->func = NULL;
249
250     return 1;
251 }
252
253 static int
254 xkb_filter_mod_set_new(struct xkb_state *state, xkb_keycode_t keycode,
255                        union xkb_action *action)
256 {
257     struct xkb_filter *filter = xkb_filter_new(state);
258
259     if (!filter) /* WSGO */
260         return -1;
261     filter->keycode = keycode;
262     filter->func = xkb_filter_mod_set_func;
263     filter->action = *action;
264
265     filter->state->base_mods |= action->mods.mask;
266
267     return 1;
268 }
269
270 static int
271 xkb_filter_mod_lock_func(struct xkb_filter *filter, xkb_keycode_t keycode,
272                          enum xkb_key_direction direction)
273 {
274     if (keycode != filter->keycode)
275         return 1;
276
277     if (direction == XKB_KEY_DOWN) {
278         filter->refcnt++;
279         return 0;
280     }
281     if (--filter->refcnt > 0)
282         return 0;
283
284     filter->state->locked_mods &= ~filter->priv;
285     filter->func = NULL;
286     return 1;
287 }
288
289 static int
290 xkb_filter_mod_lock_new(struct xkb_state *state, xkb_keycode_t keycode,
291                         union xkb_action *action)
292 {
293     struct xkb_filter *filter = xkb_filter_new(state);
294
295     if (!filter) /* WSGO */
296         return 0;
297
298     filter->keycode = keycode;
299     filter->func = xkb_filter_mod_lock_func;
300     filter->action = *action;
301     filter->priv = state->locked_mods & action->mods.mask;
302     state->locked_mods |= action->mods.mask;
303
304     return 1;
305 }
306
307 enum xkb_key_latch_state {
308     NO_LATCH,
309     LATCH_KEY_DOWN,
310     LATCH_PENDING,
311 };
312
313 static int
314 xkb_filter_mod_latch_func(struct xkb_filter *filter, xkb_keycode_t keycode,
315                           enum xkb_key_direction direction)
316 {
317     enum xkb_key_latch_state latch = filter->priv;
318
319     if (direction == XKB_KEY_DOWN && latch == LATCH_PENDING) {
320         /* If this is a new keypress and we're awaiting our single latched
321          * keypress, then either break the latch if any random key is pressed,
322          * or promote it to a lock or plain base set if it's the same
323          * modifier. */
324         union xkb_action *action = xkb_key_get_action(filter->state, keycode);
325         if (action->type == XkbSA_LatchMods &&
326             action->mods.flags == filter->action.mods.flags &&
327             action->mods.mask == filter->action.mods.mask) {
328             filter->action = *action;
329             if (filter->action.mods.flags & XkbSA_LatchToLock) {
330                 filter->action.type = XkbSA_LockMods;
331                 filter->func = xkb_filter_mod_lock_func;
332                 filter->state->locked_mods |= filter->action.mods.mask;
333             }
334             else {
335                 filter->action.type = XkbSA_SetMods;
336                 filter->func = xkb_filter_mod_set_func;
337                 filter->state->base_mods |= filter->action.mods.mask;
338             }
339             filter->keycode = keycode;
340             filter->state->latched_mods &= ~filter->action.mods.mask;
341             /* XXX beep beep! */
342             return 0;
343         }
344         else if (((1 << action->type) & XkbSA_BreakLatch)) {
345             /* XXX: This may be totally broken, we might need to break the
346              *      latch in the next run after this press? */
347             filter->state->latched_mods &= ~filter->action.mods.mask;
348             filter->func = NULL;
349             return 1;
350         }
351     }
352     else if (direction == XKB_KEY_UP && keycode == filter->keycode) {
353         /* Our key got released.  If we've set it to clear locks, and we
354          * currently have the same modifiers locked, then release them and
355          * don't actually latch.  Else we've actually hit the latching
356          * stage, so set PENDING and move our modifier from base to
357          * latched. */
358         if (latch == NO_LATCH ||
359             ((filter->action.mods.flags & XkbSA_ClearLocks) &&
360              (filter->state->locked_mods & filter->action.mods.mask) ==
361              filter->action.mods.mask)) {
362             /* XXX: We might be a bit overenthusiastic about clearing
363              *      mods other filters have set here? */
364             if (latch == LATCH_PENDING)
365                 filter->state->latched_mods &= ~filter->action.mods.mask;
366             else
367                 filter->state->base_mods &= ~filter->action.mods.mask;
368             filter->state->locked_mods &= ~filter->action.mods.mask;
369             filter->func = NULL;
370         }
371         else {
372             latch = LATCH_PENDING;
373             filter->state->base_mods &= ~filter->action.mods.mask;
374             filter->state->latched_mods |= filter->action.mods.mask;
375             /* XXX beep beep! */
376         }
377     }
378     else if (direction == XKB_KEY_DOWN && latch == LATCH_KEY_DOWN) {
379         /* Someone's pressed another key while we've still got the latching
380          * key held down, so keep the base modifier state active (from
381          * xkb_filter_mod_latch_new), but don't trip the latch, just clear
382          * it as soon as the modifier gets released. */
383         latch = NO_LATCH;
384     }
385
386     filter->priv = latch;
387
388     return 1;
389 }
390
391 static int
392 xkb_filter_mod_latch_new(struct xkb_state *state, xkb_keycode_t keycode,
393                          union xkb_action *action)
394 {
395     struct xkb_filter *filter = xkb_filter_new(state);
396     enum xkb_key_latch_state latch = LATCH_KEY_DOWN;
397
398     if (!filter) /* WSGO */
399         return -1;
400     filter->keycode = keycode;
401     filter->priv = latch;
402     filter->func = xkb_filter_mod_latch_func;
403     filter->action = *action;
404
405     filter->state->base_mods |= action->mods.mask;
406
407     return 1;
408 }
409
410 /**
411  * Applies any relevant filters to the key, first from the list of filters
412  * that are currently active, then if no filter has claimed the key, possibly
413  * apply a new filter from the key action.
414  */
415 static void
416 xkb_filter_apply_all(struct xkb_state *state, xkb_keycode_t key,
417                      enum xkb_key_direction direction)
418 {
419     struct xkb_filter *filters = state->filters;
420     union xkb_action *act = NULL;
421     int send = 1;
422     int i;
423
424     /* First run through all the currently active filters and see if any of
425      * them have claimed this event. */
426     for (i = 0; i < state->num_filters; i++) {
427         if (!filters[i].func)
428             continue;
429         send &= (*filters[i].func)(&filters[i], key, direction);
430     }
431
432     if (!send || direction == XKB_KEY_UP)
433         return;
434
435     act = xkb_key_get_action(state, key);
436     switch (act->type) {
437     case XkbSA_SetMods:
438         send = xkb_filter_mod_set_new(state, key, act);
439         break;
440     case XkbSA_LatchMods:
441         send = xkb_filter_mod_latch_new(state, key, act);
442         break;
443     case XkbSA_LockMods:
444         send = xkb_filter_mod_lock_new(state, key, act);
445         break;
446     case XkbSA_SetGroup:
447         send = xkb_filter_group_set_new(state, key, act);
448         break;
449 #if 0
450     case XkbSA_LatchGroup:
451         send = xkb_filter_mod_latch_new(state, key, act);
452         break;
453 #endif
454     case XkbSA_LockGroup:
455         send = xkb_filter_group_lock_new(state, key, act);
456         break;
457     }
458
459     return;
460 }
461
462 struct xkb_state *
463 xkb_state_new(struct xkb_keymap *xkb)
464 {
465     struct xkb_state *ret;
466
467     if (!xkb)
468         return NULL;
469
470     ret = calloc(sizeof(*ret), 1);
471     if (!ret)
472         return NULL;
473
474     ret->refcnt = 1;
475     ret->xkb = xkb_map_ref(xkb);
476
477     return ret;
478 }
479
480 struct xkb_state *
481 xkb_state_ref(struct xkb_state *state)
482 {
483     state->refcnt++;
484     return state;
485 }
486
487 void
488 xkb_state_unref(struct xkb_state *state)
489 {
490     state->refcnt--;
491     assert(state->refcnt >= 0);
492     if (state->refcnt > 0)
493         return;
494
495     xkb_map_unref(state->xkb);
496     free(state->filters);
497     free(state);
498 }
499
500 /**
501  * Update the LED state to match the rest of the xkb_state.
502  */
503 static void
504 xkb_state_led_update_all(struct xkb_state *state)
505 {
506     xkb_led_index_t led;
507
508     state->leds = 0;
509
510     for (led = 0; led < XkbNumIndicators; led++) {
511         struct xkb_indicator_map *map = &state->xkb->indicators->maps[led];
512         uint32_t mod_mask = 0;
513         uint32_t group_mask = 0;
514
515         if (!map->which_mods && !map->which_groups && !map->ctrls)
516             continue;
517
518         if (map->which_mods) {
519             if (map->which_mods & XkbIM_UseBase)
520                 mod_mask |= state->base_mods;
521             if (map->which_mods & XkbIM_UseLatched)
522                 mod_mask |= state->latched_mods;
523             if (map->which_mods & XkbIM_UseLocked)
524                 mod_mask |= state->locked_mods;
525             if (map->which_mods & XkbIM_UseEffective)
526                 mod_mask |= state->mods;
527             if ((map->mods.mask & mod_mask))
528                 state->leds |= (1 << led);
529         }
530         else if (map->which_groups) {
531             if (map->which_mods & XkbIM_UseBase)
532                 group_mask |= (1 << state->base_group);
533             if (map->which_mods & XkbIM_UseLatched)
534                 group_mask |= (1 << state->latched_group);
535             if (map->which_mods & XkbIM_UseLocked)
536                 group_mask |= (1 << state->locked_group);
537             if (map->which_mods & XkbIM_UseEffective)
538                 group_mask |= (1 << state->group);
539             if ((map->groups & group_mask))
540                 state->leds |= (1 << led);
541         }
542         else if (map->ctrls) {
543             if ((map->ctrls & state->xkb->ctrls->enabled_ctrls))
544                 state->leds |= (1 << led);
545         }
546     }
547 }
548
549 /**
550  * Calculates the derived state (effective mods/group and LEDs) from an
551  * up-to-date xkb_state.
552  */
553 static void
554 xkb_state_update_derived(struct xkb_state *state)
555 {
556     state->mods = (state->base_mods | state->latched_mods | state->locked_mods);
557     /* FIXME: Clamp/wrap locked_group */
558     state->group = state->locked_group + state->base_group +
559                    state->latched_group;
560     /* FIXME: Clamp/wrap effective group */
561
562     xkb_state_led_update_all(state);
563 }
564
565 /**
566  * Given a particular key event, updates the state structure to reflect the
567  * new modifiers.
568  */
569 void
570 xkb_state_update_key(struct xkb_state *state, xkb_keycode_t key,
571                      enum xkb_key_direction direction)
572 {
573     xkb_filter_apply_all(state, key, direction);
574     xkb_state_update_derived(state);
575 }
576
577 /**
578  * Updates the state from a set of explicit masks as gained from
579  * xkb_state_serialise_mods and xkb_state_serialise_groups.  As noted in the
580  * documentation for these functions in xkbcommon.h, this round-trip is
581  * lossy, and should only be used to update a slave state mirroring the
582  * master, e.g. in a client/server window system.
583  */
584 void
585 xkb_state_update_mask(struct xkb_state *state,
586                       xkb_mod_mask_t base_mods,
587                       xkb_mod_mask_t latched_mods,
588                       xkb_mod_mask_t locked_mods,
589                       xkb_group_index_t base_group,
590                       xkb_group_index_t latched_group,
591                       xkb_group_index_t locked_group)
592 {
593     xkb_mod_mask_t mod;
594
595     state->base_mods = 0;
596     state->latched_mods = 0;
597     state->locked_mods = 0;
598     for (mod = 0; mod < xkb_map_num_mods(state->xkb); mod++) {
599         xkb_mod_mask_t idx = (1 << mod);
600         if (base_mods & idx)
601             state->base_mods |= idx;
602         if (latched_mods & idx)
603             state->latched_mods |= idx;
604         if (locked_mods & idx)
605             state->locked_mods |= idx;
606     }
607
608     state->base_group = base_group;
609     state->latched_group = latched_group;
610     state->locked_group = locked_group;
611
612     xkb_state_update_derived(state);
613 }
614
615 /**
616  * Serialises the requested modifier state into an xkb_mod_mask_t, with all
617  * the same disclaimers as in xkb_state_update_mask.
618  */
619 xkb_mod_mask_t
620 xkb_state_serialise_mods(struct xkb_state *state,
621                          enum xkb_state_component type)
622 {
623     xkb_mod_mask_t ret = 0;
624
625     if (type == XKB_STATE_EFFECTIVE)
626         return state->mods;
627
628     if (type & XKB_STATE_DEPRESSED)
629         ret |= state->base_mods;
630     if (type & XKB_STATE_LATCHED)
631         ret |= state->latched_mods;
632     if (type & XKB_STATE_LOCKED)
633         ret |= state->locked_mods;
634
635     return ret;
636 }
637
638 /**
639  * Serialises the requested group state, with all the same disclaimers as
640  * in xkb_state_update_mask.
641  */
642 xkb_group_index_t
643 xkb_state_serialise_group(struct xkb_state *state,
644                           enum xkb_state_component type)
645 {
646     xkb_group_index_t ret = 0;
647
648     if (type == XKB_STATE_EFFECTIVE)
649         return state->group;
650
651     if (type & XKB_STATE_DEPRESSED)
652         ret += state->base_group;
653     if (type & XKB_STATE_LATCHED)
654         ret += state->latched_group;
655     if (type & XKB_STATE_LOCKED)
656         ret += state->locked_group;
657
658     return ret;
659 }
660
661 /**
662  * Returns 1 if the given modifier is active with the specified type(s), 0 if
663  * not, or -1 if the modifier is invalid.
664  */
665 int
666 xkb_state_mod_index_is_active(struct xkb_state *state,
667                               xkb_mod_index_t idx,
668                               enum xkb_state_component type)
669 {
670     int ret = 0;
671
672     if (idx >= xkb_map_num_mods(state->xkb))
673         return -1;
674
675     if (type & XKB_STATE_DEPRESSED)
676         ret |= (state->base_mods & (1 << idx));
677     if (type & XKB_STATE_LATCHED)
678         ret |= (state->latched_mods & (1 << idx));
679     if (type & XKB_STATE_LOCKED)
680         ret |= (state->locked_mods & (1 << idx));
681
682     return ret;
683 }
684
685 /**
686  * Returns 1 if the given modifier is active with the specified type(s), 0 if
687  * not, or -1 if the modifier is invalid.
688  */
689 int
690 xkb_state_mod_name_is_active(struct xkb_state *state, const char *name,
691                              enum xkb_state_component type)
692 {
693     xkb_mod_index_t idx = xkb_map_mod_get_index(state->xkb, name);
694
695     if (idx == XKB_MOD_INVALID)
696         return -1;
697
698     return xkb_state_mod_index_is_active(state, idx, type);
699 }
700
701 /**
702  * Returns 1 if the given group is active with the specified type(s), 0 if
703  * not, or -1 if the group is invalid.
704  */
705 int
706 xkb_state_group_index_is_active(struct xkb_state *state,
707                                 xkb_group_index_t idx,
708                                 enum xkb_state_component type)
709 {
710     int ret = 0;
711
712     if (idx >= xkb_map_num_groups(state->xkb))
713         return -1;
714
715     if (type & XKB_STATE_DEPRESSED)
716         ret |= (state->base_group == idx);
717     if (type & XKB_STATE_LATCHED)
718         ret |= (state->latched_group == idx);
719     if (type & XKB_STATE_LOCKED)
720         ret |= (state->locked_group == idx);
721
722     return ret;
723 }
724
725 /**
726  * Returns 1 if the given modifier is active with the specified type(s), 0 if
727  * not, or -1 if the modifier is invalid.
728  */
729 int
730 xkb_state_group_name_is_active(struct xkb_state *state, const char *name,
731                                enum xkb_state_component type)
732 {
733     xkb_group_index_t idx = xkb_map_group_get_index(state->xkb, name);
734
735     if (idx == XKB_GROUP_INVALID)
736         return -1;
737
738     return xkb_state_group_index_is_active(state, idx, type);
739 }
740
741 /**
742  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
743  */
744 int
745 xkb_state_led_index_is_active(struct xkb_state *state, xkb_led_index_t idx)
746 {
747     if (idx >= xkb_map_num_leds(state->xkb))
748         return -1;
749
750     return !!(state->leds & (1 << idx));
751 }
752
753 /**
754  * Returns 1 if the given LED is active, 0 if not, or -1 if the LED is invalid.
755  */
756 int
757 xkb_state_led_name_is_active(struct xkb_state *state, const char *name)
758 {
759     xkb_led_index_t idx = xkb_map_led_get_index(state->xkb, name);
760
761     if (idx == XKB_LED_INVALID)
762         return -1;
763
764     return xkb_state_led_index_is_active(state, idx);
765 }