1010cdda0Smrg/************************************************************
2010cdda0Smrg Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3010cdda0Smrg
4010cdda0Smrg Permission to use, copy, modify, and distribute this
5010cdda0Smrg software and its documentation for any purpose and without
6010cdda0Smrg fee is hereby granted, provided that the above copyright
7010cdda0Smrg notice appear in all copies and that both that copyright
8010cdda0Smrg notice and this permission notice appear in supporting
9010cdda0Smrg documentation, and that the name of Silicon Graphics not be
10010cdda0Smrg used in advertising or publicity pertaining to distribution
11010cdda0Smrg of the software without specific prior written permission.
12010cdda0Smrg Silicon Graphics makes no representation about the suitability
13010cdda0Smrg of this software for any purpose. It is provided "as is"
14010cdda0Smrg without any express or implied warranty.
15010cdda0Smrg
16010cdda0Smrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17010cdda0Smrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18010cdda0Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19010cdda0Smrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20010cdda0Smrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21010cdda0Smrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22010cdda0Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23010cdda0Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
24010cdda0Smrg
25010cdda0Smrg ********************************************************/
26010cdda0Smrg
27010cdda0Smrg#include <stdlib.h>
28010cdda0Smrg#include <X11/X.h>
29010cdda0Smrg#include <X11/Xlib.h>
30010cdda0Smrg#include <X11/XKBlib.h>
31010cdda0Smrg#include <X11/Intrinsic.h>
32010cdda0Smrg#include <X11/StringDefs.h>
33010cdda0Smrg#include <X11/Shell.h>
34010cdda0Smrg#include <X11/Xaw/Cardinals.h>
35010cdda0Smrg#include <X11/Xaw/Box.h>
36010cdda0Smrg
37010cdda0Smrg#define	BOOLEAN_DEFINED
38010cdda0Smrg#include "utils.h"
39010cdda0Smrg#include "LED.h"
40010cdda0Smrg
41010cdda0Smrg/***====================================================================***/
42010cdda0Smrg
43010cdda0Smrg#define	YES		1
44010cdda0Smrg#define	NO		0
45010cdda0Smrg#define	DONT_CARE	-1
46010cdda0Smrg
47b4485a66Smrgstatic Display *inDpy, *outDpy;
48b4485a66Smrgstatic unsigned long wanted, real, named, explicit, automatic, virtual;
49b4485a66Smrgstatic char *inDpyName;
50b4485a66Smrgstatic int wantNamed = DONT_CARE;
51b4485a66Smrgstatic int wantExplicit = DONT_CARE;
52b4485a66Smrgstatic int wantAutomatic = DONT_CARE;
53b4485a66Smrgstatic int wantReal = DONT_CARE;
54b4485a66Smrgstatic int wantVirtual = DONT_CARE;
55b4485a66Smrgstatic int evBase, errBase;
56b4485a66Smrgstatic Bool synch;
57b4485a66Smrgstatic Bool useUnion = True;
58010cdda0Smrg
59010cdda0Smrg/***====================================================================***/
60010cdda0Smrg
61010cdda0Smrgstatic void
62010cdda0Smrgusage(char *program)
63010cdda0Smrg{
64b4485a66Smrg    uInformation("Usage: %s <options>\n", program);
65b4485a66Smrg    uInformation("Legal options include the usual X toolkit options plus:\n"
66b4485a66Smrg                 "  -help           Print this message\n"
67b4485a66Smrg                 "  -version        Print the program version\n"
68b4485a66Smrg                 "  -indpy <name>   Name of display to watch\n"
69b4485a66Smrg                 "  -watch <leds>   Mask of LEDs to watch\n"
70b4485a66Smrg                 "  [-+]automatic   (Don't) watch automatic LEDs\n"
71b4485a66Smrg                 "  [-+]explicit    (Don't) watch explicit LEDs\n"
72b4485a66Smrg                 "  [-+]name        (Don't) watch named LEDs\n"
73b4485a66Smrg                 "  [-+]real        (Don't) watch real LEDs\n"
74b4485a66Smrg                 "  [-+]virtual     (Don't) watch virtual LEDs\n"
75b4485a66Smrg                 "  -intersection   Watch only LEDs in all desired sets\n"
76b4485a66Smrg                 "  -union          Watch LEDs in any desired sets\n"
77b4485a66Smrg                 "The default set of LEDs is -union +name +automatic +real\n");
78010cdda0Smrg    return;
79010cdda0Smrg}
80010cdda0Smrg
81010cdda0Smrgstatic Bool
82010cdda0SmrgparseArgs(int argc, char *argv[])
83010cdda0Smrg{
84b4485a66Smrg    register int i;
85010cdda0Smrg
86b4485a66Smrg    for (i = 1; i < argc; i++) {
87b4485a66Smrg        if (uStrCaseEqual(argv[i], "-indpy")) {
88b4485a66Smrg            if (i < argc - 1)
89b4485a66Smrg                inDpyName = argv[++i];
90b4485a66Smrg            else {
91b4485a66Smrg                uWarning("No name specified for input display\n");
92b4485a66Smrg                uAction("Ignoring trailing -indpy argument\n");
93b4485a66Smrg            }
94b4485a66Smrg        }
95b4485a66Smrg        else if (uStrCaseEqual(argv[i], "-watch")) {
96b4485a66Smrg            if (i < argc - 1) {
97b4485a66Smrg                int tmp;
98b4485a66Smrg
99b4485a66Smrg                if (sscanf(argv[++i], "%i", &tmp) != 1) {
100b4485a66Smrg                    uWarning("Set of LEDs must be specified as an integer\n");
101b4485a66Smrg                    uAction("Ignoring bogus value \"%s\" for -watch flag\n",
102b4485a66Smrg                            argv[i]);
103b4485a66Smrg                }
104b4485a66Smrg                else
105b4485a66Smrg                    wanted = tmp;
106b4485a66Smrg            }
107b4485a66Smrg            else {
108b4485a66Smrg                uWarning("Didn't specify any LEDs to watch\n");
109b4485a66Smrg                uAction("Ignoring trailing -watch argument\n");
110b4485a66Smrg            }
111b4485a66Smrg        }
112b4485a66Smrg        else if (uStrCaseEqual(argv[i], "-union")) {
113b4485a66Smrg            useUnion = True;
114b4485a66Smrg        }
115b4485a66Smrg        else if (uStrCaseEqual(argv[i], "-intersection")) {
116b4485a66Smrg            useUnion = False;
117b4485a66Smrg        }
118b4485a66Smrg        else if (uStrCaseEqual(argv[i], "-help")) {
119b4485a66Smrg            usage(argv[0]);
120b4485a66Smrg            exit(0);
121b4485a66Smrg        }
122b4485a66Smrg        else if (uStrCaseEqual(argv[i], "-version")) {
123b4485a66Smrg            printf("xkbvleds (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
124b4485a66Smrg            exit(0);
125b4485a66Smrg        }
126b4485a66Smrg        else if ((argv[i][0] == '+') || (argv[i][0] == '-')) {
127b4485a66Smrg            Bool onoff;
128b4485a66Smrg            int *which;
129b4485a66Smrg
130b4485a66Smrg            onoff = (argv[i][0] == '+');
131b4485a66Smrg            which = NULL;
132b4485a66Smrg            if (uStrCaseEqual(&argv[i][1], "name"))
133b4485a66Smrg                which = &wantNamed;
134b4485a66Smrg            else if (uStrCaseEqual(&argv[i][1], "explicit"))
135b4485a66Smrg                which = &wantExplicit;
136b4485a66Smrg            else if (uStrCaseEqual(&argv[i][1], "automatic"))
137b4485a66Smrg                which = &wantAutomatic;
138b4485a66Smrg            else if (uStrCaseEqual(&argv[i][1], "real"))
139b4485a66Smrg                which = &wantReal;
140b4485a66Smrg            else if (uStrCaseEqual(&argv[i][1], "virtual"))
141b4485a66Smrg                which = &wantVirtual;
142b4485a66Smrg            if (which != NULL) {
143b4485a66Smrg                if (*which != DONT_CARE) {
144b4485a66Smrg                    uWarning("Multiple settings for [+-]%s\n", &argv[i][1]);
145b4485a66Smrg                    uAction("Using %c%s, ignoring %c%s\n",
146b4485a66Smrg                            (onoff ? '+' : '-'), &argv[i][1],
147b4485a66Smrg                            (onoff ? '-' : '+'), &argv[i][1]);
148b4485a66Smrg                }
149b4485a66Smrg                *which = (onoff ? YES : NO);
150b4485a66Smrg            }
151b4485a66Smrg        }
152010cdda0Smrg    }
153010cdda0Smrg    return True;
154010cdda0Smrg}
155010cdda0Smrg
156010cdda0Smrg/***====================================================================***/
157010cdda0Smrg
158010cdda0Smrgstatic Display *
159010cdda0SmrgGetDisplay(char *program, char *dpyName)
160010cdda0Smrg{
161b4485a66Smrg    int mjr, mnr, error;
162b4485a66Smrg    Display *dpy;
163010cdda0Smrg
164b4485a66Smrg    mjr = XkbMajorVersion;
165b4485a66Smrg    mnr = XkbMinorVersion;
166b4485a66Smrg    dpy = XkbOpenDisplay(dpyName, &evBase, &errBase, &mjr, &mnr, &error);
167b4485a66Smrg    if (dpy == NULL) {
168b4485a66Smrg        switch (error) {
169b4485a66Smrg        case XkbOD_BadLibraryVersion:
170b4485a66Smrg            uInformation("%s was compiled with XKB version %d.%02d\n",
171b4485a66Smrg                         program, XkbMajorVersion, XkbMinorVersion);
172b4485a66Smrg            uError("X library supports incompatible version %d.%02d\n",
173b4485a66Smrg                   mjr, mnr);
174b4485a66Smrg            break;
175b4485a66Smrg        case XkbOD_ConnectionRefused:
176b4485a66Smrg            uError("Cannot open display \"%s\"\n", dpyName);
177b4485a66Smrg            break;
178b4485a66Smrg        case XkbOD_NonXkbServer:
179b4485a66Smrg            uError("XKB extension not present on %s\n", dpyName);
180b4485a66Smrg            break;
181b4485a66Smrg        case XkbOD_BadServerVersion:
182b4485a66Smrg            uInformation("%s was compiled with XKB version %d.%02d\n",
183b4485a66Smrg                         program, XkbMajorVersion, XkbMinorVersion);
184b4485a66Smrg            uError("Server %s uses incompatible version %d.%02d\n",
185b4485a66Smrg                   dpyName, mjr, mnr);
186b4485a66Smrg            break;
187b4485a66Smrg        default:
188b4485a66Smrg            uInternalError("Unknown error %d from XkbOpenDisplay\n", error);
189b4485a66Smrg        }
190010cdda0Smrg    }
191010cdda0Smrg    else if (synch)
192b4485a66Smrg        XSynchronize(dpy, True);
193010cdda0Smrg    return dpy;
194010cdda0Smrg}
195010cdda0Smrg
196010cdda0Smrg/***====================================================================***/
197010cdda0Smrg
198010cdda0Smrgint
199010cdda0Smrgmain(int argc, char *argv[])
200010cdda0Smrg{
201b4485a66Smrg    Widget toplevel;
202b4485a66Smrg    XtAppContext app_con;
203b4485a66Smrg    Widget panel;
204b4485a66Smrg    Widget leds[XkbNumIndicators];
205b4485a66Smrg    register int i;
206b4485a66Smrg    unsigned bit;
207b4485a66Smrg    unsigned n;
208b4485a66Smrg    XkbDescPtr xkb;
209b4485a66Smrg    XkbEvent ev;
210b4485a66Smrg    static Arg boxArgs[] = { {XtNorientation, (XtArgVal) XtorientHorizontal} };
211b4485a66Smrg    static Arg onArgs[] = { {XtNon, (XtArgVal) True} };
212b4485a66Smrg    static Arg offArgs[] = { {XtNon, (XtArgVal) False} };
213945aa7e3Smrg    static String fallback_resources[] = {
214b4485a66Smrg        "*Box*background: grey40",
215b4485a66Smrg        NULL
216b4485a66Smrg    };
217010cdda0Smrg
218b4485a66Smrg    bzero(leds, XkbNumIndicators * sizeof(Widget));
219b4485a66Smrg    toplevel = XtOpenApplication(&app_con, "XkbLEDPanel", NULL, 0, &argc, argv,
220b4485a66Smrg                                 fallback_resources,
221b4485a66Smrg                                 sessionShellWidgetClass, NULL, ZERO);
222b4485a66Smrg    if (toplevel == NULL) {
223b4485a66Smrg        uFatalError("Couldn't create application top level\n");
224b4485a66Smrg        return 1;
225010cdda0Smrg    }
226b4485a66Smrg    if ((argc > 1) && (!parseArgs(argc, argv))) {
227b4485a66Smrg        usage(argv[0]);
228b4485a66Smrg        return 1;
229010cdda0Smrg    }
230b4485a66Smrg    if ((wanted == 0) && (wantNamed == DONT_CARE) && (wantExplicit == DONT_CARE)
231b4485a66Smrg        && (wantAutomatic == DONT_CARE) && (wantReal == DONT_CARE)) {
232b4485a66Smrg        wantNamed = YES;
233b4485a66Smrg        wantReal = YES;
234b4485a66Smrg        wantAutomatic = YES;
235010cdda0Smrg    }
236b4485a66Smrg    outDpy = XtDisplay(toplevel);
237b4485a66Smrg    if (inDpyName != NULL) {
238b4485a66Smrg        inDpy = GetDisplay(argv[0], inDpyName);
239b4485a66Smrg        if (!inDpy)
240b4485a66Smrg            return 1;
241010cdda0Smrg    }
242010cdda0Smrg    else {
243b4485a66Smrg        inDpy = outDpy;
244010cdda0Smrg    }
245010cdda0Smrg    if (inDpy) {
246b4485a66Smrg        int i1, mn, mj;
247b4485a66Smrg
248b4485a66Smrg        mj = XkbMajorVersion;
249b4485a66Smrg        mn = XkbMinorVersion;
250b4485a66Smrg        if (!XkbLibraryVersion(&mj, &mn)) {
251b4485a66Smrg            uInformation("%s was compiled with XKB version %d.%02d\n",
252b4485a66Smrg                         argv[0], XkbMajorVersion, XkbMinorVersion);
253b4485a66Smrg            uError("X library supports incompatible version %d.%02d\n", mj, mn);
254b4485a66Smrg        }
255b4485a66Smrg        if (!XkbQueryExtension(inDpy, &i1, &evBase, &errBase, &mj, &mn)) {
256b4485a66Smrg            uFatalError("Server doesn't support a compatible XKB\n");
257b4485a66Smrg            return 1;
258b4485a66Smrg        }
259010cdda0Smrg    }
260010cdda0Smrg    else {
261b4485a66Smrg        uFatalError("No input display\n");
262b4485a66Smrg        return 1;
263010cdda0Smrg    }
264b4485a66Smrg    panel =
265b4485a66Smrg        XtCreateManagedWidget("xkbleds", boxWidgetClass, toplevel, boxArgs, 1);
266b4485a66Smrg    if (panel == NULL) {
267b4485a66Smrg        uFatalError("Couldn't create list of leds\n");
268b4485a66Smrg        return 1;
269010cdda0Smrg    }
270b4485a66Smrg    real = virtual = named = explicit = automatic = 0;
271010cdda0Smrg    if (wantReal || wantNamed || wantAutomatic || wantExplicit || wantVirtual) {
272b4485a66Smrg        register int i, bit;
273b4485a66Smrg
274b4485a66Smrg        xkb = XkbGetMap(inDpy, 0, XkbUseCoreKbd);
275b4485a66Smrg        if (!xkb) {
276b4485a66Smrg            uFatalError("Couldn't read keymap\n");
277b4485a66Smrg            return 1;
278b4485a66Smrg        }
279b4485a66Smrg        if (XkbGetIndicatorMap(inDpy, XkbAllIndicatorsMask, xkb) != Success) {
280b4485a66Smrg            uFatalError("Couldn't read indicator map\n");
281b4485a66Smrg            return 1;
282b4485a66Smrg        }
283b4485a66Smrg        if (XkbGetNames(inDpy, XkbAllNamesMask, xkb) != Success) {
284b4485a66Smrg            uFatalError("Couldn't read indicator names\n");
285b4485a66Smrg            return 1;
286b4485a66Smrg        }
287b4485a66Smrg        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
288b4485a66Smrg            XkbIndicatorMapPtr map = &xkb->indicators->maps[i];
289b4485a66Smrg
290b4485a66Smrg            if (xkb->names->indicators[i] != None)
291b4485a66Smrg                named |= bit;
292b4485a66Smrg            if (xkb->indicators->phys_indicators & bit)
293b4485a66Smrg                real |= bit;
294b4485a66Smrg            if ((((map->which_groups != 0) && (map->groups != 0)) ||
295b4485a66Smrg                 ((map->which_mods != 0) &&
296b4485a66Smrg                  ((map->mods.real_mods != 0) || (map->mods.vmods != 0))) ||
297b4485a66Smrg                 (map->ctrls != 0)) &&
298b4485a66Smrg                ((map->flags & XkbIM_NoAutomatic) == 0)) {
299b4485a66Smrg                automatic |= bit;
300b4485a66Smrg            }
301b4485a66Smrg            else
302b4485a66Smrg                explicit |= bit;
303b4485a66Smrg        }
304b4485a66Smrg        virtual = ~real;
305b4485a66Smrg        if (wantReal == NO)
306b4485a66Smrg            real = ~real;
307b4485a66Smrg        else if (wantReal == DONT_CARE)
308b4485a66Smrg            real = (useUnion ? 0 : ~0);
309b4485a66Smrg        if (wantVirtual == NO)
310b4485a66Smrg            virtual = ~virtual;
311b4485a66Smrg        else if (wantVirtual == DONT_CARE)
312b4485a66Smrg            virtual = (useUnion ? 0 : ~0);
313b4485a66Smrg        if (wantNamed == NO)
314b4485a66Smrg            named = ~named;
315b4485a66Smrg        else if (wantNamed == DONT_CARE)
316b4485a66Smrg            named = (useUnion ? 0 : ~0);
317b4485a66Smrg        if (wantAutomatic == NO)
318b4485a66Smrg            automatic = ~automatic;
319b4485a66Smrg        else if (wantAutomatic == DONT_CARE)
320b4485a66Smrg            automatic = (useUnion ? 0 : ~0);
321b4485a66Smrg        if (wantExplicit == NO)
322b4485a66Smrg            explicit = ~explicit;
323b4485a66Smrg        else if (wantExplicit == DONT_CARE)
324b4485a66Smrg            explicit = (useUnion ? 0 : ~0);
325b4485a66Smrg        if (useUnion)
326b4485a66Smrg            wanted |= real | virtual | named | automatic | explicit;
327b4485a66Smrg        else
328b4485a66Smrg            wanted &= real & virtual & named & automatic & explicit;
329010cdda0Smrg    }
330b4485a66Smrg    else
331b4485a66Smrg        xkb = NULL;
332b4485a66Smrg    if (wanted == 0) {
333b4485a66Smrg        uError("No indicator maps match the selected criteria\n");
334b4485a66Smrg        uAction("Exiting\n");
335b4485a66Smrg        return 1;
336010cdda0Smrg    }
337010cdda0Smrg
338b4485a66Smrg    XkbSelectEvents(inDpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
339b4485a66Smrg                    XkbIndicatorStateNotifyMask);
340b4485a66Smrg    XkbGetIndicatorState(inDpy, XkbUseCoreKbd, &n);
341b4485a66Smrg    bit = (1U << (XkbNumIndicators - 1));
342b4485a66Smrg    for (i = XkbNumIndicators - 1; i >= 0; i--, bit >>= 1) {
343b4485a66Smrg        if (wanted & bit) {
344b4485a66Smrg            char buf[12];
345b4485a66Smrg            ArgList list;
346010cdda0Smrg
347affd2f3fSmrg            snprintf(buf, sizeof(buf), "led%d", i + 1);
348b4485a66Smrg            if (n & bit)
349b4485a66Smrg                list = onArgs;
350b4485a66Smrg            else
351b4485a66Smrg                list = offArgs;
352b4485a66Smrg            leds[i] =
353b4485a66Smrg                XtCreateManagedWidget(buf, ledWidgetClass, panel, list, 1);
354b4485a66Smrg        }
355010cdda0Smrg    }
356010cdda0Smrg    XtRealizeWidget(toplevel);
357010cdda0Smrg    while (1) {
358b4485a66Smrg        XtAppNextEvent(app_con, &ev.core);
359b4485a66Smrg        if (ev.core.type == evBase + XkbEventCode) {
360b4485a66Smrg            if (ev.any.xkb_type == XkbIndicatorStateNotify) {
361b4485a66Smrg                for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
362b4485a66Smrg                    if ((ev.indicators.changed & bit) && (leds[i])) {
363b4485a66Smrg                        ArgList list;
364b4485a66Smrg
365b4485a66Smrg                        if (ev.indicators.state & bit)
366b4485a66Smrg                            list = onArgs;
367b4485a66Smrg                        else
368b4485a66Smrg                            list = offArgs;
369b4485a66Smrg                        XtSetValues(leds[i], list, 1);
370b4485a66Smrg                    }
371b4485a66Smrg                }
372b4485a66Smrg            }
373b4485a66Smrg        }
374b4485a66Smrg        else
375b4485a66Smrg            XtDispatchEvent(&ev.core);
376010cdda0Smrg    }
377010cdda0Smrg/* BAIL: */
378b4485a66Smrg    if (inDpy)
379b4485a66Smrg        XCloseDisplay(inDpy);
380b4485a66Smrg    if (outDpy != inDpy)
381b4485a66Smrg        XCloseDisplay(outDpy);
382b4485a66Smrg    inDpy = outDpy = NULL;
383010cdda0Smrg    return 0;
384010cdda0Smrg}
385