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