xkbvleds.c revision b3eb03f3
1/* $Xorg: xkbvleds.c,v 1.4 2000/08/17 19:54:51 cpqbld Exp $ */
2/************************************************************
3 Copyright (c) 1995 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/xkbutils/xkbvleds.c,v 3.4 2001/01/17 23:46:14 dawes Exp $ */
28
29#include <stdlib.h>
30#include <X11/X.h>
31#include <X11/Xlib.h>
32#include <X11/XKBlib.h>
33#include <X11/Intrinsic.h>
34#include <X11/StringDefs.h>
35#include <X11/Shell.h>
36#include <X11/Xaw/Cardinals.h>
37#include <X11/Xaw/Box.h>
38
39#define	OPAQUE_DEFINED
40#define	BOOLEAN_DEFINED
41#define	DEBUG_VAR_NOT_LOCAL
42#define	DEBUG_VAR debugFlags
43#include "utils.h"
44#include "LED.h"
45
46/***====================================================================***/
47
48#define	YES		1
49#define	NO		0
50#define	DONT_CARE	-1
51
52static	Display *	inDpy,*outDpy;
53static	unsigned long	wanted,real,named,explicit,automatic,virtual;
54static	char *		inDpyName;
55static	int		wantNamed= DONT_CARE;
56static	int		wantExplicit= DONT_CARE;
57static	int		wantAutomatic= DONT_CARE;
58static	int		wantReal= DONT_CARE;
59static	int		wantVirtual= DONT_CARE;
60static	int		evBase,errBase;
61static	Bool		synch;
62static	Bool		useUnion= True;
63
64/***====================================================================***/
65
66static void
67usage(char *program)
68{
69    uInformation("Usage: %s <options>\n",program);
70    uInformation("Legal options include the usual X toolkit options plus:\n");
71    uInformation("  -help           Print this message\n");
72    uInformation("  -indpy <name>   Name of display to watch\n");
73    uInformation("  -watch <leds>   Mask of LEDs to watch\n");
74    uInformation("  [-+]automatic   (Don't) watch automatic LEDs\n");
75    uInformation("  [-+]explicit    (Don't) watch explicit LEDs\n");
76    uInformation("  [-+]name        (Don't) watch named LEDs\n");
77    uInformation("  [-+]real        (Don't) watch real LEDs\n");
78    uInformation("  [-+]virtual     (Don't) watch virtual LEDs\n");
79    uInformation("  -intersection   Watch only LEDs in all desired sets\n");
80    uInformation("  -union          Watch LEDs in any desired sets\n");
81    uInformation("The default set of LEDs is -union +name +automatic +real\n");
82    return;
83}
84
85static Bool
86parseArgs(int argc, char *argv[])
87{
88register int 	i;
89
90    for (i=1;i<argc;i++) {
91	if (uStrCaseEqual(argv[i],"-indpy")) {
92	    if (i<argc-1)	inDpyName= argv[++i];
93	    else {
94		uWarning("No name specified for input display\n");
95		uAction("Ignoring trailing -indpy argument\n");
96	    }
97	}
98	else if (uStrCaseEqual(argv[i],"-watch")) {
99	    if (i<argc-1) {
100		int tmp;
101		if (sscanf(argv[++i],"%i",&tmp)!=1) {
102		    uWarning("Set of LEDs must be specified as an integer\n");
103		    uAction("Ignoring bogus value \"%s\" for -watch flag\n",
104								argv[i]);
105		}
106		else wanted= tmp;
107	    }
108	    else {
109		uWarning("Didn't specify any LEDs to watch\n");
110		uAction("Ignoring trailing -watch argument\n");
111	    }
112	}
113	else if (uStrCaseEqual(argv[i],"-union")) {
114	    useUnion= True;
115	}
116	else if (uStrCaseEqual(argv[i],"-intersection")) {
117	    useUnion= False;
118	}
119	else if (uStrCaseEqual(argv[i],"-help")) {
120	    usage(argv[0]);
121	    exit(0);
122	}
123	else if ((argv[i][0]=='+')||(argv[i][0]=='-')) {
124	    Bool 	onoff;
125	    int	 *	which;
126	    onoff= (argv[i][0]=='+');
127	    which= NULL;
128	    if (uStrCaseEqual(&argv[i][1],"name"))
129		 which= &wantNamed;
130	    else if (uStrCaseEqual(&argv[i][1],"explicit"))
131		 which= &wantExplicit;
132	    else if (uStrCaseEqual(&argv[i][1],"automatic"))
133		 which= &wantAutomatic;
134	    else if (uStrCaseEqual(&argv[i][1],"real"))
135		 which= &wantReal;
136	    else if (uStrCaseEqual(&argv[i][1],"virtual"))
137		 which= &wantVirtual;
138	    if (which!=NULL) {
139		if (*which!=DONT_CARE) {
140		    uWarning("Multiple settings for [+-]%s\n",&argv[i][1]);
141		    uAction("Using %c%s, ignoring %c%s\n",
142					(onoff?'+':'-'),&argv[i][1],
143					(onoff?'-':'+'),&argv[i][1]);
144		}
145		*which= (onoff?YES:NO);
146	    }
147	}
148    }
149    return True;
150}
151
152/***====================================================================***/
153
154static Display *
155GetDisplay(char *program, char *dpyName)
156{
157int		mjr,mnr,error;
158Display	*	dpy;
159
160    mjr= XkbMajorVersion;
161    mnr= XkbMinorVersion;
162    dpy= XkbOpenDisplay(dpyName,&evBase,&errBase,&mjr,&mnr,&error);
163    if (dpy==NULL) {
164	switch (error) {
165	    case XkbOD_BadLibraryVersion:
166		uInformation("%s was compiled with XKB version %d.%02d\n",
167				program,XkbMajorVersion,XkbMinorVersion);
168		uError("X library supports incompatible version %d.%02d\n",
169				mjr,mnr);
170		break;
171	    case XkbOD_ConnectionRefused:
172		uError("Cannot open display \"%s\"\n",dpyName);
173		break;
174	    case XkbOD_NonXkbServer:
175		uError("XKB extension not present on %s\n",dpyName);
176		break;
177	    case XkbOD_BadServerVersion:
178		uInformation("%s was compiled with XKB version %d.%02d\n",
179				program,XkbMajorVersion,XkbMinorVersion);
180		uError("Server %s uses incompatible version %d.%02d\n",
181				dpyName,mjr,mnr);
182		break;
183	    default:
184		uInternalError("Unknown error %d from XkbOpenDisplay\n",error);
185	}
186    }
187    else if (synch)
188	XSynchronize(dpy,True);
189    return dpy;
190}
191
192/***====================================================================***/
193
194int
195main(int argc, char *argv[])
196{
197Widget		toplevel;
198XtAppContext	app_con;
199Widget		panel;
200Widget		leds[XkbNumIndicators];
201register int	i;
202unsigned	bit;
203unsigned	n;
204XkbDescPtr	xkb;
205XkbEvent	ev;
206static Arg	boxArgs[]= {{ XtNorientation, (XtArgVal)XtorientHorizontal }};
207static Arg	onArgs[]=  {{ XtNon, (XtArgVal)True }};
208static Arg	offArgs[]=  {{ XtNon, (XtArgVal)False }};
209static char *	fallback_resources[] = {
210    "*Box*background: grey40",
211    NULL
212};
213
214    uSetEntryFile(NullString);
215    uSetDebugFile(NullString);
216    uSetErrorFile(NullString);
217    bzero(leds,XkbNumIndicators*sizeof(Widget));
218    toplevel = XtOpenApplication(&app_con, "XkbLEDPanel", NULL, 0, &argc, argv,
219				 fallback_resources,
220				 sessionShellWidgetClass, NULL, ZERO);
221    if (toplevel==NULL) {
222	uFatalError("Couldn't create application top level\n");
223	return 1;
224    }
225    if ((argc>1)&&(!parseArgs(argc,argv))) {
226	usage(argv[0]);
227	return 1;
228    }
229    if ((wanted==0)&&(wantNamed==DONT_CARE)&&(wantExplicit==DONT_CARE)&&
230			(wantAutomatic==DONT_CARE)&&(wantReal==DONT_CARE)) {
231	wantNamed= YES;
232	wantReal= YES;
233	wantAutomatic= YES;
234    }
235    outDpy= XtDisplay(toplevel);
236    if (inDpyName!=NULL) {
237	inDpy= GetDisplay(argv[0],inDpyName);
238	if (!inDpy)
239	    return 1;
240    }
241    else {
242	inDpy= outDpy;
243    }
244    if (inDpy) {
245	int i1,mn,mj;
246	mj= XkbMajorVersion;
247	mn= XkbMinorVersion;
248	if (!XkbLibraryVersion(&mj,&mn)) {
249	    uInformation("%s was compiled with XKB version %d.%02d\n",
250				argv[0],XkbMajorVersion,XkbMinorVersion);
251	    uError("X library supports incompatible version %d.%02d\n",
252				mj,mn);
253	}
254	if (!XkbQueryExtension(inDpy,&i1,&evBase,&errBase,&mj,&mn)) {
255	    uFatalError("Server doesn't support a compatible XKB\n");
256	    return 1;
257	}
258    }
259    else {
260	uFatalError("No input display\n");
261	return 1;
262    }
263    panel= XtCreateManagedWidget("xkbleds",boxWidgetClass,toplevel,boxArgs,1);
264    if (panel==NULL) {
265	uFatalError("Couldn't create list of leds\n");
266	return 1;
267    }
268    real= virtual= named= explicit= automatic= 0;
269    if (wantReal || wantNamed || wantAutomatic || wantExplicit || wantVirtual) {
270	register int i,bit;
271	xkb= XkbGetMap(inDpy,0,XkbUseCoreKbd);
272	if (!xkb) {
273	    uFatalError("Couldn't read keymap\n");
274	    return 1;
275	}
276	if (XkbGetIndicatorMap(inDpy,XkbAllIndicatorsMask,xkb)!=Success) {
277	    uFatalError("Couldn't read indicator map\n");
278	    return 1;
279	}
280	if (XkbGetNames(inDpy,XkbAllNamesMask,xkb)!=Success) {
281	    uFatalError("Couldn't read indicator names\n");
282	    return 1;
283	}
284	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
285	    XkbIndicatorMapPtr map= &xkb->indicators->maps[i];
286	    if (xkb->names->indicators[i]!=None)
287		named|= bit;
288	    if (xkb->indicators->phys_indicators&bit)
289		real|= bit;
290	    if ((((map->which_groups!=0)&&(map->groups!=0))||
291		((map->which_mods!=0)&&
292		((map->mods.real_mods!=0)||(map->mods.vmods!=0)))||
293		(map->ctrls!=0))&&
294		((map->flags&XkbIM_NoAutomatic)==0)) {
295		automatic|= bit;
296	    }
297	    else explicit|= bit;
298	}
299	virtual= ~real;
300	if (wantReal==NO)			real= ~real;
301	else if (wantReal==DONT_CARE)		real= (useUnion?0:~0);
302	if (wantVirtual==NO)			virtual= ~virtual;
303	else if (wantVirtual==DONT_CARE)	virtual= (useUnion?0:~0);
304	if (wantNamed==NO)			named= ~named;
305	else if (wantNamed==DONT_CARE)		named= (useUnion?0:~0);
306	if (wantAutomatic==NO)			automatic= ~automatic;
307	else if (wantAutomatic==DONT_CARE)	automatic= (useUnion?0:~0);
308	if (wantExplicit==NO)			explicit= ~explicit;
309	else if (wantExplicit==DONT_CARE)	explicit= (useUnion?0:~0);
310	if (useUnion)
311	     wanted|= real|virtual|named|automatic|explicit;
312	else wanted&= real&virtual&named&automatic&explicit;
313    }
314    else xkb= NULL;
315    if (wanted==0) {
316	uError("No indicator maps match the selected criteria\n");
317	uAction("Exiting\n");
318	return 1;
319    }
320
321    XkbSelectEvents(inDpy,XkbUseCoreKbd,XkbIndicatorStateNotifyMask,
322						XkbIndicatorStateNotifyMask);
323    XkbGetIndicatorState(inDpy,XkbUseCoreKbd,&n);
324    bit= (1<<(XkbNumIndicators-1));
325    for (i=XkbNumIndicators-1;i>=0;i--,bit>>=1) {
326	if (wanted&bit) {
327	    char 	buf[12];
328	    ArgList	list;
329
330	    sprintf(buf,"led%d",i+1);
331	    if (n&bit)	list= onArgs;
332	    else	list= offArgs;
333	    leds[i]= XtCreateManagedWidget(buf,ledWidgetClass,panel,list,1);
334	}
335    }
336    XtRealizeWidget(toplevel);
337    while (1) {
338        XtAppNextEvent(app_con,&ev.core);
339	if (ev.core.type==evBase+XkbEventCode) {
340	    if (ev.any.xkb_type==XkbIndicatorStateNotify) {
341		for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
342		    if ((ev.indicators.changed&bit)&&(leds[i])) {
343			ArgList	list;
344			if (ev.indicators.state&bit)	list= onArgs;
345			else				list= offArgs;
346			XtSetValues(leds[i],list,1);
347		    }
348		}
349	    }
350	}
351	else XtDispatchEvent(&ev.core);
352    }
353/* BAIL: */
354    if (inDpy)
355	XCloseDisplay(inDpy);
356    if (outDpy!=inDpy)
357	XCloseDisplay(outDpy);
358    inDpy= outDpy= NULL;
359    return 0;
360}
361