xkbvleds.c revision b4485a66
1/************************************************************
2 Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27#include <stdlib.h>
28#include <X11/X.h>
29#include <X11/Xlib.h>
30#include <X11/XKBlib.h>
31#include <X11/Intrinsic.h>
32#include <X11/StringDefs.h>
33#include <X11/Shell.h>
34#include <X11/Xaw/Cardinals.h>
35#include <X11/Xaw/Box.h>
36
37#define	BOOLEAN_DEFINED
38#include "utils.h"
39#include "LED.h"
40
41/***====================================================================***/
42
43#define	YES		1
44#define	NO		0
45#define	DONT_CARE	-1
46
47static Display *inDpy, *outDpy;
48static unsigned long wanted, real, named, explicit, automatic, virtual;
49static char *inDpyName;
50static int wantNamed = DONT_CARE;
51static int wantExplicit = DONT_CARE;
52static int wantAutomatic = DONT_CARE;
53static int wantReal = DONT_CARE;
54static int wantVirtual = DONT_CARE;
55static int evBase, errBase;
56static Bool synch;
57static Bool useUnion = True;
58
59/***====================================================================***/
60
61static void
62usage(char *program)
63{
64    uInformation("Usage: %s <options>\n", program);
65    uInformation("Legal options include the usual X toolkit options plus:\n"
66                 "  -help           Print this message\n"
67                 "  -version        Print the program version\n"
68                 "  -indpy <name>   Name of display to watch\n"
69                 "  -watch <leds>   Mask of LEDs to watch\n"
70                 "  [-+]automatic   (Don't) watch automatic LEDs\n"
71                 "  [-+]explicit    (Don't) watch explicit LEDs\n"
72                 "  [-+]name        (Don't) watch named LEDs\n"
73                 "  [-+]real        (Don't) watch real LEDs\n"
74                 "  [-+]virtual     (Don't) watch virtual LEDs\n"
75                 "  -intersection   Watch only LEDs in all desired sets\n"
76                 "  -union          Watch LEDs in any desired sets\n"
77                 "The default set of LEDs is -union +name +automatic +real\n");
78    return;
79}
80
81static Bool
82parseArgs(int argc, char *argv[])
83{
84    register int i;
85
86    for (i = 1; i < argc; i++) {
87        if (uStrCaseEqual(argv[i], "-indpy")) {
88            if (i < argc - 1)
89                inDpyName = argv[++i];
90            else {
91                uWarning("No name specified for input display\n");
92                uAction("Ignoring trailing -indpy argument\n");
93            }
94        }
95        else if (uStrCaseEqual(argv[i], "-watch")) {
96            if (i < argc - 1) {
97                int tmp;
98
99                if (sscanf(argv[++i], "%i", &tmp) != 1) {
100                    uWarning("Set of LEDs must be specified as an integer\n");
101                    uAction("Ignoring bogus value \"%s\" for -watch flag\n",
102                            argv[i]);
103                }
104                else
105                    wanted = tmp;
106            }
107            else {
108                uWarning("Didn't specify any LEDs to watch\n");
109                uAction("Ignoring trailing -watch argument\n");
110            }
111        }
112        else if (uStrCaseEqual(argv[i], "-union")) {
113            useUnion = True;
114        }
115        else if (uStrCaseEqual(argv[i], "-intersection")) {
116            useUnion = False;
117        }
118        else if (uStrCaseEqual(argv[i], "-help")) {
119            usage(argv[0]);
120            exit(0);
121        }
122        else if (uStrCaseEqual(argv[i], "-version")) {
123            printf("xkbvleds (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
124            exit(0);
125        }
126        else if ((argv[i][0] == '+') || (argv[i][0] == '-')) {
127            Bool onoff;
128            int *which;
129
130            onoff = (argv[i][0] == '+');
131            which = NULL;
132            if (uStrCaseEqual(&argv[i][1], "name"))
133                which = &wantNamed;
134            else if (uStrCaseEqual(&argv[i][1], "explicit"))
135                which = &wantExplicit;
136            else if (uStrCaseEqual(&argv[i][1], "automatic"))
137                which = &wantAutomatic;
138            else if (uStrCaseEqual(&argv[i][1], "real"))
139                which = &wantReal;
140            else if (uStrCaseEqual(&argv[i][1], "virtual"))
141                which = &wantVirtual;
142            if (which != NULL) {
143                if (*which != DONT_CARE) {
144                    uWarning("Multiple settings for [+-]%s\n", &argv[i][1]);
145                    uAction("Using %c%s, ignoring %c%s\n",
146                            (onoff ? '+' : '-'), &argv[i][1],
147                            (onoff ? '-' : '+'), &argv[i][1]);
148                }
149                *which = (onoff ? YES : NO);
150            }
151        }
152    }
153    return True;
154}
155
156/***====================================================================***/
157
158static Display *
159GetDisplay(char *program, char *dpyName)
160{
161    int mjr, mnr, error;
162    Display *dpy;
163
164    mjr = XkbMajorVersion;
165    mnr = XkbMinorVersion;
166    dpy = XkbOpenDisplay(dpyName, &evBase, &errBase, &mjr, &mnr, &error);
167    if (dpy == NULL) {
168        switch (error) {
169        case XkbOD_BadLibraryVersion:
170            uInformation("%s was compiled with XKB version %d.%02d\n",
171                         program, XkbMajorVersion, XkbMinorVersion);
172            uError("X library supports incompatible version %d.%02d\n",
173                   mjr, mnr);
174            break;
175        case XkbOD_ConnectionRefused:
176            uError("Cannot open display \"%s\"\n", dpyName);
177            break;
178        case XkbOD_NonXkbServer:
179            uError("XKB extension not present on %s\n", dpyName);
180            break;
181        case XkbOD_BadServerVersion:
182            uInformation("%s was compiled with XKB version %d.%02d\n",
183                         program, XkbMajorVersion, XkbMinorVersion);
184            uError("Server %s uses incompatible version %d.%02d\n",
185                   dpyName, mjr, mnr);
186            break;
187        default:
188            uInternalError("Unknown error %d from XkbOpenDisplay\n", error);
189        }
190    }
191    else if (synch)
192        XSynchronize(dpy, True);
193    return dpy;
194}
195
196/***====================================================================***/
197
198int
199main(int argc, char *argv[])
200{
201    Widget toplevel;
202    XtAppContext app_con;
203    Widget panel;
204    Widget leds[XkbNumIndicators];
205    register int i;
206    unsigned bit;
207    unsigned n;
208    XkbDescPtr xkb;
209    XkbEvent ev;
210    static Arg boxArgs[] = { {XtNorientation, (XtArgVal) XtorientHorizontal} };
211    static Arg onArgs[] = { {XtNon, (XtArgVal) True} };
212    static Arg offArgs[] = { {XtNon, (XtArgVal) False} };
213    static char *fallback_resources[] = {
214        "*Box*background: grey40",
215        NULL
216    };
217
218    uSetErrorFile(NullString);
219    bzero(leds, XkbNumIndicators * sizeof(Widget));
220    toplevel = XtOpenApplication(&app_con, "XkbLEDPanel", NULL, 0, &argc, argv,
221                                 fallback_resources,
222                                 sessionShellWidgetClass, NULL, ZERO);
223    if (toplevel == NULL) {
224        uFatalError("Couldn't create application top level\n");
225        return 1;
226    }
227    if ((argc > 1) && (!parseArgs(argc, argv))) {
228        usage(argv[0]);
229        return 1;
230    }
231    if ((wanted == 0) && (wantNamed == DONT_CARE) && (wantExplicit == DONT_CARE)
232        && (wantAutomatic == DONT_CARE) && (wantReal == DONT_CARE)) {
233        wantNamed = YES;
234        wantReal = YES;
235        wantAutomatic = YES;
236    }
237    outDpy = XtDisplay(toplevel);
238    if (inDpyName != NULL) {
239        inDpy = GetDisplay(argv[0], inDpyName);
240        if (!inDpy)
241            return 1;
242    }
243    else {
244        inDpy = outDpy;
245    }
246    if (inDpy) {
247        int i1, mn, mj;
248
249        mj = XkbMajorVersion;
250        mn = XkbMinorVersion;
251        if (!XkbLibraryVersion(&mj, &mn)) {
252            uInformation("%s was compiled with XKB version %d.%02d\n",
253                         argv[0], XkbMajorVersion, XkbMinorVersion);
254            uError("X library supports incompatible version %d.%02d\n", mj, mn);
255        }
256        if (!XkbQueryExtension(inDpy, &i1, &evBase, &errBase, &mj, &mn)) {
257            uFatalError("Server doesn't support a compatible XKB\n");
258            return 1;
259        }
260    }
261    else {
262        uFatalError("No input display\n");
263        return 1;
264    }
265    panel =
266        XtCreateManagedWidget("xkbleds", boxWidgetClass, toplevel, boxArgs, 1);
267    if (panel == NULL) {
268        uFatalError("Couldn't create list of leds\n");
269        return 1;
270    }
271    real = virtual = named = explicit = automatic = 0;
272    if (wantReal || wantNamed || wantAutomatic || wantExplicit || wantVirtual) {
273        register int i, bit;
274
275        xkb = XkbGetMap(inDpy, 0, XkbUseCoreKbd);
276        if (!xkb) {
277            uFatalError("Couldn't read keymap\n");
278            return 1;
279        }
280        if (XkbGetIndicatorMap(inDpy, XkbAllIndicatorsMask, xkb) != Success) {
281            uFatalError("Couldn't read indicator map\n");
282            return 1;
283        }
284        if (XkbGetNames(inDpy, XkbAllNamesMask, xkb) != Success) {
285            uFatalError("Couldn't read indicator names\n");
286            return 1;
287        }
288        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
289            XkbIndicatorMapPtr map = &xkb->indicators->maps[i];
290
291            if (xkb->names->indicators[i] != None)
292                named |= bit;
293            if (xkb->indicators->phys_indicators & bit)
294                real |= bit;
295            if ((((map->which_groups != 0) && (map->groups != 0)) ||
296                 ((map->which_mods != 0) &&
297                  ((map->mods.real_mods != 0) || (map->mods.vmods != 0))) ||
298                 (map->ctrls != 0)) &&
299                ((map->flags & XkbIM_NoAutomatic) == 0)) {
300                automatic |= bit;
301            }
302            else
303                explicit |= bit;
304        }
305        virtual = ~real;
306        if (wantReal == NO)
307            real = ~real;
308        else if (wantReal == DONT_CARE)
309            real = (useUnion ? 0 : ~0);
310        if (wantVirtual == NO)
311            virtual = ~virtual;
312        else if (wantVirtual == DONT_CARE)
313            virtual = (useUnion ? 0 : ~0);
314        if (wantNamed == NO)
315            named = ~named;
316        else if (wantNamed == DONT_CARE)
317            named = (useUnion ? 0 : ~0);
318        if (wantAutomatic == NO)
319            automatic = ~automatic;
320        else if (wantAutomatic == DONT_CARE)
321            automatic = (useUnion ? 0 : ~0);
322        if (wantExplicit == NO)
323            explicit = ~explicit;
324        else if (wantExplicit == DONT_CARE)
325            explicit = (useUnion ? 0 : ~0);
326        if (useUnion)
327            wanted |= real | virtual | named | automatic | explicit;
328        else
329            wanted &= real & virtual & named & automatic & explicit;
330    }
331    else
332        xkb = NULL;
333    if (wanted == 0) {
334        uError("No indicator maps match the selected criteria\n");
335        uAction("Exiting\n");
336        return 1;
337    }
338
339    XkbSelectEvents(inDpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
340                    XkbIndicatorStateNotifyMask);
341    XkbGetIndicatorState(inDpy, XkbUseCoreKbd, &n);
342    bit = (1U << (XkbNumIndicators - 1));
343    for (i = XkbNumIndicators - 1; i >= 0; i--, bit >>= 1) {
344        if (wanted & bit) {
345            char buf[12];
346            ArgList list;
347
348            sprintf(buf, "led%d", i + 1);
349            if (n & bit)
350                list = onArgs;
351            else
352                list = offArgs;
353            leds[i] =
354                XtCreateManagedWidget(buf, ledWidgetClass, panel, list, 1);
355        }
356    }
357    XtRealizeWidget(toplevel);
358    while (1) {
359        XtAppNextEvent(app_con, &ev.core);
360        if (ev.core.type == evBase + XkbEventCode) {
361            if (ev.any.xkb_type == XkbIndicatorStateNotify) {
362                for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
363                    if ((ev.indicators.changed & bit) && (leds[i])) {
364                        ArgList list;
365
366                        if (ev.indicators.state & bit)
367                            list = onArgs;
368                        else
369                            list = offArgs;
370                        XtSetValues(leds[i], list, 1);
371                    }
372                }
373            }
374        }
375        else
376            XtDispatchEvent(&ev.core);
377    }
378/* BAIL: */
379    if (inDpy)
380        XCloseDisplay(inDpy);
381    if (outDpy != inDpy)
382        XCloseDisplay(outDpy);
383    inDpy = outDpy = NULL;
384    return 0;
385}
386