1/************************************************************ 2 Copyright (c) 1994 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 "xkbcomp.h" 28#include "misc.h" 29#include "tokens.h" 30#include "expr.h" 31#include "vmod.h" 32#include "indicators.h" 33#include "action.h" 34#include "compat.h" 35 36/***====================================================================***/ 37 38#define ReportIndicatorBadType(d,l,f,w) \ 39 ReportBadType("indicator map",(f),\ 40 XkbAtomText((d),(l)->name,XkbMessage),(w)) 41#define ReportIndicatorNotArray(d,l,f) \ 42 ReportNotArray("indicator map",(f),\ 43 XkbAtomText((d),(l)->name,XkbMessage)) 44 45/***====================================================================***/ 46 47void 48ClearIndicatorMapInfo(Display * dpy, LEDInfo * info) 49{ 50 info->name = XkbInternAtom(dpy, "default", False); 51 info->indicator = _LED_NotBound; 52 info->flags = info->which_mods = info->real_mods = 0; 53 info->vmods = 0; 54 info->which_groups = info->groups = 0; 55 info->ctrls = 0; 56 return; 57} 58 59LEDInfo * 60AddIndicatorMap(LEDInfo *oldLEDs, const LEDInfo *new) 61{ 62 LEDInfo *old, *last; 63 64 last = NULL; 65 for (old = oldLEDs; old != NULL; old = (LEDInfo *) old->defs.next) 66 { 67 if (old->name == new->name) 68 { 69 unsigned collide; 70 71 if ((old->real_mods == new->real_mods) && 72 (old->vmods == new->vmods) && 73 (old->groups == new->groups) && 74 (old->ctrls == new->ctrls) && 75 (old->which_mods == new->which_mods) && 76 (old->which_groups == new->which_groups)) 77 { 78 old->defs.defined |= new->defs.defined; 79 return oldLEDs; 80 } 81 if (new->defs.merge == MergeReplace) 82 { 83 CommonInfo *next = old->defs.next; 84 if (((old->defs.fileID == new->defs.fileID) 85 && (warningLevel > 0)) || (warningLevel > 9)) 86 { 87 WARN("Map for indicator %s redefined\n", 88 XkbAtomText(NULL, old->name, XkbMessage)); 89 ACTION("Earlier definition ignored\n"); 90 } 91 *old = *new; 92 old->defs.next = next; 93 return oldLEDs; 94 } 95 collide = 0; 96 if (UseNewField(_LED_Index, &old->defs, &new->defs, &collide)) 97 { 98 old->indicator = new->indicator; 99 old->defs.defined |= _LED_Index; 100 } 101 if (UseNewField(_LED_Mods, &old->defs, &new->defs, &collide)) 102 { 103 old->which_mods = new->which_mods; 104 old->real_mods = new->real_mods; 105 old->vmods = new->vmods; 106 old->defs.defined |= _LED_Mods; 107 } 108 if (UseNewField(_LED_Groups, &old->defs, &new->defs, &collide)) 109 { 110 old->which_groups = new->which_groups; 111 old->groups = new->groups; 112 old->defs.defined |= _LED_Groups; 113 } 114 if (UseNewField(_LED_Ctrls, &old->defs, &new->defs, &collide)) 115 { 116 old->ctrls = new->ctrls; 117 old->defs.defined |= _LED_Ctrls; 118 } 119 if (UseNewField(_LED_Explicit, &old->defs, &new->defs, &collide)) 120 { 121 old->flags &= ~XkbIM_NoExplicit; 122 old->flags |= (new->flags & XkbIM_NoExplicit); 123 old->defs.defined |= _LED_Explicit; 124 } 125 if (UseNewField(_LED_Automatic, &old->defs, &new->defs, &collide)) 126 { 127 old->flags &= ~XkbIM_NoAutomatic; 128 old->flags |= (new->flags & XkbIM_NoAutomatic); 129 old->defs.defined |= _LED_Automatic; 130 } 131 if (UseNewField(_LED_DrivesKbd, &old->defs, &new->defs, &collide)) 132 { 133 old->flags &= ~XkbIM_LEDDrivesKB; 134 old->flags |= (new->flags & XkbIM_LEDDrivesKB); 135 old->defs.defined |= _LED_DrivesKbd; 136 } 137 if (collide && (warningLevel > 0)) 138 { 139 WARN("Map for indicator %s redefined\n", 140 XkbAtomText(NULL, old->name, XkbMessage)); 141 ACTION("Using %s definition for duplicate fields\n", 142 (new->defs.merge == MergeAugment ? "first" : "last")); 143 } 144 return oldLEDs; 145 } 146 if (old->defs.next == NULL) 147 last = old; 148 } 149 /* new definition */ 150 old = malloc(sizeof(LEDInfo)); 151 if (!old) 152 { 153 WSGO("Couldn't allocate indicator map\n"); 154 ACTION("Map for indicator %s not compiled\n", 155 XkbAtomText(NULL, new->name, XkbMessage)); 156 return NULL; 157 } 158 *old = *new; 159 old->defs.next = NULL; 160 if (last) 161 { 162 last->defs.next = &old->defs; 163 return oldLEDs; 164 } 165 return old; 166} 167 168static LookupEntry modComponentNames[] = { 169 {"base", XkbIM_UseBase} 170 , 171 {"latched", XkbIM_UseLatched} 172 , 173 {"locked", XkbIM_UseLocked} 174 , 175 {"effective", XkbIM_UseEffective} 176 , 177 {"compat", XkbIM_UseCompat} 178 , 179 {"any", XkbIM_UseAnyMods} 180 , 181 {"none", 0} 182 , 183 {NULL, 0} 184}; 185static LookupEntry groupComponentNames[] = { 186 {"base", XkbIM_UseBase} 187 , 188 {"latched", XkbIM_UseLatched} 189 , 190 {"locked", XkbIM_UseLocked} 191 , 192 {"effective", XkbIM_UseEffective} 193 , 194 {"any", XkbIM_UseAnyGroup} 195 , 196 {"none", 0} 197 , 198 {NULL, 0} 199}; 200 201int 202SetIndicatorMapField(LEDInfo *led, XkbDescPtr xkb, const char *field, 203 const ExprDef *arrayNdx, const ExprDef *value) 204{ 205 ExprResult rtrn; 206 Bool ok; 207 208 ok = True; 209 if ((uStrCaseCmp(field, "modifiers") == 0) 210 || (uStrCaseCmp(field, "mods") == 0)) 211 { 212 if (arrayNdx != NULL) 213 return ReportIndicatorNotArray(xkb->dpy, led, field); 214 if (!ExprResolveModMask(value, &rtrn, LookupVModMask, (XPointer) xkb)) 215 return ReportIndicatorBadType(xkb->dpy, led, field, 216 "modifier mask"); 217 led->real_mods = rtrn.uval & 0xff; 218 led->vmods = (rtrn.uval >> 8) & 0xff; 219 led->defs.defined |= _LED_Mods; 220 } 221 else if (uStrCaseCmp(field, "groups") == 0) 222 { 223 if (arrayNdx != NULL) 224 return ReportIndicatorNotArray(xkb->dpy, led, field); 225 if (!ExprResolveMask 226 (value, &rtrn, SimpleLookup, (XPointer) groupNames)) 227 return ReportIndicatorBadType(xkb->dpy, led, field, "group mask"); 228 led->groups = rtrn.uval; 229 led->defs.defined |= _LED_Groups; 230 } 231 else if ((uStrCaseCmp(field, "controls") == 0) || 232 (uStrCaseCmp(field, "ctrls") == 0)) 233 { 234 if (arrayNdx != NULL) 235 return ReportIndicatorNotArray(xkb->dpy, led, field); 236 if (!ExprResolveMask 237 (value, &rtrn, SimpleLookup, (XPointer) ctrlNames)) 238 return ReportIndicatorBadType(xkb->dpy, led, field, 239 "controls mask"); 240 led->ctrls = rtrn.uval; 241 led->defs.defined |= _LED_Ctrls; 242 } 243 else if (uStrCaseCmp(field, "allowexplicit") == 0) 244 { 245 if (arrayNdx != NULL) 246 return ReportIndicatorNotArray(xkb->dpy, led, field); 247 if (!ExprResolveBoolean(value, &rtrn, NULL, NULL)) 248 return ReportIndicatorBadType(xkb->dpy, led, field, "boolean"); 249 if (rtrn.uval) 250 led->flags &= ~XkbIM_NoExplicit; 251 else 252 led->flags |= XkbIM_NoExplicit; 253 led->defs.defined |= _LED_Explicit; 254 } 255 else if ((uStrCaseCmp(field, "whichmodstate") == 0) || 256 (uStrCaseCmp(field, "whichmodifierstate") == 0)) 257 { 258 if (arrayNdx != NULL) 259 return ReportIndicatorNotArray(xkb->dpy, led, field); 260 if (!ExprResolveMask(value, &rtrn, SimpleLookup, 261 (XPointer) modComponentNames)) 262 { 263 return ReportIndicatorBadType(xkb->dpy, led, field, 264 "mask of modifier state components"); 265 } 266 led->which_mods = rtrn.uval; 267 } 268 else if (uStrCaseCmp(field, "whichgroupstate") == 0) 269 { 270 if (arrayNdx != NULL) 271 return ReportIndicatorNotArray(xkb->dpy, led, field); 272 if (!ExprResolveMask(value, &rtrn, SimpleLookup, 273 (XPointer) groupComponentNames)) 274 { 275 return ReportIndicatorBadType(xkb->dpy, led, field, 276 "mask of group state components"); 277 } 278 led->which_groups = rtrn.uval; 279 } 280 else if ((uStrCaseCmp(field, "driveskbd") == 0) || 281 (uStrCaseCmp(field, "driveskeyboard") == 0) || 282 (uStrCaseCmp(field, "leddriveskbd") == 0) || 283 (uStrCaseCmp(field, "leddriveskeyboard") == 0) || 284 (uStrCaseCmp(field, "indicatordriveskbd") == 0) || 285 (uStrCaseCmp(field, "indicatordriveskeyboard") == 0)) 286 { 287 if (arrayNdx != NULL) 288 return ReportIndicatorNotArray(xkb->dpy, led, field); 289 if (!ExprResolveBoolean(value, &rtrn, NULL, NULL)) 290 return ReportIndicatorBadType(xkb->dpy, led, field, "boolean"); 291 if (rtrn.uval) 292 led->flags |= XkbIM_LEDDrivesKB; 293 else 294 led->flags &= ~XkbIM_LEDDrivesKB; 295 led->defs.defined |= _LED_DrivesKbd; 296 } 297 else if (uStrCaseCmp(field, "index") == 0) 298 { 299 if (arrayNdx != NULL) 300 return ReportIndicatorNotArray(xkb->dpy, led, field); 301 if (!ExprResolveInteger(value, &rtrn, NULL, NULL)) 302 return ReportIndicatorBadType(xkb->dpy, led, field, 303 "indicator index"); 304 if ((rtrn.uval < 1) || (rtrn.uval > 32)) 305 { 306 ERROR("Illegal indicator index %d (range 1..%d)\n", 307 rtrn.uval, XkbNumIndicators); 308 ACTION("Index definition for %s indicator ignored\n", 309 XkbAtomText(NULL, led->name, XkbMessage)); 310 return False; 311 } 312 led->indicator = rtrn.uval; 313 led->defs.defined |= _LED_Index; 314 } 315 else 316 { 317 ERROR("Unknown field %s in map for %s indicator\n", field, 318 XkbAtomText(NULL, led->name, XkbMessage)); 319 ACTION("Definition ignored\n"); 320 ok = False; 321 } 322 return ok; 323} 324 325LEDInfo * 326HandleIndicatorMapDef(IndicatorMapDef *def, XkbDescPtr xkb, 327 const LEDInfo *dflt, LEDInfo *oldLEDs, unsigned merge) 328{ 329 LEDInfo led; 330 Bool ok; 331 332 if (def->merge != MergeDefault) 333 merge = def->merge; 334 335 led = *dflt; 336 led.defs.merge = merge; 337 led.name = def->name; 338 339 ok = True; 340 for (VarDef *var = def->body; var != NULL; 341 var = (VarDef *) var->common.next) 342 { 343 ExprResult elem, field; 344 ExprDef *arrayNdx; 345 if (!ExprResolveLhs(var->name, &elem, &field, &arrayNdx)) 346 { 347 ok = False; 348 continue; 349 } 350 if (elem.str != NULL) 351 { 352 ERROR 353 ("Cannot set defaults for \"%s\" element in indicator map\n", 354 elem.str); 355 ACTION("Assignment to %s.%s ignored\n", elem.str, field.str); 356 ok = False; 357 } 358 else 359 { 360 ok = SetIndicatorMapField(&led, xkb, field.str, arrayNdx, 361 var->value) && ok; 362 } 363 } 364 if (ok) 365 { 366 LEDInfo *rtrn = AddIndicatorMap(oldLEDs, &led); 367 return rtrn; 368 } 369 return NULL; 370} 371 372Bool 373CopyIndicatorMapDefs(XkbFileInfo * result, LEDInfo * leds, 374 LEDInfo ** unboundRtrn) 375{ 376 LEDInfo *led, *next; 377 LEDInfo *unbound, *last; 378 XkbDescPtr xkb; 379 380 xkb = result->xkb; 381 if (XkbAllocNames(xkb, XkbIndicatorNamesMask, 0, 0) != Success) 382 { 383 WSGO("Couldn't allocate names\n"); 384 ACTION("Indicator names may be incorrect\n"); 385 } 386 if (XkbAllocIndicatorMaps(xkb) != Success) 387 { 388 WSGO("Can't allocate indicator maps\n"); 389 ACTION("Indicator map definitions may be lost\n"); 390 return False; 391 } 392 last = unbound = (unboundRtrn ? *unboundRtrn : NULL); 393 while ((last != NULL) && (last->defs.next != NULL)) 394 { 395 last = (LEDInfo *) last->defs.next; 396 } 397 for (led = leds; led != NULL; led = next) 398 { 399 next = (LEDInfo *) led->defs.next; 400 if ((led->groups != 0) && (led->which_groups == 0)) 401 led->which_groups = XkbIM_UseEffective; 402 if ((led->which_mods == 0) && ((led->real_mods) || (led->vmods))) 403 led->which_mods = XkbIM_UseEffective; 404 if ((led->indicator == _LED_NotBound) || (!xkb->indicators)) 405 { 406 if (unboundRtrn != NULL) 407 { 408 led->defs.next = NULL; 409 if (last != NULL) 410 last->defs.next = (CommonInfo *) led; 411 else 412 unbound = led; 413 last = led; 414 } 415 else 416 free(led); 417 } 418 else 419 { 420 XkbIndicatorMapPtr im; 421 im = &xkb->indicators->maps[led->indicator - 1]; 422 im->flags = led->flags; 423 im->which_groups = led->which_groups; 424 im->groups = led->groups; 425 im->which_mods = led->which_mods; 426 im->mods.mask = led->real_mods; 427 im->mods.real_mods = led->real_mods; 428 im->mods.vmods = led->vmods; 429 im->ctrls = led->ctrls; 430 if (xkb->names != NULL) 431 xkb->names->indicators[led->indicator - 1] = led->name; 432 free(led); 433 } 434 } 435 if (unboundRtrn != NULL) 436 { 437 *unboundRtrn = unbound; 438 } 439 return True; 440} 441 442Bool 443BindIndicators(XkbFileInfo * result, 444 Bool force, LEDInfo * unbound, LEDInfo ** unboundRtrn) 445{ 446 XkbDescPtr xkb; 447 LEDInfo *led, *next, *last; 448 449 xkb = result->xkb; 450 if (xkb->names != NULL) 451 { 452 for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next) 453 { 454 if (led->indicator == _LED_NotBound) 455 { 456 for (int i = 0; i < XkbNumIndicators; i++) 457 { 458 if (xkb->names->indicators[i] == led->name) 459 { 460 led->indicator = i + 1; 461 break; 462 } 463 } 464 } 465 } 466 if (force) 467 { 468 for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next) 469 { 470 if (led->indicator == _LED_NotBound) 471 { 472 for (int i = 0; i < XkbNumIndicators; i++) 473 { 474 if (xkb->names->indicators[i] == None) 475 { 476 xkb->names->indicators[i] = led->name; 477 led->indicator = i + 1; 478 xkb->indicators->phys_indicators &= ~(1 << i); 479 break; 480 } 481 } 482 if (led->indicator == _LED_NotBound) 483 { 484 ERROR("No unnamed indicators found\n"); 485 ACTION 486 ("Virtual indicator map \"%s\" not bound\n", 487 XkbAtomGetString(xkb->dpy, led->name)); 488 continue; 489 } 490 } 491 } 492 } 493 } 494 for (last = NULL, led = unbound; led != NULL; led = next) 495 { 496 next = (LEDInfo *) led->defs.next; 497 if (led->indicator == _LED_NotBound) 498 { 499 if (force) 500 { 501 unbound = next; 502 free(led); 503 } 504 else 505 { 506 if (last) 507 last->defs.next = &led->defs; 508 else 509 unbound = led; 510 last = led; 511 } 512 } 513 else 514 { 515 if ((xkb->names != NULL) && 516 (xkb->names->indicators[led->indicator - 1] != led->name)) 517 { 518 Atom old = xkb->names->indicators[led->indicator - 1]; 519 ERROR("Multiple names bound to indicator %d\n", 520 (unsigned int) led->indicator); 521 ACTION("Using %s, ignoring %s\n", 522 XkbAtomGetString(xkb->dpy, old), 523 XkbAtomGetString(xkb->dpy, led->name)); 524 led->indicator = _LED_NotBound; 525 if (force) 526 { 527 free(led); 528 unbound = next; 529 } 530 else 531 { 532 if (last) 533 last->defs.next = &led->defs; 534 else 535 unbound = led; 536 last = led; 537 } 538 } 539 else 540 { 541 XkbIndicatorMapPtr map; 542 map = &xkb->indicators->maps[led->indicator - 1]; 543 map->flags = led->flags; 544 map->which_groups = led->which_groups; 545 map->groups = led->groups; 546 map->which_mods = led->which_mods; 547 map->mods.mask = led->real_mods; 548 map->mods.real_mods = led->real_mods; 549 map->mods.vmods = led->vmods; 550 map->ctrls = led->ctrls; 551 if (last) 552 last->defs.next = &next->defs; 553 else 554 unbound = next; 555 led->defs.next = NULL; 556 free(led); 557 } 558 } 559 } 560 if (unboundRtrn) 561 { 562 *unboundRtrn = unbound; 563 } 564 else if (unbound) 565 { 566 for (led = unbound; led != NULL; led = next) 567 { 568 next = (LEDInfo *) led->defs.next; 569 free(led); 570 } 571 } 572 return True; 573} 574