#include "xkbcomp.h"
#include "misc.h"
#include "tokens.h"
#include "expr.h"
#include "vmod.h"
#include "indicators.h"
#include "action.h"
#include "compat.h"
#define ReportIndicatorBadType(d,l,f,w) \
ReportBadType("indicator map",(f),\
XkbAtomText((d),(l)->name,XkbMessage),(w))
#define ReportIndicatorNotArray(d,l,f) \
ReportNotArray("indicator map",(f),\
XkbAtomText((d),(l)->name,XkbMessage))
void
ClearIndicatorMapInfo(Display * dpy, LEDInfo * info)
{
info->name = XkbInternAtom(dpy, "default", False);
info->indicator = _LED_NotBound;
info->flags = info->which_mods = info->real_mods = 0;
info->vmods = 0;
info->which_groups = info->groups = 0;
info->ctrls = 0;
return;
}
LEDInfo *
AddIndicatorMap(LEDInfo * oldLEDs, LEDInfo * new)
{
LEDInfo *old, *last;
unsigned collide;
last = NULL;
for (old = oldLEDs; old != NULL; old = (LEDInfo *) old->defs.next)
{
if (old->name == new->name)
{
if ((old->real_mods == new->real_mods) &&
(old->vmods == new->vmods) &&
(old->groups == new->groups) &&
(old->ctrls == new->ctrls) &&
(old->which_mods == new->which_mods) &&
(old->which_groups == new->which_groups))
{
old->defs.defined |= new->defs.defined;
return oldLEDs;
}
if (new->defs.merge == MergeReplace)
{
CommonInfo *next = old->defs.next;
if (((old->defs.fileID == new->defs.fileID)
&& (warningLevel > 0)) || (warningLevel > 9))
{
WARN1("Map for indicator %s redefined\n",
XkbAtomText(NULL, old->name, XkbMessage));
ACTION("Earlier definition ignored\n");
}
*old = *new;
old->defs.next = next;
return oldLEDs;
}
collide = 0;
if (UseNewField(_LED_Index, &old->defs, &new->defs, &collide))
{
old->indicator = new->indicator;
old->defs.defined |= _LED_Index;
}
if (UseNewField(_LED_Mods, &old->defs, &new->defs, &collide))
{
old->which_mods = new->which_mods;
old->real_mods = new->real_mods;
old->vmods = new->vmods;
old->defs.defined |= _LED_Mods;
}
if (UseNewField(_LED_Groups, &old->defs, &new->defs, &collide))
{
old->which_groups = new->which_groups;
old->groups = new->groups;
old->defs.defined |= _LED_Groups;
}
if (UseNewField(_LED_Ctrls, &old->defs, &new->defs, &collide))
{
old->ctrls = new->ctrls;
old->defs.defined |= _LED_Ctrls;
}
if (UseNewField(_LED_Explicit, &old->defs, &new->defs, &collide))
{
old->flags &= ~XkbIM_NoExplicit;
old->flags |= (new->flags & XkbIM_NoExplicit);
old->defs.defined |= _LED_Explicit;
}
if (UseNewField(_LED_Automatic, &old->defs, &new->defs, &collide))
{
old->flags &= ~XkbIM_NoAutomatic;
old->flags |= (new->flags & XkbIM_NoAutomatic);
old->defs.defined |= _LED_Automatic;
}
if (UseNewField(_LED_DrivesKbd, &old->defs, &new->defs, &collide))
{
old->flags &= ~XkbIM_LEDDrivesKB;
old->flags |= (new->flags & XkbIM_LEDDrivesKB);
old->defs.defined |= _LED_DrivesKbd;
}
if (collide)
{
WARN1("Map for indicator %s redefined\n",
XkbAtomText(NULL, old->name, XkbMessage));
ACTION1("Using %s definition for duplicate fields\n",
(new->defs.merge == MergeAugment ? "first" : "last"));
}
return oldLEDs;
}
if (old->defs.next == NULL)
last = old;
}
old = uTypedAlloc(LEDInfo);
if (!old)
{
WSGO("Couldn't allocate indicator map\n");
ACTION1("Map for indicator %s not compiled\n",
XkbAtomText(NULL, new->name, XkbMessage));
return NULL;
}
*old = *new;
old->defs.next = NULL;
if (last)
{
last->defs.next = &old->defs;
return oldLEDs;
}
return old;
}
static LookupEntry modComponentNames[] = {
{"base", XkbIM_UseBase}
,
{"latched", XkbIM_UseLatched}
,
{"locked", XkbIM_UseLocked}
,
{"effective", XkbIM_UseEffective}
,
{"compat", XkbIM_UseCompat}
,
{"any", XkbIM_UseAnyMods}
,
{"none", 0}
,
{NULL, 0}
};
static LookupEntry groupComponentNames[] = {
{"base", XkbIM_UseBase}
,
{"latched", XkbIM_UseLatched}
,
{"locked", XkbIM_UseLocked}
,
{"effective", XkbIM_UseEffective}
,
{"any", XkbIM_UseAnyGroup}
,
{"none", 0}
,
{NULL, 0}
};
int
SetIndicatorMapField(LEDInfo * led,
XkbDescPtr xkb,
char *field, ExprDef * arrayNdx, ExprDef * value)
{
ExprResult rtrn;
Bool ok;
ok = True;
if ((uStrCaseCmp(field, "modifiers") == 0)
|| (uStrCaseCmp(field, "mods") == 0))
{
if (arrayNdx != NULL)
return ReportIndicatorNotArray(xkb->dpy, led, field);
if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (XPointer) xkb))
return ReportIndicatorBadType(xkb->dpy, led, field,
"modifier mask");
led->real_mods = rtrn.uval & 0xff;
led->vmods = (rtrn.uval >> 8) & 0xff;
led->defs.defined |= _LED_Mods;
}
else if (uStrCaseCmp(field, "groups") == 0)
{
if (arrayNdx != NULL)
return ReportIndicatorNotArray(xkb->dpy, led, field);
if (!ExprResolveMask
(value, &rtrn, SimpleLookup, (XPointer) groupNames))
return ReportIndicatorBadType(xkb->dpy, led, field, "group mask");
led->groups = rtrn.uval;
led->defs.defined |= _LED_Groups;
}
else if ((uStrCaseCmp(field, "controls") == 0) ||
(uStrCaseCmp(field, "ctrls") == 0))
{
if (arrayNdx != NULL)
return ReportIndicatorNotArray(xkb->dpy, led, field);
if (!ExprResolveMask
(value, &rtrn, SimpleLookup, (XPointer) ctrlNames))
return ReportIndicatorBadType(xkb->dpy, led, field,
"controls mask");
led->ctrls = rtrn.uval;
led->defs.defined |= _LED_Ctrls;
}
else if (uStrCaseCmp(field, "allowexplicit") == 0)
{
if (arrayNdx != NULL)
return ReportIndicatorNotArray(xkb->dpy, led, field);
if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
return ReportIndicatorBadType(xkb->dpy, led, field, "boolean");
if (rtrn.uval)
led->flags &= ~XkbIM_NoExplicit;
else
led->flags |= XkbIM_NoExplicit;
led->defs.defined |= _LED_Explicit;
}
else if ((uStrCaseCmp(field, "whichmodstate") == 0) ||
(uStrCaseCmp(field, "whichmodifierstate") == 0))
{
if (arrayNdx != NULL)
return ReportIndicatorNotArray(xkb->dpy, led, field);
if (!ExprResolveMask(value, &rtrn, SimpleLookup,
(XPointer) modComponentNames))
{
return ReportIndicatorBadType(xkb->dpy, led, field,
"mask of modifier state components");
}
led->which_mods = rtrn.uval;
}
else if (uStrCaseCmp(field, "whichgroupstate") == 0)
{
if (arrayNdx != NULL)
return ReportIndicatorNotArray(xkb->dpy, led, field);
if (!ExprResolveMask(value, &rtrn, SimpleLookup,
(XPointer) groupComponentNames))
{
return ReportIndicatorBadType(xkb->dpy, led, field,
"mask of group state components");
}
led->which_groups = rtrn.uval;
}
else if ((uStrCaseCmp(field, "driveskbd") == 0) ||
(uStrCaseCmp(field, "driveskeyboard") == 0) ||
(uStrCaseCmp(field, "leddriveskbd") == 0) ||
(uStrCaseCmp(field, "leddriveskeyboard") == 0) ||
(uStrCaseCmp(field, "indicatordriveskbd") == 0) ||
(uStrCaseCmp(field, "indicatordriveskeyboard") == 0))
{
if (arrayNdx != NULL)
return ReportIndicatorNotArray(xkb->dpy, led, field);
if (!ExprResolveBoolean(value, &rtrn, NULL, NULL))
return ReportIndicatorBadType(xkb->dpy, led, field, "boolean");
if (rtrn.uval)
led->flags |= XkbIM_LEDDrivesKB;
else
led->flags &= ~XkbIM_LEDDrivesKB;
led->defs.defined |= _LED_DrivesKbd;
}
else if (uStrCaseCmp(field, "index") == 0)
{
if (arrayNdx != NULL)
return ReportIndicatorNotArray(xkb->dpy, led, field);
if (!ExprResolveInteger(value, &rtrn, NULL, NULL))
return ReportIndicatorBadType(xkb->dpy, led, field,
"indicator index");
if ((rtrn.uval < 1) || (rtrn.uval > 32))
{
ERROR2("Illegal indicator index %d (range 1..%d)\n",
rtrn.uval, XkbNumIndicators);
ACTION1("Index definition for %s indicator ignored\n",
XkbAtomText(NULL, led->name, XkbMessage));
return False;
}
led->indicator = rtrn.uval;
led->defs.defined |= _LED_Index;
}
else
{
ERROR2("Unknown field %s in map for %s indicator\n", field,
XkbAtomText(NULL, led->name, XkbMessage));
ACTION("Definition ignored\n");
ok = False;
}
return ok;
}
LEDInfo *
HandleIndicatorMapDef(IndicatorMapDef * def,
XkbDescPtr xkb,
LEDInfo * dflt, LEDInfo * oldLEDs, unsigned merge)
{
LEDInfo led, *rtrn;
VarDef *var;
Bool ok;
if (def->merge != MergeDefault)
merge = def->merge;
led = *dflt;
led.defs.merge = merge;
led.name = def->name;
ok = True;
for (var = def->body; var != NULL; var = (VarDef *) var->common.next)
{
ExprResult elem, field;
ExprDef *arrayNdx;
if (!ExprResolveLhs(var->name, &elem, &field, &arrayNdx))
{
ok = False;
continue;
}
if (elem.str != NULL)
{
ERROR1
("Cannot set defaults for \"%s\" element in indicator map\n",
elem.str);
ACTION2("Assignment to %s.%s ignored\n", elem.str, field.str);
ok = False;
}
else
{
ok = SetIndicatorMapField(&led, xkb, field.str, arrayNdx,
var->value) && ok;
}
}
if (ok)
{
rtrn = AddIndicatorMap(oldLEDs, &led);
return rtrn;
}
return NULL;
}
Bool
CopyIndicatorMapDefs(XkbFileInfo * result, LEDInfo * leds,
LEDInfo ** unboundRtrn)
{
LEDInfo *led, *next;
LEDInfo *unbound, *last;
XkbDescPtr xkb;
xkb = result->xkb;
if (XkbAllocNames(xkb, XkbIndicatorNamesMask, 0, 0) != Success)
{
WSGO("Couldn't allocate names\n");
ACTION("Indicator names may be incorrect\n");
}
if (XkbAllocIndicatorMaps(xkb) != Success)
{
WSGO("Can't allocate indicator maps\n");
ACTION("Indicator map definitions may be lost\n");
return False;
}
last = unbound = (unboundRtrn ? *unboundRtrn : NULL);
while ((last != NULL) && (last->defs.next != NULL))
{
last = (LEDInfo *) last->defs.next;
}
for (led = leds; led != NULL; led = next)
{
next = (LEDInfo *) led->defs.next;
if ((led->groups != 0) && (led->which_groups == 0))
led->which_groups = XkbIM_UseEffective;
if ((led->which_mods == 0) && ((led->real_mods) || (led->vmods)))
led->which_mods = XkbIM_UseEffective;
if ((led->indicator == _LED_NotBound) || (!xkb->indicators))
{
if (unboundRtrn != NULL)
{
led->defs.next = NULL;
if (last != NULL)
last->defs.next = (CommonInfo *) led;
else
unbound = led;
last = led;
}
else
uFree(led);
}
else
{
register XkbIndicatorMapPtr im;
im = &xkb->indicators->maps[led->indicator - 1];
im->flags = led->flags;
im->which_groups = led->which_groups;
im->groups = led->groups;
im->which_mods = led->which_mods;
im->mods.mask = led->real_mods;
im->mods.real_mods = led->real_mods;
im->mods.vmods = led->vmods;
im->ctrls = led->ctrls;
if (xkb->names != NULL)
xkb->names->indicators[led->indicator - 1] = led->name;
uFree(led);
}
}
if (unboundRtrn != NULL)
{
*unboundRtrn = unbound;
}
return True;
}
Bool
BindIndicators(XkbFileInfo * result,
Bool force, LEDInfo * unbound, LEDInfo ** unboundRtrn)
{
XkbDescPtr xkb;
register int i;
register LEDInfo *led, *next, *last;
xkb = result->xkb;
if (xkb->names != NULL)
{
for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next)
{
if (led->indicator == _LED_NotBound)
{
for (i = 0; i < XkbNumIndicators; i++)
{
if (xkb->names->indicators[i] == led->name)
{
led->indicator = i + 1;
break;
}
}
}
}
if (force)
{
for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next)
{
if (led->indicator == _LED_NotBound)
{
for (i = 0; i < XkbNumIndicators; i++)
{
if (xkb->names->indicators[i] == None)
{
xkb->names->indicators[i] = led->name;
led->indicator = i + 1;
xkb->indicators->phys_indicators &= ~(1 << i);
break;
}
}
if (led->indicator == _LED_NotBound)
{
ERROR("No unnamed indicators found\n");
ACTION1
("Virtual indicator map \"%s\" not bound\n",
XkbAtomGetString(xkb->dpy, led->name));
continue;
}
}
}
}
}
for (last = NULL, led = unbound; led != NULL; led = next)
{
next = (LEDInfo *) led->defs.next;
if (led->indicator == _LED_NotBound)
{
if (force)
{
unbound = next;
uFree(led);
}
else
{
if (last)
last->defs.next = &led->defs;
else
unbound = led;
last = led;
}
}
else
{
if ((xkb->names != NULL) &&
(xkb->names->indicators[led->indicator - 1] != led->name))
{
Atom old = xkb->names->indicators[led->indicator - 1];
ERROR1("Multiple names bound to indicator %d\n",
(unsigned int) led->indicator);
ACTION2("Using %s, ignoring %s\n",
XkbAtomGetString(xkb->dpy, old),
XkbAtomGetString(xkb->dpy, led->name));
led->indicator = _LED_NotBound;
if (force)
{
uFree(led);
unbound = next;
}
else
{
if (last)
last->defs.next = &led->defs;
else
unbound = led;
last = led;
}
}
else
{
XkbIndicatorMapPtr map;
map = &xkb->indicators->maps[led->indicator - 1];
map->flags = led->flags;
map->which_groups = led->which_groups;
map->groups = led->groups;
map->which_mods = led->which_mods;
map->mods.mask = led->real_mods;
map->mods.real_mods = led->real_mods;
map->mods.vmods = led->vmods;
map->ctrls = led->ctrls;
if (last)
last->defs.next = &next->defs;
else
unbound = next;
led->defs.next = NULL;
uFree(led);
}
}
}
if (unboundRtrn)
{
*unboundRtrn = unbound;
}
else if (unbound)
{
for (led = unbound; led != NULL; led = next)
{
next = (LEDInfo *) led->defs.next;
uFree(led);
}
}
return True;
}