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
43static Display *inDpy, *outDpy;
44static int evBase, errBase;
45
46/***====================================================================***/
47
48static XrmOptionDescRec options[] = {
49    {"-off", "*on.on", XrmoptionNoArg, "FALSE"},
50    {"-on", "*on.on", XrmoptionNoArg, "TRUE"}
51};
52
53/***====================================================================***/
54
55int
56main(int argc, char *argv[])
57{
58    Widget toplevel;
59    XtAppContext app_con;
60    Widget panel;
61    Widget base[XkbNumModifiers];
62    Widget latched[XkbNumModifiers];
63    Widget locked[XkbNumModifiers];
64    Widget effective[XkbNumModifiers];
65    Widget compat[XkbNumModifiers];
66    Widget baseBox, latchBox, lockBox, effBox, compatBox;
67    register int i;
68    unsigned bit;
69    XkbEvent ev;
70    XkbStateRec state;
71    static Arg hArgs[] = { {XtNorientation, (XtArgVal) XtorientHorizontal} };
72    static Arg vArgs[] = { {XtNorientation, (XtArgVal) XtorientVertical} };
73    static Arg onArgs[] = { {XtNon, (XtArgVal) True} };
74    static Arg offArgs[] = { {XtNon, (XtArgVal) False} };
75    static String fallback_resources[] = {
76        "*Box*background: grey50",
77        "*Box*borderWidth: 0",
78        "*Box*vSpace: 1",
79        NULL
80    };
81
82    for (i = 1; i < argc; i++) {
83        if (strcmp(argv[i], "-version") == 0) {
84            printf("xkbwatch (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
85            exit(0);
86        }
87    }
88
89    toplevel = XtOpenApplication(&app_con, "XkbWatch",
90                                 options, XtNumber(options), &argc, argv,
91                                 fallback_resources,
92                                 sessionShellWidgetClass, NULL, ZERO);
93    if (toplevel == NULL) {
94        uFatalError("Couldn't create application top level\n");
95        exit(1);
96    }
97    inDpy = outDpy = XtDisplay(toplevel);
98    if (inDpy) {
99        int i1, mn, mj;
100
101        mj = XkbMajorVersion;
102        mn = XkbMinorVersion;
103        if (!XkbQueryExtension(inDpy, &i1, &evBase, &errBase, &mj, &mn)) {
104            uFatalError("Server doesn't support a compatible XKB\n");
105            exit(1);
106        }
107    }
108    panel =
109        XtCreateManagedWidget("xkbwatch", boxWidgetClass, toplevel, vArgs, 1);
110    if (panel == NULL) {
111        uFatalError("Couldn't create top level box\n");
112        exit(1);
113    }
114    baseBox = XtCreateManagedWidget("base", boxWidgetClass, panel, hArgs, 1);
115    if (baseBox == NULL)
116        uFatalError("Couldn't create base modifiers box\n");
117    latchBox =
118        XtCreateManagedWidget("latched", boxWidgetClass, panel, hArgs, 1);
119    if (latchBox == NULL)
120        uFatalError("Couldn't create latched modifiers box\n");
121    lockBox = XtCreateManagedWidget("locked", boxWidgetClass, panel, hArgs, 1);
122    if (lockBox == NULL)
123        uFatalError("Couldn't create locked modifiers box\n");
124    effBox =
125        XtCreateManagedWidget("effective", boxWidgetClass, panel, hArgs, 1);
126    if (effBox == NULL)
127        uFatalError("Couldn't create effective modifiers box\n");
128    compatBox =
129        XtCreateManagedWidget("compat", boxWidgetClass, panel, hArgs, 1);
130    if (compatBox == NULL)
131        uFatalError("Couldn't create compatibility state box\n");
132    XkbSelectEvents(inDpy, XkbUseCoreKbd, XkbStateNotifyMask,
133                    XkbStateNotifyMask);
134    XkbGetState(inDpy, XkbUseCoreKbd, &state);
135    for (i = XkbNumModifiers - 1, bit = 0x80; i >= 0; i--, bit >>= 1) {
136        ArgList list;
137
138        char buf[30];
139
140        snprintf(buf, sizeof(buf), "base%d", i);
141        if (state.base_mods & bit)
142            list = onArgs;
143        else
144            list = offArgs;
145        base[i] = XtCreateManagedWidget(buf, ledWidgetClass, baseBox, list, 1);
146        snprintf(buf, sizeof(buf), "latched%d", i);
147        if (state.latched_mods & bit)
148            list = onArgs;
149        else
150            list = offArgs;
151        latched[i] =
152            XtCreateManagedWidget(buf, ledWidgetClass, latchBox, list, 1);
153        snprintf(buf, sizeof(buf), "locked%d", i);
154        if (state.locked_mods & bit)
155            list = onArgs;
156        else
157            list = offArgs;
158        locked[i] =
159            XtCreateManagedWidget(buf, ledWidgetClass, lockBox, list, 1);
160        snprintf(buf, sizeof(buf), "effective%d", i);
161        if (state.mods & bit)
162            list = onArgs;
163        else
164            list = offArgs;
165        effective[i] =
166            XtCreateManagedWidget(buf, ledWidgetClass, effBox, list, 1);
167        snprintf(buf, sizeof(buf), "compat%d", i);
168        if (state.compat_state & bit)
169            list = onArgs;
170        else
171            list = offArgs;
172        compat[i] =
173            XtCreateManagedWidget(buf, ledWidgetClass, compatBox, list, 1);
174    }
175    XtRealizeWidget(toplevel);
176    while (1) {
177        XtAppNextEvent(app_con, &ev.core);
178        if (ev.core.type == evBase + XkbEventCode) {
179            if (ev.any.xkb_type == XkbStateNotify) {
180                unsigned changed;
181
182                if (ev.state.changed & XkbModifierBaseMask) {
183                    changed = ev.state.base_mods ^ state.base_mods;
184                    state.base_mods = ev.state.base_mods;
185                    for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) {
186                        if (changed & bit) {
187                            ArgList list;
188
189                            if (state.base_mods & bit)
190                                list = onArgs;
191                            else
192                                list = offArgs;
193                            XtSetValues(base[i], list, 1);
194                        }
195                    }
196                }
197                if (ev.state.changed & XkbModifierLatchMask) {
198                    changed = ev.state.latched_mods ^ state.latched_mods;
199                    state.latched_mods = ev.state.latched_mods;
200                    for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) {
201                        if (changed & bit) {
202                            ArgList list;
203
204                            if (state.latched_mods & bit)
205                                list = onArgs;
206                            else
207                                list = offArgs;
208                            XtSetValues(latched[i], list, 1);
209                        }
210                    }
211                }
212                if (ev.state.changed & XkbModifierLockMask) {
213                    changed = ev.state.locked_mods ^ state.locked_mods;
214                    state.locked_mods = ev.state.locked_mods;
215                    for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) {
216                        if (changed & bit) {
217                            ArgList list;
218
219                            if (state.locked_mods & bit)
220                                list = onArgs;
221                            else
222                                list = offArgs;
223                            XtSetValues(locked[i], list, 1);
224                        }
225                    }
226                }
227                if (ev.state.changed & XkbModifierStateMask) {
228                    changed = ev.state.mods ^ state.mods;
229                    state.mods = ev.state.mods;
230                    for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) {
231                        if (changed & bit) {
232                            ArgList list;
233
234                            if (state.mods & bit)
235                                list = onArgs;
236                            else
237                                list = offArgs;
238                            XtSetValues(effective[i], list, 1);
239                        }
240                    }
241                }
242                if (ev.state.changed & XkbCompatStateMask) {
243                    changed = ev.state.compat_state ^ state.compat_state;
244                    state.compat_state = ev.state.compat_state;
245                    for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) {
246                        if (changed & bit) {
247                            ArgList list;
248
249                            if (state.compat_state & bit)
250                                list = onArgs;
251                            else
252                                list = offArgs;
253                            XtSetValues(compat[i], list, 1);
254                        }
255                    }
256                }
257            }
258        }
259        else
260            XtDispatchEvent(&ev.core);
261    }
262/* BAIL: */
263    if (inDpy)
264        XCloseDisplay(inDpy);
265    if (outDpy != inDpy)
266        XCloseDisplay(outDpy);
267    inDpy = outDpy = NULL;
268    return 0;
269}
270