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