indicators.c revision f46a6179
1/* $Xorg: indicators.c,v 1.3 2000/08/17 19:54:31 cpqbld Exp $ */
2/************************************************************
3 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
4
5 Permission to use, copy, modify, and distribute this
6 software and its documentation for any purpose and without
7 fee is hereby granted, provided that the above copyright
8 notice appear in all copies and that both that copyright
9 notice and this permission notice appear in supporting
10 documentation, and that the name of Silicon Graphics not be
11 used in advertising or publicity pertaining to distribution
12 of the software without specific prior written permission.
13 Silicon Graphics makes no representation about the suitability
14 of this software for any purpose. It is provided "as is"
15 without any express or implied warranty.
16
17 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
20 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
23 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
24 THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
26 ********************************************************/
27/* $XFree86: xc/programs/xkbcomp/indicators.c,v 1.4 2001/01/17 23:45:43 dawes Exp $ */
28
29#include "xkbcomp.h"
30#include "misc.h"
31#include "tokens.h"
32#include "expr.h"
33#include "vmod.h"
34#include "indicators.h"
35#include "action.h"
36#include "compat.h"
37
38/***====================================================================***/
39
40#define	ReportIndicatorBadType(d,l,f,w)	\
41		ReportBadType("indicator map",(f),\
42		      	XkbAtomText((d),(l)->name,XkbMessage),(w))
43#define	ReportIndicatorNotArray(d,l,f)	\
44		ReportNotArray("indicator map",(f),\
45			XkbAtomText((d),(l)->name,XkbMessage))
46
47/***====================================================================***/
48
49void
50ClearIndicatorMapInfo(Display *dpy,LEDInfo *info)
51{
52    info->name= 	XkbInternAtom(dpy,"default",False);
53    info->indicator=	_LED_NotBound;
54    info->flags= info->which_mods= info->real_mods= 0;
55    info->vmods= 0;
56    info->which_groups= info->groups= 0;
57    info->ctrls= 0;
58    return;
59}
60
61LEDInfo *
62AddIndicatorMap(LEDInfo *oldLEDs,LEDInfo *new)
63{
64LEDInfo *old,*last;
65unsigned collide;
66
67    last= NULL;
68    for (old=oldLEDs;old!=NULL;old=(LEDInfo *)old->defs.next) {
69	if (old->name==new->name) {
70	    if ((old->real_mods==new->real_mods)&&
71		(old->vmods==new->vmods)&&
72		(old->groups==new->groups)&&
73		(old->ctrls==new->ctrls)&&
74		(old->which_mods==new->which_mods)&&
75		(old->which_groups==new->which_groups)) {
76		old->defs.defined|= new->defs.defined;
77		return oldLEDs;
78	    }
79	    if (new->defs.merge==MergeReplace) {
80		CommonInfo *next= old->defs.next;
81		if (((old->defs.fileID==new->defs.fileID)&&(warningLevel>0))||
82		   					   (warningLevel>9)) {
83		    WARN1("Map for indicator %s redefined\n",
84				  XkbAtomText(NULL,old->name,XkbMessage));
85		    ACTION("Earlier definition ignored\n");
86		}
87		*old= *new;
88		old->defs.next= next;
89		return oldLEDs;
90	    }
91	    collide= 0;
92	    if (UseNewField(_LED_Index,&old->defs,&new->defs,&collide)) {
93		old->indicator= new->indicator;
94		old->defs.defined|= _LED_Index;
95	    }
96	    if (UseNewField(_LED_Mods,&old->defs,&new->defs,&collide)) {
97		old->which_mods= new->which_mods;
98		old->real_mods= new->real_mods;
99		old->vmods= new->vmods;
100		old->defs.defined|= _LED_Mods;
101	    }
102	    if (UseNewField(_LED_Groups,&old->defs,&new->defs,&collide)) {
103		old->which_groups= new->which_groups;
104		old->groups= new->groups;
105		old->defs.defined|= _LED_Groups;
106	    }
107	    if (UseNewField(_LED_Ctrls,&old->defs,&new->defs,&collide)) {
108		old->ctrls= new->ctrls;
109		old->defs.defined|= _LED_Ctrls;
110	    }
111	    if (UseNewField(_LED_Explicit,&old->defs,&new->defs,&collide)) {
112		old->flags&= ~XkbIM_NoExplicit;
113		old->flags|= (new->flags&XkbIM_NoExplicit);
114		old->defs.defined|= _LED_Explicit;
115	    }
116	    if (UseNewField(_LED_Automatic,&old->defs,&new->defs,&collide)) {
117		old->flags&= ~XkbIM_NoAutomatic;
118		old->flags|= (new->flags&XkbIM_NoAutomatic);
119		old->defs.defined|= _LED_Automatic;
120	    }
121	    if (UseNewField(_LED_DrivesKbd,&old->defs,&new->defs,&collide)) {
122		old->flags&= ~XkbIM_LEDDrivesKB;
123		old->flags|= (new->flags&XkbIM_LEDDrivesKB);
124		old->defs.defined|= _LED_DrivesKbd;
125	    }
126	    if (collide) {
127		WARN1("Map for indicator %s redefined\n",
128				XkbAtomText(NULL,old->name,XkbMessage));
129		ACTION1("Using %s definition for duplicate fields\n",
130				(new->defs.merge==MergeAugment?"first":"last"));
131	    }
132	    return oldLEDs;
133	}
134	if (old->defs.next==NULL)
135	    last= old;
136    }
137    /* new definition */
138    old= uTypedAlloc(LEDInfo);
139    if (!old) {
140	WSGO("Couldn't allocate indicator map\n");
141	ACTION1("Map for indicator %s not compiled\n",
142				XkbAtomText(NULL,new->name,XkbMessage));
143	return False;
144    }
145    *old= *new;
146    old->defs.next= NULL;
147    if (last) {
148	last->defs.next= &old->defs;
149	return oldLEDs;
150    }
151    return old;
152}
153
154LookupEntry	modComponentNames[] = {
155	{	"base",		XkbIM_UseBase		},
156	{	"latched",	XkbIM_UseLatched	},
157	{	"locked",	XkbIM_UseLocked		},
158	{	"effective",	XkbIM_UseEffective	},
159	{	"compat",	XkbIM_UseCompat		},
160	{	"any",		XkbIM_UseAnyMods	},
161	{	"none",		0			},
162	{	NULL,		0			}
163};
164LookupEntry	groupComponentNames[] = {
165	{	"base",		XkbIM_UseBase		},
166	{	"latched",	XkbIM_UseLatched	},
167	{	"locked",	XkbIM_UseLocked		},
168	{	"effective",	XkbIM_UseEffective	},
169	{	"any",		XkbIM_UseAnyGroup	},
170	{	"none",		0			},
171	{	NULL,		0			}
172};
173
174int
175SetIndicatorMapField(	LEDInfo *	led,
176			XkbDescPtr 	xkb,
177			char *		field,
178			ExprDef *	arrayNdx,
179			ExprDef *	value)
180{
181ExprResult	rtrn;
182Bool		ok;
183
184    ok= True;
185    if ((uStrCaseCmp(field,"modifiers")==0)||(uStrCaseCmp(field,"mods")==0)) {
186	if (arrayNdx!=NULL)
187	    return ReportIndicatorNotArray(xkb->dpy,led,field);
188	if (!ExprResolveModMask(value,&rtrn,LookupVModMask,(XPointer)xkb))
189	    return ReportIndicatorBadType(xkb->dpy,led,field,"modifier mask");
190	led->real_mods= rtrn.uval&0xff;
191	led->vmods= (rtrn.uval>>8)&0xff;
192	led->defs.defined|= _LED_Mods;
193    }
194    else if (uStrCaseCmp(field,"groups")==0) {
195	if (arrayNdx!=NULL)
196	    return ReportIndicatorNotArray(xkb->dpy,led,field);
197	if (!ExprResolveMask(value,&rtrn,SimpleLookup,(XPointer)groupNames))
198	    return ReportIndicatorBadType(xkb->dpy,led,field,"group mask");
199	led->groups= rtrn.uval;
200	led->defs.defined|= _LED_Groups;
201    }
202    else if ((uStrCaseCmp(field,"controls")==0)||
203	     (uStrCaseCmp(field,"ctrls")==0)) {
204	if (arrayNdx!=NULL)
205	    return ReportIndicatorNotArray(xkb->dpy,led,field);
206	if (!ExprResolveMask(value,&rtrn,SimpleLookup,(XPointer)ctrlNames))
207	    return ReportIndicatorBadType(xkb->dpy,led,field,"controls mask");
208	led->ctrls= rtrn.uval;
209	led->defs.defined|= _LED_Ctrls;
210    }
211    else if (uStrCaseCmp(field,"allowexplicit")==0) {
212	if (arrayNdx!=NULL)
213	    return ReportIndicatorNotArray(xkb->dpy,led,field);
214	if (!ExprResolveBoolean(value,&rtrn,NULL,NULL))
215	    return ReportIndicatorBadType(xkb->dpy,led,field,"boolean");
216	if (rtrn.uval)	led->flags&= ~XkbIM_NoExplicit;
217	else		led->flags|=  XkbIM_NoExplicit;
218	led->defs.defined|= _LED_Explicit;
219    }
220    else if ((uStrCaseCmp(field,"whichmodstate")==0)||
221	     (uStrCaseCmp(field,"whichmodifierstate")==0)) {
222	if (arrayNdx!=NULL)
223	    return ReportIndicatorNotArray(xkb->dpy,led,field);
224	if (!ExprResolveMask(value,&rtrn,SimpleLookup,
225						(XPointer)modComponentNames)) {
226	    return ReportIndicatorBadType(xkb->dpy,led,field,
227    					"mask of modifier state components");
228	}
229	led->which_mods= rtrn.uval;
230    }
231    else if (uStrCaseCmp(field,"whichgroupstate")==0) {
232	if (arrayNdx!=NULL)
233	    return ReportIndicatorNotArray(xkb->dpy,led,field);
234	if (!ExprResolveMask(value,&rtrn,SimpleLookup,
235						(XPointer)groupComponentNames)){
236	    return ReportIndicatorBadType(xkb->dpy,led,field,
237					"mask of group state components");
238	}
239	led->which_groups= rtrn.uval;
240    }
241    else if ((uStrCaseCmp(field,"driveskbd")==0)||
242	     (uStrCaseCmp(field,"driveskeyboard")==0)||
243	     (uStrCaseCmp(field,"leddriveskbd")==0)||
244	     (uStrCaseCmp(field,"leddriveskeyboard")==0)||
245	     (uStrCaseCmp(field,"indicatordriveskbd")==0)||
246	     (uStrCaseCmp(field,"indicatordriveskeyboard")==0)) {
247	if (arrayNdx!=NULL)
248	    return ReportIndicatorNotArray(xkb->dpy,led,field);
249	if (!ExprResolveBoolean(value,&rtrn,NULL,NULL))
250	    return ReportIndicatorBadType(xkb->dpy,led,field,"boolean");
251	if (rtrn.uval)	led->flags|=  XkbIM_LEDDrivesKB;
252	else		led->flags&= ~XkbIM_LEDDrivesKB;
253	led->defs.defined|= _LED_DrivesKbd;
254    }
255    else if (uStrCaseCmp(field,"index")==0) {
256	if (arrayNdx!=NULL)
257	    return ReportIndicatorNotArray(xkb->dpy,led,field);
258	if (!ExprResolveInteger(value,&rtrn,NULL,NULL))
259	    return ReportIndicatorBadType(xkb->dpy,led,field,"indicator index");
260	if ((rtrn.uval<1)||(rtrn.uval>32)) {
261	    ERROR2("Illegal indicator index %d (range 1..%d)\n",rtrn.uval,
262							XkbNumIndicators);
263	    ACTION1("Index definition for %s indicator ignored\n",
264				XkbAtomText(NULL,led->name,XkbMessage));
265	    return False;
266	}
267	led->indicator= rtrn.uval;
268	led->defs.defined|= _LED_Index;
269    }
270    else {
271	ERROR2("Unknown field %s in map for %s indicator\n",field,
272				XkbAtomText(NULL,led->name,XkbMessage));
273	ACTION("Definition ignored\n");
274	ok= False;
275    }
276    return ok;
277}
278
279LEDInfo *
280HandleIndicatorMapDef(	IndicatorMapDef *	def,
281			XkbDescPtr		xkb,
282			LEDInfo *		dflt,
283			LEDInfo *		oldLEDs,
284			unsigned 		merge)
285{
286LEDInfo			led,*rtrn;
287VarDef *		var;
288Bool			ok;
289
290    if (def->merge!=MergeDefault)
291	merge= def->merge;
292
293    led= *dflt;
294    led.defs.merge= merge;
295    led.name= def->name;
296
297    ok= True;
298    for (var= def->body;var!=NULL;var= (VarDef *)var->common.next) {
299	ExprResult	elem,field;
300	ExprDef *	arrayNdx;
301	if (!ExprResolveLhs(var->name,&elem,&field,&arrayNdx)) {
302	    ok= False;
303	    continue;
304	}
305	if (elem.str!=NULL) {
306	    ERROR1("Cannot set defaults for \"%s\" element in indicator map\n",
307								elem.str);
308	    ACTION2("Assignment to %s.%s ignored\n",elem.str,field.str);
309	    ok= False;
310	}
311	else {
312	    ok=SetIndicatorMapField(&led,xkb,field.str,arrayNdx,var->value)&&ok;
313	}
314    }
315    if (ok) {
316	rtrn= AddIndicatorMap(oldLEDs,&led);
317	return rtrn;
318    }
319    return NULL;
320}
321
322Bool
323CopyIndicatorMapDefs(XkbFileInfo *result,LEDInfo *leds,LEDInfo **unboundRtrn)
324{
325LEDInfo *		led,*next;
326LEDInfo *		unbound,*last;
327XkbDescPtr		xkb;
328
329    xkb= result->xkb;
330    if (XkbAllocNames(xkb,XkbIndicatorNamesMask,0,0)!=Success) {
331	WSGO("Couldn't allocate names\n");
332	ACTION("Indicator names may be incorrect\n");
333    }
334    if (XkbAllocIndicatorMaps(xkb)!=Success) {
335	WSGO("Can't allocate indicator maps\n");
336	ACTION("Indicator map definitions may be lost\n");
337	return False;
338    }
339    last= unbound= (unboundRtrn?*unboundRtrn:NULL);
340    while ((last!=NULL) && (last->defs.next!=NULL)) {
341	last= (LEDInfo *)last->defs.next;
342    }
343    for (led=leds;led!=NULL;led=next) {
344	next= (LEDInfo *)led->defs.next;
345	if ((led->groups!=0)&&(led->which_groups==0))
346	    led->which_groups= XkbIM_UseEffective;
347	if ((led->which_mods==0)&&((led->real_mods)||(led->vmods)))
348	    led->which_mods= XkbIM_UseEffective;
349	if ((led->indicator==_LED_NotBound)||(!xkb->indicators)) {
350	    if (unboundRtrn!=NULL) {
351		led->defs.next= NULL;
352		if (last!=NULL) 	last->defs.next= (CommonInfo *)led;
353		else			unbound= led;
354		last= led;
355	    }
356	    else uFree(led);
357	}
358	else {
359	    register XkbIndicatorMapPtr im;
360	    im= &xkb->indicators->maps[led->indicator-1];
361	    im->flags= led->flags;
362	    im->which_groups= led->which_groups;
363	    im->groups= led->groups;
364	    im->which_mods= led->which_mods;
365	    im->mods.mask= led->real_mods;
366	    im->mods.real_mods= led->real_mods;
367	    im->mods.vmods= led->vmods;
368	    im->ctrls= led->ctrls;
369	    if (xkb->names!=NULL)
370		xkb->names->indicators[led->indicator-1]= led->name;
371	    uFree(led);
372	}
373    }
374    if (unboundRtrn!=NULL) {
375	*unboundRtrn= unbound;
376    }
377    return True;
378}
379
380Bool
381BindIndicators(	XkbFileInfo *	result,
382		Bool		force,
383		LEDInfo *	unbound,
384		LEDInfo **	unboundRtrn)
385{
386XkbDescPtr		xkb;
387register int 		i;
388register LEDInfo	 *led,*next,*last;
389
390    xkb= result->xkb;
391    if (xkb->names!=NULL) {
392	for (led=unbound;led!=NULL;led= (LEDInfo *)led->defs.next) {
393	    if (led->indicator==_LED_NotBound) {
394		for (i=0;i<XkbNumIndicators;i++) {
395		    if (xkb->names->indicators[i]==led->name) {
396			led->indicator= i+1;
397			break;
398		    }
399		}
400	    }
401	}
402	if (force) {
403	    for (led=unbound;led!=NULL;led= (LEDInfo *)led->defs.next) {
404		if (led->indicator==_LED_NotBound) {
405		    for (i=0;i<XkbNumIndicators;i++) {
406			if (xkb->names->indicators[i]==None) {
407			    xkb->names->indicators[i]= led->name;
408			    led->indicator= i+1;
409			    xkb->indicators->phys_indicators&= ~(1<<i);
410			    break;
411			}
412		    }
413		    if (led->indicator==_LED_NotBound) {
414			ERROR("No unnamed indicators found\n");
415			ACTION1("Virtual indicator map \"%s\" not bound\n",
416				XkbAtomGetString(xkb->dpy,led->name));
417			continue;
418		    }
419		}
420	    }
421	}
422    }
423    for (last=NULL,led=unbound;led!=NULL;led= next) {
424	next= (LEDInfo *)led->defs.next;
425	if (led->indicator==_LED_NotBound) {
426	    if (force) {
427		unbound= next;
428		uFree(led);
429	    }
430	    else {
431		if (last)
432		     last->defs.next= &led->defs;
433		else unbound= led;
434		last= led;
435	    }
436	}
437	else {
438	    if ((xkb->names!=NULL)&&
439		(xkb->names->indicators[led->indicator-1]!=led->name)) {
440		Atom old= xkb->names->indicators[led->indicator-1];
441		ERROR1("Multiple names bound to indicator %d\n",(unsigned int)led->indicator);
442		ACTION2("Using %s, ignoring %s\n",
443				XkbAtomGetString(xkb->dpy,old),
444				XkbAtomGetString(xkb->dpy,led->name));
445		led->indicator= _LED_NotBound;
446		if (force) {
447		    uFree(led);
448		    unbound= next;
449		}
450		else {
451		    if (last)
452			 last->defs.next= &led->defs;
453		    else unbound= led;
454		    last= led;
455		}
456	    }
457	    else {
458		XkbIndicatorMapPtr map;
459		map= &xkb->indicators->maps[led->indicator-1];
460		map->flags= led->flags;
461		map->which_groups= led->which_groups;
462		map->groups= led->groups;
463		map->which_mods= led->which_mods;
464		map->mods.mask= led->real_mods;
465		map->mods.real_mods= led->real_mods;
466		map->mods.vmods= led->vmods;
467		map->ctrls= led->ctrls;
468		if (last)	last->defs.next= &next->defs;
469		else		unbound= next;
470		led->defs.next= NULL;
471		uFree(led);
472	    }
473	}
474    }
475    if (unboundRtrn) {
476	*unboundRtrn= unbound;
477    }
478    else if (unbound) {
479	for (led=unbound;led!=NULL;led=next) {
480	    next= (LEDInfo *)led->defs.next;
481	    uFree(led);
482	}
483    }
484    return True;
485}
486