xkbvleds.c revision b4485a66
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} };
213b4485a66Smrg    static char *fallback_resources[] = {
214b4485a66Smrg        "*Box*background: grey40",
215b4485a66Smrg        NULL
216b4485a66Smrg    };
217010cdda0Smrg
218010cdda0Smrg    uSetErrorFile(NullString);
219b4485a66Smrg    bzero(leds, XkbNumIndicators * sizeof(Widget));
220b4485a66Smrg    toplevel = XtOpenApplication(&app_con, "XkbLEDPanel", NULL, 0, &argc, argv,
221b4485a66Smrg                                 fallback_resources,
222b4485a66Smrg                                 sessionShellWidgetClass, NULL, ZERO);
223b4485a66Smrg    if (toplevel == NULL) {
224b4485a66Smrg        uFatalError("Couldn't create application top level\n");
225b4485a66Smrg        return 1;
226010cdda0Smrg    }
227b4485a66Smrg    if ((argc > 1) && (!parseArgs(argc, argv))) {
228b4485a66Smrg        usage(argv[0]);
229b4485a66Smrg        return 1;
230010cdda0Smrg    }
231b4485a66Smrg    if ((wanted == 0) && (wantNamed == DONT_CARE) && (wantExplicit == DONT_CARE)
232b4485a66Smrg        && (wantAutomatic == DONT_CARE) && (wantReal == DONT_CARE)) {
233b4485a66Smrg        wantNamed = YES;
234b4485a66Smrg        wantReal = YES;
235b4485a66Smrg        wantAutomatic = YES;
236010cdda0Smrg    }
237b4485a66Smrg    outDpy = XtDisplay(toplevel);
238b4485a66Smrg    if (inDpyName != NULL) {
239b4485a66Smrg        inDpy = GetDisplay(argv[0], inDpyName);
240b4485a66Smrg        if (!inDpy)
241b4485a66Smrg            return 1;
242010cdda0Smrg    }
243010cdda0Smrg    else {
244b4485a66Smrg        inDpy = outDpy;
245010cdda0Smrg    }
246010cdda0Smrg    if (inDpy) {
247b4485a66Smrg        int i1, mn, mj;
248b4485a66Smrg
249b4485a66Smrg        mj = XkbMajorVersion;
250b4485a66Smrg        mn = XkbMinorVersion;
251b4485a66Smrg        if (!XkbLibraryVersion(&mj, &mn)) {
252b4485a66Smrg            uInformation("%s was compiled with XKB version %d.%02d\n",
253b4485a66Smrg                         argv[0], XkbMajorVersion, XkbMinorVersion);
254b4485a66Smrg            uError("X library supports incompatible version %d.%02d\n", mj, mn);
255b4485a66Smrg        }
256b4485a66Smrg        if (!XkbQueryExtension(inDpy, &i1, &evBase, &errBase, &mj, &mn)) {
257b4485a66Smrg            uFatalError("Server doesn't support a compatible XKB\n");
258b4485a66Smrg            return 1;
259b4485a66Smrg        }
260010cdda0Smrg    }
261010cdda0Smrg    else {
262b4485a66Smrg        uFatalError("No input display\n");
263b4485a66Smrg        return 1;
264010cdda0Smrg    }
265b4485a66Smrg    panel =
266b4485a66Smrg        XtCreateManagedWidget("xkbleds", boxWidgetClass, toplevel, boxArgs, 1);
267b4485a66Smrg    if (panel == NULL) {
268b4485a66Smrg        uFatalError("Couldn't create list of leds\n");
269b4485a66Smrg        return 1;
270010cdda0Smrg    }
271b4485a66Smrg    real = virtual = named = explicit = automatic = 0;
272010cdda0Smrg    if (wantReal || wantNamed || wantAutomatic || wantExplicit || wantVirtual) {
273b4485a66Smrg        register int i, bit;
274b4485a66Smrg
275b4485a66Smrg        xkb = XkbGetMap(inDpy, 0, XkbUseCoreKbd);
276b4485a66Smrg        if (!xkb) {
277b4485a66Smrg            uFatalError("Couldn't read keymap\n");
278b4485a66Smrg            return 1;
279b4485a66Smrg        }
280b4485a66Smrg        if (XkbGetIndicatorMap(inDpy, XkbAllIndicatorsMask, xkb) != Success) {
281b4485a66Smrg            uFatalError("Couldn't read indicator map\n");
282b4485a66Smrg            return 1;
283b4485a66Smrg        }
284b4485a66Smrg        if (XkbGetNames(inDpy, XkbAllNamesMask, xkb) != Success) {
285b4485a66Smrg            uFatalError("Couldn't read indicator names\n");
286b4485a66Smrg            return 1;
287b4485a66Smrg        }
288b4485a66Smrg        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
289b4485a66Smrg            XkbIndicatorMapPtr map = &xkb->indicators->maps[i];
290b4485a66Smrg
291b4485a66Smrg            if (xkb->names->indicators[i] != None)
292b4485a66Smrg                named |= bit;
293b4485a66Smrg            if (xkb->indicators->phys_indicators & bit)
294b4485a66Smrg                real |= bit;
295b4485a66Smrg            if ((((map->which_groups != 0) && (map->groups != 0)) ||
296b4485a66Smrg                 ((map->which_mods != 0) &&
297b4485a66Smrg                  ((map->mods.real_mods != 0) || (map->mods.vmods != 0))) ||
298b4485a66Smrg                 (map->ctrls != 0)) &&
299b4485a66Smrg                ((map->flags & XkbIM_NoAutomatic) == 0)) {
300b4485a66Smrg                automatic |= bit;
301b4485a66Smrg            }
302b4485a66Smrg            else
303b4485a66Smrg                explicit |= bit;
304b4485a66Smrg        }
305b4485a66Smrg        virtual = ~real;
306b4485a66Smrg        if (wantReal == NO)
307b4485a66Smrg            real = ~real;
308b4485a66Smrg        else if (wantReal == DONT_CARE)
309b4485a66Smrg            real = (useUnion ? 0 : ~0);
310b4485a66Smrg        if (wantVirtual == NO)
311b4485a66Smrg            virtual = ~virtual;
312b4485a66Smrg        else if (wantVirtual == DONT_CARE)
313b4485a66Smrg            virtual = (useUnion ? 0 : ~0);
314b4485a66Smrg        if (wantNamed == NO)
315b4485a66Smrg            named = ~named;
316b4485a66Smrg        else if (wantNamed == DONT_CARE)
317b4485a66Smrg            named = (useUnion ? 0 : ~0);
318b4485a66Smrg        if (wantAutomatic == NO)
319b4485a66Smrg            automatic = ~automatic;
320b4485a66Smrg        else if (wantAutomatic == DONT_CARE)
321b4485a66Smrg            automatic = (useUnion ? 0 : ~0);
322b4485a66Smrg        if (wantExplicit == NO)
323b4485a66Smrg            explicit = ~explicit;
324b4485a66Smrg        else if (wantExplicit == DONT_CARE)
325b4485a66Smrg            explicit = (useUnion ? 0 : ~0);
326b4485a66Smrg        if (useUnion)
327b4485a66Smrg            wanted |= real | virtual | named | automatic | explicit;
328b4485a66Smrg        else
329b4485a66Smrg            wanted &= real & virtual & named & automatic & explicit;
330010cdda0Smrg    }
331b4485a66Smrg    else
332b4485a66Smrg        xkb = NULL;
333b4485a66Smrg    if (wanted == 0) {
334b4485a66Smrg        uError("No indicator maps match the selected criteria\n");
335b4485a66Smrg        uAction("Exiting\n");
336b4485a66Smrg        return 1;
337010cdda0Smrg    }
338010cdda0Smrg
339b4485a66Smrg    XkbSelectEvents(inDpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
340b4485a66Smrg                    XkbIndicatorStateNotifyMask);
341b4485a66Smrg    XkbGetIndicatorState(inDpy, XkbUseCoreKbd, &n);
342b4485a66Smrg    bit = (1U << (XkbNumIndicators - 1));
343b4485a66Smrg    for (i = XkbNumIndicators - 1; i >= 0; i--, bit >>= 1) {
344b4485a66Smrg        if (wanted & bit) {
345b4485a66Smrg            char buf[12];
346b4485a66Smrg            ArgList list;
347010cdda0Smrg
348b4485a66Smrg            sprintf(buf, "led%d", i + 1);
349b4485a66Smrg            if (n & bit)
350b4485a66Smrg                list = onArgs;
351b4485a66Smrg            else
352b4485a66Smrg                list = offArgs;
353b4485a66Smrg            leds[i] =
354b4485a66Smrg                XtCreateManagedWidget(buf, ledWidgetClass, panel, list, 1);
355b4485a66Smrg        }
356010cdda0Smrg    }
357010cdda0Smrg    XtRealizeWidget(toplevel);
358010cdda0Smrg    while (1) {
359b4485a66Smrg        XtAppNextEvent(app_con, &ev.core);
360b4485a66Smrg        if (ev.core.type == evBase + XkbEventCode) {
361b4485a66Smrg            if (ev.any.xkb_type == XkbIndicatorStateNotify) {
362b4485a66Smrg                for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
363b4485a66Smrg                    if ((ev.indicators.changed & bit) && (leds[i])) {
364b4485a66Smrg                        ArgList list;
365b4485a66Smrg
366b4485a66Smrg                        if (ev.indicators.state & bit)
367b4485a66Smrg                            list = onArgs;
368b4485a66Smrg                        else
369b4485a66Smrg                            list = offArgs;
370b4485a66Smrg                        XtSetValues(leds[i], list, 1);
371b4485a66Smrg                    }
372b4485a66Smrg                }
373b4485a66Smrg            }
374b4485a66Smrg        }
375b4485a66Smrg        else
376b4485a66Smrg            XtDispatchEvent(&ev.core);
377010cdda0Smrg    }
378010cdda0Smrg/* BAIL: */
379b4485a66Smrg    if (inDpy)
380b4485a66Smrg        XCloseDisplay(inDpy);
381b4485a66Smrg    if (outDpy != inDpy)
382b4485a66Smrg        XCloseDisplay(outDpy);
383b4485a66Smrg    inDpy = outDpy = NULL;
384010cdda0Smrg    return 0;
385010cdda0Smrg}
386