Toggle.c revision efbcb2bf
1/* 2 3Copyright 1989, 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27/* 28 * Author: Chris D. Peterson 29 * MIT X Consortium 30 * kit@expo.lcs.mit.edu 31 * 32 * Date: January 12, 1989 33 * 34 */ 35 36#ifdef HAVE_CONFIG_H 37#include <config.h> 38#endif 39#include <stdio.h> 40#include <X11/IntrinsicP.h> 41#include <X11/StringDefs.h> 42#include <X11/Xmu/Converters.h> 43#include <X11/Xmu/Misc.h> 44#include <X11/Xaw/ToggleP.h> 45#include <X11/Xaw/XawInit.h> 46 47/* 48 * Class Methods 49 */ 50static void XawToggleClassInitialize(void); 51static void XawToggleInitialize(Widget, Widget, ArgList, Cardinal*); 52static Boolean XawToggleSetValues(Widget, Widget, Widget, ArgList, Cardinal*); 53 54/* 55 * Prototypes 56 */ 57static void AddToRadioGroup(RadioGroup*, Widget); 58static void CreateRadioGroup(Widget, Widget); 59static RadioGroup *GetRadioGroup(Widget); 60static void RemoveFromRadioGroup(Widget); 61static void TurnOffRadioSiblings(Widget); 62static void XawToggleDestroy(Widget, XtPointer, XtPointer); 63 64/* 65 * Actions 66 */ 67static void Notify(Widget, XEvent*, String*, Cardinal*); 68static void Toggle(Widget, XEvent*, String*, Cardinal*); 69static void ToggleSet(Widget, XEvent*, String*, Cardinal*); 70 71/* 72 * Initialization 73 */ 74/* 75 * The order of toggle and notify are important, as the state has 76 * to be set when we call the notify proc 77 */ 78static char defaultTranslations[] = 79"<Enter>:" "highlight(Always)\n" 80"<Leave>:" "unhighlight()\n" 81"<Btn1Down>,<Btn1Up>:" "toggle() notify()\n" 82; 83 84#define offset(field) XtOffsetOf(ToggleRec, field) 85static XtResource resources[] = { 86 { 87 XtNstate, 88 XtCState, 89 XtRBoolean, 90 sizeof(Boolean), 91 offset(command.set), 92 XtRString, 93 (XtPointer)"off" 94 }, 95 { 96 XtNradioGroup, 97 XtCWidget, 98 XtRWidget, 99 sizeof(Widget), 100 offset(toggle.widget), 101 XtRWidget, 102 NULL 103 }, 104 { 105 XtNradioData, 106 XtCRadioData, 107 XtRPointer, 108 sizeof(XtPointer), 109 offset(toggle.radio_data), 110 XtRPointer, 111 NULL 112 }, 113}; 114#undef offset 115 116static XtActionsRec actionsList[] = { 117 {"toggle", Toggle}, 118 {"notify", Notify}, 119 {"set", ToggleSet}, 120}; 121 122#define Superclass ((CommandWidgetClass)&commandClassRec) 123ToggleClassRec toggleClassRec = { 124 /* core */ 125 { 126 (WidgetClass)Superclass, /* superclass */ 127 "Toggle", /* class_name */ 128 sizeof(ToggleRec), /* size */ 129 XawToggleClassInitialize, /* class_initialize */ 130 NULL, /* class_part_initialize */ 131 False, /* class_inited */ 132 XawToggleInitialize, /* initialize */ 133 NULL, /* initialize_hook */ 134 XtInheritRealize, /* realize */ 135 actionsList, /* actions */ 136 XtNumber(actionsList), /* num_actions */ 137 resources, /* resources */ 138 XtNumber(resources), /* resource_count */ 139 NULLQUARK, /* xrm_class */ 140 False, /* compress_motion */ 141 True, /* compress_exposure */ 142 True, /* compress_enterleave */ 143 False, /* visible_interest */ 144 NULL, /* destroy */ 145 XtInheritResize, /* resize */ 146 XtInheritExpose, /* expose */ 147 XawToggleSetValues, /* set_values */ 148 NULL, /* set_values_hook */ 149 XtInheritSetValuesAlmost, /* set_values_almost */ 150 NULL, /* get_values_hook */ 151 NULL, /* accept_focus */ 152 XtVersion, /* version */ 153 NULL, /* callback_private */ 154 defaultTranslations, /* tm_table */ 155 XtInheritQueryGeometry, /* query_geometry */ 156 XtInheritDisplayAccelerator, /* display_accelerator */ 157 NULL, /* extension */ 158 }, 159 /* simple */ 160 { 161 XtInheritChangeSensitive, /* change_sensitive */ 162#ifndef OLDXAW 163 NULL, 164#endif 165 }, 166 /* label */ 167 { 168 NULL, /* extension */ 169 }, 170 /* command */ 171 { 172 NULL, /* extension */ 173 }, 174 /* toggle */ 175 { 176 NULL, /* Set */ 177 NULL, /* Unset */ 178 NULL, /* extension */ 179 } 180}; 181 182WidgetClass toggleWidgetClass = (WidgetClass)&toggleClassRec; 183 184/* 185 * Implementation 186 */ 187static void 188XawToggleClassInitialize(void) 189{ 190 XtActionList actions; 191 Cardinal num_actions; 192 Cardinal i; 193 ToggleWidgetClass cclass = (ToggleWidgetClass)toggleWidgetClass; 194 static XtConvertArgRec parentCvtArgs[] = { 195 {XtBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.parent), 196 sizeof(Widget)} 197 }; 198 199 XawInitializeWidgetSet(); 200 XtSetTypeConverter(XtRString, XtRWidget, XmuNewCvtStringToWidget, 201 parentCvtArgs, XtNumber(parentCvtArgs), 202 XtCacheNone, NULL); 203 XtSetTypeConverter(XtRWidget, XtRString, XmuCvtWidgetToString, 204 NULL, 0, XtCacheNone, NULL); 205 206 /* 207 * Find the set and unset actions in the command widget's action table 208 */ 209 XtGetActionList(commandWidgetClass, &actions, &num_actions); 210 211 for (i = 0 ; i < num_actions ; i++) { 212 if (streq(actions[i].string, "set")) 213 cclass->toggle_class.Set = actions[i].proc; 214 if (streq(actions[i].string, "unset")) 215 cclass->toggle_class.Unset = actions[i].proc; 216 217 if (cclass->toggle_class.Set != NULL && 218 cclass->toggle_class.Unset != NULL) { 219 XtFree((char *)actions); 220 return; 221 } 222 } 223 224 /* We should never get here */ 225 XtError("Aborting, due to errors resolving bindings in the Toggle widget."); 226} 227 228/*ARGSUSED*/ 229static void 230XawToggleInitialize(Widget request, Widget cnew, 231 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 232{ 233 ToggleWidget tw = (ToggleWidget)cnew; 234 ToggleWidget tw_req = (ToggleWidget)request; 235 236 tw->toggle.radio_group = NULL; 237 238 if (tw->toggle.radio_data == NULL) 239 tw->toggle.radio_data = (XtPointer)cnew->core.name; 240 241 if (tw->toggle.widget != NULL) { 242 if (GetRadioGroup(tw->toggle.widget) == NULL) 243 CreateRadioGroup(cnew, tw->toggle.widget); 244 else 245 AddToRadioGroup(GetRadioGroup(tw->toggle.widget), cnew); 246 } 247 XtAddCallback(cnew, XtNdestroyCallback, XawToggleDestroy, NULL); 248 249 /* 250 * Command widget assumes that the widget is unset, so we only 251 * have to handle the case where it needs to be set 252 * 253 * If this widget is in a radio group then it may cause another 254 * widget to be unset, thus calling the notify procedure 255 * 256 * I want to set the toggle if the user set the state to "On" in 257 * the resource group, regardless of what my ancestors did 258 */ 259 if (tw_req->command.set) 260 ToggleSet(cnew, NULL, NULL, NULL); 261} 262 263/*ARGSUSED*/ 264static void 265ToggleSet(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 266{ 267 ToggleWidgetClass cclass = (ToggleWidgetClass)w->core.widget_class; 268 269 TurnOffRadioSiblings(w); 270 cclass->toggle_class.Set(w, event, NULL, NULL); 271} 272 273static void 274Toggle(Widget w, XEvent *event, String *params, Cardinal *num_params) 275{ 276 ToggleWidget tw = (ToggleWidget)w; 277 ToggleWidgetClass cclass = (ToggleWidgetClass)w->core.widget_class; 278 279 if (tw->command.set) 280 cclass->toggle_class.Unset(w, event, NULL, NULL); 281 else 282 ToggleSet(w, event, params, num_params); 283} 284 285/*ARGSUSED*/ 286static void 287Notify(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 288{ 289 ToggleWidget tw = (ToggleWidget)w; 290 long antilint = tw->command.set; 291 292 XtCallCallbacks(w, XtNcallback, (XtPointer)antilint); 293} 294 295/*ARGSUSED*/ 296static Boolean 297XawToggleSetValues(Widget current, Widget request, Widget cnew, 298 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 299{ 300 ToggleWidget oldtw = (ToggleWidget)current; 301 ToggleWidget tw = (ToggleWidget)cnew; 302 ToggleWidget rtw = (ToggleWidget)request; 303 304 if (oldtw->toggle.widget != tw->toggle.widget) 305 XawToggleChangeRadioGroup(cnew, tw->toggle.widget); 306 307 if (!tw->core.sensitive && oldtw->core.sensitive && rtw->command.set) 308 tw->command.set = True; 309 310 if (oldtw->command.set != tw->command.set) { 311 tw->command.set = oldtw->command.set; 312 Toggle(cnew, NULL, NULL, NULL); 313 } 314 315 return (False); 316} 317 318/* 319 * Function: 320 * XawToggleDestroy 321 * 322 * Parameters: 323 * w - toggle widget that is being destroyed 324 * temp1 - not used 325 * temp2 - "" 326 * 327 * Description: 328 * Destroy Callback for toggle widget. 329 */ 330/*ARGSUSED*/ 331static void 332XawToggleDestroy(Widget w, XtPointer temp1 _X_UNUSED, XtPointer temp2 _X_UNUSED) 333{ 334 RemoveFromRadioGroup(w); 335} 336 337/* 338 * Function: 339 * GetRadioGroup 340 * 341 * Parameters: 342 * w - toggle widget who's radio group we are getting 343 * 344 * Description: 345 * Gets the radio group associated with a give toggle widget. 346 * 347 * Returns: 348 * The radio group associated with this toggle group 349 */ 350static RadioGroup * 351GetRadioGroup(Widget w) 352{ 353 ToggleWidget tw = (ToggleWidget)w; 354 355 if (tw == NULL) 356 return (NULL); 357 358 return (tw->toggle.radio_group); 359} 360 361/* 362 * Function: 363 * CreateRadioGroup 364 * 365 * Parameters: 366 * w1 - toggle widgets to add to the radio group 367 * w2 - "" 368 * 369 * Description: 370 * Creates a radio group. give two widgets. 371 * 372 * Note: 373 * A pointer to the group is added to each widget's radio_group field. 374 */ 375static void 376CreateRadioGroup(Widget w1, Widget w2) 377{ 378 ToggleWidget tw1 = (ToggleWidget)w1; 379 ToggleWidget tw2 = (ToggleWidget) w2; 380 381 if (tw1->toggle.radio_group != NULL || tw2->toggle.radio_group != NULL) 382 XtAppWarning(XtWidgetToApplicationContext(w1), 383 "Toggle Widget Error - Attempting to create a " 384 "new toggle group, when one already exists."); 385 386 AddToRadioGroup(NULL, w1); 387 AddToRadioGroup(GetRadioGroup(w1), w2); 388} 389 390/* 391 * Function: 392 * AddToRadioGroup 393 * 394 * Parameters: 395 * group - element of the radio group the we are adding to 396 * w - new toggle widget to add to the group 397 * 398 * Description: 399 * Adds a toggle to the radio group. 400 */ 401static void 402AddToRadioGroup(RadioGroup *group, Widget w) 403{ 404 ToggleWidget tw = (ToggleWidget)w; 405 RadioGroup *local; 406 407 local = (RadioGroup *)XtMalloc(sizeof(RadioGroup)); 408 local->widget = w; 409 tw->toggle.radio_group = local; 410 411 if (group == NULL) { /* Creating new group */ 412 group = local; 413 group->next = NULL; 414 group->prev = NULL; 415 return; 416 } 417 local->prev = group; /* Adding to previous group */ 418 if ((local->next = group->next) != NULL) 419 local->next->prev = local; 420 group->next = local; 421} 422 423/* 424 * Function: 425 * TurnOffRadioSiblings 426 * 427 * Parameters: 428 * widget - toggle widget 429 * 430 * Description: 431 * Deactivates all radio siblings. 432 */ 433static void 434TurnOffRadioSiblings(Widget w) 435{ 436 RadioGroup *group; 437 ToggleWidgetClass cclass = (ToggleWidgetClass)w->core.widget_class; 438 439 if ((group = GetRadioGroup(w)) == NULL) /* Punt if there is no group */ 440 return; 441 442 /* Go to the top of the group */ 443 for (; group->prev != NULL ; group = group->prev) 444 ; 445 446 while (group != NULL) { 447 ToggleWidget local_tog = (ToggleWidget)group->widget; 448 449 if (local_tog->command.set) { 450 cclass->toggle_class.Unset(group->widget, NULL, NULL, NULL); 451 Notify(group->widget, NULL, NULL, NULL); 452 } 453 group = group->next; 454 } 455} 456 457/* 458 * Function: 459 * RemoveFromRadioGroup 460 * 461 * Parameters: 462 * w - toggle widget to remove 463 * 464 * Description: 465 * Removes a toggle from a RadioGroup. 466 */ 467static void 468RemoveFromRadioGroup(Widget w) 469{ 470 RadioGroup *group = GetRadioGroup(w); 471 if (group != NULL) { 472 if (group->prev != NULL) 473 (group->prev)->next = group->next; 474 if (group->next != NULL) 475 (group->next)->prev = group->prev; 476 XtFree((char *)group); 477 } 478} 479 480/* 481 * Function: 482 * XawToggleChangeRadioGroup 483 * 484 * Parameters: 485 * w - toggle widget to change groups 486 * radio_group - any widget in the new group 487 * 488 * Description: 489 * Allows a toggle widget to change radio groups. 490 */ 491void 492XawToggleChangeRadioGroup(Widget w, Widget radio_group) 493{ 494 ToggleWidget tw = (ToggleWidget)w; 495 496 RemoveFromRadioGroup(w); 497 498 /* 499 * If the toggle that we are about to add is set then we will 500 * unset all toggles in the new radio group 501 */ 502 503 if (tw->command.set && radio_group != NULL) 504 XawToggleUnsetCurrent(radio_group); 505 506 if (radio_group != NULL) { 507 RadioGroup *group = GetRadioGroup(radio_group); 508 509 if (group == NULL) 510 CreateRadioGroup(w, radio_group); 511 else 512 AddToRadioGroup(group, w); 513 } 514} 515 516/* 517 * Function: 518 * XawToggleGetCurrent 519 * 520 * Parameters: 521 * w - any toggle widget in the toggle group 522 * 523 * Description: 524 * Returns the RadioData associated with the toggle 525 * widget that is currently active in a toggle group. 526 * 527 * Returns: 528 * The XtNradioData associated with the toggle widget 529 */ 530XtPointer 531XawToggleGetCurrent(Widget w) 532{ 533 RadioGroup *group; 534 535 if ((group = GetRadioGroup(w)) == NULL) 536 return (NULL); 537 538 for (; group->prev != NULL ; group = group->prev) 539 ; 540 541 while (group != NULL) { 542 ToggleWidget local_tog = (ToggleWidget)group->widget; 543 544 if (local_tog->command.set) 545 return (local_tog->toggle.radio_data); 546 group = group->next; 547 } 548 549 return (NULL); 550} 551 552/* 553 * Function: 554 * XawToggleSetCurrent 555 * 556 * Parameters: 557 * radio_group - any toggle widget in the toggle group 558 * radio_data - radio data of the toggle widget to set 559 * 560 * Description: 561 * Sets the Toggle widget associated with the radio_data specified. 562 */ 563void 564XawToggleSetCurrent(Widget radio_group, XtPointer radio_data) 565{ 566 RadioGroup *group; 567 ToggleWidget local_tog; 568 569 /* Special case of no radio group */ 570 571 if ((group = GetRadioGroup(radio_group)) == NULL) { 572 local_tog = (ToggleWidget)radio_group; 573 574 if (local_tog->toggle.radio_data == radio_data && 575 !local_tog->command.set) { 576 ToggleSet(radio_group, NULL, NULL, NULL); 577 Notify(radio_group, NULL, NULL, NULL); 578 } 579 return; 580 } 581 582 /* 583 * find top of radio_roup 584 */ 585 for (; group->prev != NULL ; group = group->prev) 586 ; 587 588 /* 589 * search for matching radio data 590 */ 591 while (group != NULL) { 592 local_tog = (ToggleWidget)group->widget; 593 594 if (local_tog->toggle.radio_data == radio_data) { 595 if (!local_tog->command.set) { /* if not already set */ 596 ToggleSet(group->widget, NULL, NULL, NULL); 597 Notify(group->widget, NULL, NULL, NULL); 598 } 599 return; /* found it, done */ 600 } 601 group = group->next; 602 } 603} 604 605/* 606 * Function: 607 * XawToggleUnsetCurrent 608 * 609 * Parameters: 610 * radio_group - any toggle widget in the toggle group 611 * 612 * Description: 613 * Unsets all Toggles in the radio_group specified. 614 */ 615void 616XawToggleUnsetCurrent(Widget radio_group) 617{ 618 ToggleWidget local_tog = (ToggleWidget)radio_group; 619 620 /* Special Case no radio group */ 621 622 if (local_tog->command.set) { 623 ToggleWidgetClass cclass; 624 625 cclass = (ToggleWidgetClass)local_tog->core.widget_class; 626 cclass->toggle_class.Unset(radio_group, NULL, NULL, NULL); 627 Notify(radio_group, NULL, NULL, NULL); 628 } 629 if (GetRadioGroup(radio_group) == NULL) 630 return; 631 632 TurnOffRadioSiblings(radio_group); 633} 634