4 #include <X11/Intrinsic.h>
5 #include <X11/XKBlib.h>
7 #include <Xm/RowColumn.h>
8 #include <Xm/ToggleB.h>
11 XtAppContext appContext;
14 Widget leds[XkbNumIndicators];
15 Atom ledAtoms[XkbNumIndicators];
16 XmString ledNames[XkbNumIndicators];
19 void valueChangedProc(Widget,XtPointer,XmToggleButtonCallbackStruct *);
20 XtCallbackRec valueChangedCB[2]={(XtCallbackProc)valueChangedProc,NULL};
22 /************************************************************************/
24 /* Application Resources */
26 /************************************************************************/
44 #define Offset(field) XtOffsetOf(OptionsRec,field)
45 XtResource resources[] =
47 {"wanted", "Wanted", XtRInt, sizeof(int),
48 Offset(wanted), XtRImmediate, (XtPointer) DONT_CARE },
49 {"wantAutomatic", "WantAutomatic", XtRInt, sizeof(int),
50 Offset(wantAutomatic), XtRImmediate, (XtPointer) DONT_CARE},
51 {"wantExplicit", "WantExplicit", XtRInt, sizeof(int),
52 Offset(wantExplicit), XtRImmediate, (XtPointer) DONT_CARE},
53 {"wantNamed", "WantNamed", XtRInt, sizeof(int),
54 Offset(wantNamed), XtRImmediate, (XtPointer) DONT_CARE},
55 {"wantReal", "WantReal", XtRInt, sizeof(int),
56 Offset(wantReal), XtRImmediate, (XtPointer) DONT_CARE},
57 {"wantVirtual", "WantVirtual", XtRInt, sizeof(int),
58 Offset(wantVirtual), XtRImmediate, (XtPointer) DONT_CARE},
59 {"useUnion", "UseUnion", XtRInt, sizeof(int),
60 Offset(useUnion), XtRImmediate, (XtPointer) YES},
65 String fallbackResources[] =
67 "*mainWindow.width: 100",
68 "*mainWindow.height: 50",
72 XrmOptionDescRec optionDesc[] =
74 {"-watch", "*wanted", XrmoptionSepArg, (XtPointer) "0"},
75 {"-automatic", "*wantAutomatic", XrmoptionNoArg, (XtPointer) "0"},
76 {"+automatic", "*wantAutomatic", XrmoptionNoArg, (XtPointer) "1"},
77 {"-explicit", "*wantExplicit", XrmoptionNoArg, (XtPointer) "0"},
78 {"+explicit", "*wantExplicit", XrmoptionNoArg, (XtPointer) "1"},
79 {"-named", "*wantNamed", XrmoptionNoArg, (XtPointer) "0"},
80 {"+named", "*wantNamed", XrmoptionNoArg, (XtPointer) "1"},
81 {"-real", "*wantReal", XrmoptionNoArg, (XtPointer) "0"},
82 {"+real", "*wantReal", XrmoptionNoArg, (XtPointer) "1"},
83 {"-virtual", "*wantVirtual", XrmoptionNoArg, (XtPointer) "0"},
84 {"+virtual", "*wantVirtual", XrmoptionNoArg, (XtPointer) "1"},
85 {"-intersection", "*useUnion", XrmoptionNoArg, (XtPointer) "0"},
86 {"-union", "*useUnion", XrmoptionNoArg, (XtPointer) "1"}
89 /************************************************************************/
93 /************************************************************************/
94 void usage(char *program)
96 printf("Usage: %s <options>\n",program);
97 printf("Legal options include the usual X toolkit options plus:\n");
98 printf(" -help Print this message\n");
99 printf(" -indpy <name> Name of display to watch\n");
100 printf(" -watch <leds> Mask of LEDs to watch\n");
101 printf(" [-+]automatic (Don't) watch automatic LEDs\n");
102 printf(" [-+]explicit (Don't) watch explicit LEDs\n");
103 printf(" [-+]named (Don't) watch named LEDs\n");
104 printf(" [-+]real (Don't) watch real LEDs\n");
105 printf(" [-+]virtual (Don't) watch virtual LEDs\n");
106 printf(" -intersection Watch only LEDs in all desired sets\n");
107 printf(" -union Watch LEDs in any desired sets\n");
108 printf("The default set of LEDs is -intersection +named +virtual\n");
111 /************************************************************************/
113 /* XkbEventHandler */
117 /* Handles events generated by the Xkb server extension. */
119 /************************************************************************/
120 Boolean XkbEventHandler(XEvent *event)
122 XkbEvent *xkbEv = (XkbEvent *) event;
124 if (xkbEv->any.xkb_type==XkbIndicatorStateNotify) {
126 register unsigned bit;
127 for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1)
128 if ((xkbEv->indicators.changed&bit)&&(leds[i]))
130 if (xkbEv->indicators.state&bit)
131 XmToggleButtonSetState(leds[i],True,False);
133 XmToggleButtonSetState(leds[i],False,False);
136 else if (xkbEv->any.xkb_type==XkbIndicatorMapNotify) {
137 unsigned change= xkbEv->indicators.changed;
139 if (XkbGetIndicatorMap(theDisplay,change,xkb_desc)!=Success)
140 fprintf(stderr,"Couldn't get changed indicator maps\n");
145 } /* XkbEventHandler */
147 /************************************************************************/
151 /************************************************************************/
152 Boolean InitXkb(Display *theDisplay)
154 int i,opcode,errorBase,major,minor;
157 unsigned int real,virtual,named,explicit,automatic;
160 if (!XkbQueryExtension(theDisplay,
168 if (!XkbUseExtension(theDisplay,&major,&minor))
171 XkbSelectEvents(theDisplay,
173 XkbIndicatorStateNotifyMask|XkbIndicatorMapNotifyMask,
174 XkbIndicatorStateNotifyMask|XkbIndicatorMapNotifyMask);
176 XtSetEventDispatcher(theDisplay,
177 xkbEventBase+XkbEventCode,
180 xkb=XkbGetMap(theDisplay,0,XkbUseCoreKbd);
181 real=virtual=named=explicit=automatic=0;
185 fprintf(stderr,"Couldn't get keymap\n");
188 if (XkbGetIndicatorMap(theDisplay,XkbAllIndicatorsMask,xkb)!=Success)
190 fprintf(stderr,"Couldn't read indicator map\n");
191 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
194 real=virtual=named=explicit=automatic=0;
196 if (XkbGetNames(theDisplay,XkbIndicatorNamesMask,xkb)!=Success)
198 fprintf(stderr,"Couldn't read indicator names\n");
199 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
202 real=virtual=named=explicit=automatic=0;
204 for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1)
206 XkbIndicatorMapPtr map= &xkb->indicators->maps[i];
208 if (xkb->names->indicators[i]!=None)
211 name = XGetAtomName(theDisplay,xkb->names->indicators[i]);
215 ledAtoms[i] = xkb->names->indicators[i];
216 ledNames[i] = XmStringCreate(name,XmSTRING_DEFAULT_CHARSET);
221 sprintf(temp,"led%d\0",i+1);
223 ledNames[i] = XmStringCreate(temp,XmSTRING_DEFAULT_CHARSET);
225 if (xkb->indicators->phys_indicators&bit)
227 if ((((map->which_groups!=0)&&(map->groups!=0))||
228 ((map->which_mods!=0)&&
229 ((map->mods.real_mods!=0)||(map->mods.vmods!=0)))||
231 ((map->flags&XkbIM_NoAutomatic)==0)) {
239 if (options.useUnion)
241 if ((options.wantReal==NO) || (options.wantReal==DONT_CARE))
243 if ((options.wantVirtual==NO) || (options.wantVirtual==DONT_CARE))
245 if ((options.wantNamed==NO) || (options.wantNamed==DONT_CARE))
247 if ((options.wantAutomatic==NO) || (options.wantAutomatic==DONT_CARE))
249 if ((options.wantExplicit==NO) || (options.wantExplicit==DONT_CARE))
252 options.wanted |= real|virtual|named|automatic|explicit;
256 if (options.wanted == DONT_CARE)
259 if (options.wantReal==NO)
261 else if (options.wantReal==DONT_CARE)
264 if (options.wantVirtual==NO)
266 else if (options.wantVirtual==DONT_CARE)
269 if (options.wantNamed==NO)
271 else if (options.wantNamed==DONT_CARE)
274 if (options.wantAutomatic==NO)
275 automatic = ~automatic;
276 else if (options.wantAutomatic==DONT_CARE)
279 if (options.wantExplicit==NO)
280 explicit = ~explicit;
281 else if (options.wantExplicit==DONT_CARE)
284 options.wanted &= real&virtual&named&automatic&explicit;
287 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
292 /************************************************************************/
294 /* valueChangedProc - called when a toggle button is pressed. */
296 /************************************************************************/
297 void valueChangedProc(Widget w,
298 XtPointer clientData,
299 XmToggleButtonCallbackStruct *callbackData)
301 int led = (int) clientData;
304 xkb = XkbGetMap(theDisplay,0,XkbUseCoreKbd);
307 fprintf(stderr,"XkbGetMap failed\n");
311 if (XkbGetIndicatorMap(theDisplay,XkbAllIndicatorsMask,xkb)!=Success)
313 fprintf(stderr,"GetIndicatorMap failed\n");
314 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
318 /* The 'flags' field tells whether this indicator is automatic
319 * (XkbIM_NoExplicit - 0x80), explicit (XkbIM_NoAutomatic - 0x40),
320 * or neither (both - 0xC0).
322 * If NoAutomatic is set, the server ignores the rest of the
323 * fields in the indicator map (i.e. it disables automatic control
324 * of the LED). If NoExplicit is set, the server prevents clients
325 * from explicitly changing the value of the LED (using the core
326 * protocol *or* XKB). If NoAutomatic *and* NoExplicit are set,
327 * the LED cannot be changed (unless you change the map first).
328 * If neither NoAutomatic nor NoExplicit are set, the server will
329 * change the LED according to the indicator map, but clients can
330 * override that (until the next automatic change) using the core
333 switch (xkb->indicators->maps[led].flags &
334 (XkbIM_NoExplicit|XkbIM_NoAutomatic))
336 case XkbIM_NoExplicit|XkbIM_NoAutomatic:
338 XmToggleButtonSetState(w,!callbackData->set,FALSE);
339 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
343 case XkbIM_NoAutomatic:
345 if (ledAtoms[led] != None)
346 XkbSetNamedIndicator(theDisplay,XkbUseCoreKbd,
347 ledAtoms[led],callbackData->set,
351 XKeyboardControl xkc;
353 if (callbackData->set)
354 xkc.led_mode= LedModeOn;
355 else xkc.led_mode= LedModeOff;
356 XChangeKeyboardControl(theDisplay,KBLed|KBLedMode,&xkc);
360 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
364 case XkbIM_NoExplicit:
368 /* The 'ctrls' field tells what controls tell this indicator to
369 * to turn on: RepeatKeys (0x1), SlowKeys (0x2), BounceKeys (0x4),
370 * StickyKeys (0x8), MouseKeys (0x10), AccessXKeys (0x20),
371 * TimeOut (0x40), Feedback (0x80), ToggleKeys (0x100),
372 * Overlay1 (0x200), Overlay2 (0x400), GroupsWrap (0x800),
373 * InternalMods (0x1000), IgnoreLockMods (0x2000),
374 * PerKeyRepeat (0x3000), or ControlsEnabled (0x4000)
376 if (xkb->indicators->maps[led].ctrls)
378 unsigned long which = xkb->indicators->maps[led].ctrls;
380 XkbGetControls(theDisplay,XkbAllControlsMask,xkb);
381 if (callbackData->set)
382 xkb->ctrls->enabled_ctrls |= which;
384 xkb->ctrls->enabled_ctrls &= ~which;
385 XkbSetControls(theDisplay,which|XkbControlsEnabledMask,xkb);
388 /* The 'which_groups' field tells when this indicator turns on
389 * for the 'groups' field: base (0x1), latched (0x2), locked (0x4),
390 * or effective (0x8).
392 if (xkb->indicators->maps[led].groups)
395 unsigned int group = 1;
397 /* Turning on a group indicator is kind of tricky. For
398 * now, we will just Latch or Lock the first group we find
399 * if that is what this indicator does. Otherwise, we're
400 * just going to punt and get out of here.
402 if (callbackData->set)
404 for (i = XkbNumKbdGroups-1; i >= 0; i--)
406 xkb->indicators->maps[led].groups)
408 if (xkb->indicators->maps[led].which_groups &
409 (XkbIM_UseLocked | XkbIM_UseEffective))
410 XkbLockGroup(theDisplay,XkbUseCoreKbd,group);
411 else if (xkb->indicators->maps[led].which_groups&XkbIM_UseLatched)
412 XkbLatchGroup(theDisplay,XkbUseCoreKbd,group);
415 XmToggleButtonSetState(w,!callbackData->set,FALSE);
416 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
420 /* Turning off a group indicator will mean that we just
421 * Lock the first group that this indicator doesn't watch.
425 for (i = XkbNumKbdGroups-1; i >= 0; i--)
427 xkb->indicators->maps[led].groups))
429 XkbLockGroup(theDisplay,XkbUseCoreKbd,group);
433 /* The 'which_mods' field tells when this indicator turns on
434 * for the modifiers: base (0x1), latched (0x2), locked (0x4),
435 * or effective (0x8).
437 * The 'real_mods' field tells whether this turns on when one of
438 * the real X modifiers is set: Shift (0x1), Lock (0x2), Control (0x4),
439 * Mod1 (0x8), Mod2 (0x10), Mod3 (0x20), Mod4 (0x40), or Mod5 (0x80).
441 * The 'virtual_mods' field tells whether this turns on when one of
442 * the virtual modifiers is set.
444 * The 'mask' field tells what real X modifiers the virtual_modifiers
447 if (xkb->indicators->maps[led].mods.real_mods ||
448 xkb->indicators->maps[led].mods.mask)
451 unsigned int affect,mods;
453 affect = (xkb->indicators->maps[led].mods.real_mods |
454 xkb->indicators->maps[led].mods.mask);
456 if (callbackData->set)
461 if (xkb->indicators->maps[led].which_mods &
462 (XkbIM_UseLocked | XkbIM_UseEffective))
463 XkbLockModifiers(theDisplay,XkbUseCoreKbd,affect,mods);
464 else if (xkb->indicators->maps[led].which_mods &
466 XkbLatchModifiers(theDisplay,XkbUseCoreKbd,affect,mods);
469 XmToggleButtonSetState(w,!callbackData->set,FALSE);
470 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
475 XkbFreeKeyboard(xkb,XkbAllComponentsMask,True);
477 } /* valueChangedProc */
479 /************************************************************************/
483 /************************************************************************/
484 void InitializeUI(Widget topLevel)
490 Widget mainWindow,rowColumn;
493 mainWindow = (Widget) XmCreateMainWindow(topLevel,"mainWindow",NULL,0);
494 XtManageChild(mainWindow);
495 rowColumn = (Widget) XmCreateRowColumn(mainWindow,"rowColumn",NULL,0);
496 XtManageChild(rowColumn);
498 XkbGetIndicatorState(theDisplay,XkbUseCoreKbd,&n);
499 for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1)
501 if (options.wanted&bit)
503 /* [[[ WDW - If we wanted to be really fancy, we
504 * would look for a "*ledxx.labelString" value
505 * in the resource database so the I18N dudes
506 * can see localized strings. ]]]
508 XtSetArg(argList[0], XmNlabelString,ledNames[i]);
509 if (n&bit) XtSetArg(argList[1], XmNset, True);
510 else XtSetArg(argList[1], XmNset, False);
511 sprintf(buf,"led%d\0",i);
512 valueChangedCB[0].closure = (XtPointer) i;
513 XtSetArg(argList[2], XmNvalueChangedCallback, valueChangedCB);
514 leds[i]= XmCreateToggleButton(rowColumn,buf,argList,3);
515 XtManageChild(leds[i]);
523 /************************************************************************/
527 /************************************************************************/
528 #if NeedFunctionPrototypes
537 /********************************************************************/
539 /* Initialize the toolkit */
541 /********************************************************************/
543 topLevel = XtAppInitialize(&appContext, "xkbleds",
544 optionDesc, XtNumber(optionDesc),
548 XtSetArg(argList[0], XtNallowShellResize, TRUE);
549 XtSetValues(topLevel,argList,1);
550 XtGetApplicationResources(topLevel, (XtPointer)&options, resources,
551 XtNumber(resources), NULL, 0);
561 if ((options.wanted == DONT_CARE) &&
562 (options.wantReal == DONT_CARE) &&
563 (options.wantVirtual == DONT_CARE) &&
564 (options.wantNamed == DONT_CARE) &&
565 (options.wantAutomatic == DONT_CARE) &&
566 (options.wantExplicit == DONT_CARE) &&
567 (options.useUnion == YES))
570 options.wantReal = YES;
571 options.wantNamed = YES;
572 options.wantAutomatic = YES;
575 /********************************************************************/
577 /* See if the server has XKB. */
579 /********************************************************************/
580 theDisplay = XtDisplay(topLevel);
581 if (!InitXkb(theDisplay))
583 fprintf(stderr,"Could not initialize XKB extension.\n");
587 if (options.wanted == 0)
589 fprintf(stderr,"No LED's were selected.\n\n");
594 /********************************************************************/
596 /* Set up the UI and go. */
598 /********************************************************************/
599 XtRealizeWidget(topLevel);
600 InitializeUI(topLevel);
601 XtAppMainLoop(appContext);