Toggle.c revision 421c997b
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 "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 }, 163 /* label */ 164 { 165 NULL, /* extension */ 166 }, 167 /* command */ 168 { 169 NULL, /* extension */ 170 }, 171 /* toggle */ 172 { 173 NULL, /* Set */ 174 NULL, /* Unset */ 175 NULL, /* extension */ 176 } 177}; 178 179WidgetClass toggleWidgetClass = (WidgetClass)&toggleClassRec; 180 181/* 182 * Impelementation 183 */ 184static void 185XawToggleClassInitialize(void) 186{ 187 XtActionList actions; 188 Cardinal num_actions; 189 Cardinal i; 190 ToggleWidgetClass cclass = (ToggleWidgetClass)toggleWidgetClass; 191 static XtConvertArgRec parentCvtArgs[] = { 192 {XtBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.parent), 193 sizeof(Widget)} 194 }; 195 196 XawInitializeWidgetSet(); 197 XtSetTypeConverter(XtRString, XtRWidget, XmuNewCvtStringToWidget, 198 parentCvtArgs, XtNumber(parentCvtArgs), 199 XtCacheNone, NULL); 200 XtSetTypeConverter(XtRWidget, XtRString, XmuCvtWidgetToString, 201 NULL, 0, XtCacheNone, NULL); 202 203 /* 204 * Find the set and unset actions in the command widget's action table 205 */ 206 XtGetActionList(commandWidgetClass, &actions, &num_actions); 207 208 for (i = 0 ; i < num_actions ; i++) { 209 if (streq(actions[i].string, "set")) 210 cclass->toggle_class.Set = actions[i].proc; 211 if (streq(actions[i].string, "unset")) 212 cclass->toggle_class.Unset = actions[i].proc; 213 214 if (cclass->toggle_class.Set != NULL && 215 cclass->toggle_class.Unset != NULL) { 216 XtFree((char *)actions); 217 return; 218 } 219 } 220 221 /* We should never get here */ 222 XtError("Aborting, due to errors resolving bindings in the Toggle widget."); 223} 224 225/*ARGSUSED*/ 226static void 227XawToggleInitialize(Widget request, Widget cnew, 228 ArgList args, Cardinal *num_args) 229{ 230 ToggleWidget tw = (ToggleWidget)cnew; 231 ToggleWidget tw_req = (ToggleWidget)request; 232 233 tw->toggle.radio_group = NULL; 234 235 if (tw->toggle.radio_data == NULL) 236 tw->toggle.radio_data = (XtPointer)cnew->core.name; 237 238 if (tw->toggle.widget != NULL) { 239 if (GetRadioGroup(tw->toggle.widget) == NULL) 240 CreateRadioGroup(cnew, tw->toggle.widget); 241 else 242 AddToRadioGroup(GetRadioGroup(tw->toggle.widget), cnew); 243 } 244 XtAddCallback(cnew, XtNdestroyCallback, XawToggleDestroy, NULL); 245 246 /* 247 * Command widget assumes that the widget is unset, so we only 248 * have to handle the case where it needs to be set 249 * 250 * If this widget is in a radio group then it may cause another 251 * widget to be unset, thus calling the notify proceedure 252 * 253 * I want to set the toggle if the user set the state to "On" in 254 * the resource group, reguardless of what my ancestors did 255 */ 256 if (tw_req->command.set) 257 ToggleSet(cnew, NULL, NULL, NULL); 258} 259 260/*ARGSUSED*/ 261static void 262ToggleSet(Widget w, XEvent *event, String *params, Cardinal *num_params) 263{ 264 ToggleWidgetClass cclass = (ToggleWidgetClass)w->core.widget_class; 265 266 TurnOffRadioSiblings(w); 267 cclass->toggle_class.Set(w, event, NULL, NULL); 268} 269 270static void 271Toggle(Widget w, XEvent *event, String *params, Cardinal *num_params) 272{ 273 ToggleWidget tw = (ToggleWidget)w; 274 ToggleWidgetClass cclass = (ToggleWidgetClass)w->core.widget_class; 275 276 if (tw->command.set) 277 cclass->toggle_class.Unset(w, event, NULL, NULL); 278 else 279 ToggleSet(w, event, params, num_params); 280} 281 282/*ARGSUSED*/ 283static void 284Notify(Widget w, XEvent *event, String *params, Cardinal *num_params) 285{ 286 ToggleWidget tw = (ToggleWidget)w; 287 long antilint = tw->command.set; 288 289 XtCallCallbacks(w, XtNcallback, (XtPointer)antilint); 290} 291 292/*ARGSUSED*/ 293static Boolean 294XawToggleSetValues(Widget current, Widget request, Widget cnew, 295 ArgList args, Cardinal *num_args) 296{ 297 ToggleWidget oldtw = (ToggleWidget)current; 298 ToggleWidget tw = (ToggleWidget)cnew; 299 ToggleWidget rtw = (ToggleWidget)request; 300 301 if (oldtw->toggle.widget != tw->toggle.widget) 302 XawToggleChangeRadioGroup(cnew, tw->toggle.widget); 303 304 if (!tw->core.sensitive && oldtw->core.sensitive && rtw->command.set) 305 tw->command.set = True; 306 307 if (oldtw->command.set != tw->command.set) { 308 tw->command.set = oldtw->command.set; 309 Toggle(cnew, NULL, NULL, NULL); 310 } 311 312 return (False); 313} 314 315/* 316 * Function: 317 * XawToggleDestroy 318 * 319 * Parameters: 320 * w - toggle widget that is being destroyed 321 * temp1 - not used 322 * temp2 - "" 323 * 324 * Description: 325 * Destroy Callback for toggle widget. 326 */ 327/*ARGSUSED*/ 328static void 329XawToggleDestroy(Widget w, XtPointer temp1, XtPointer temp2) 330{ 331 RemoveFromRadioGroup(w); 332} 333 334/* 335 * Function: 336 * GetRadioGroup 337 * 338 * Parameters: 339 * w - toggle widget who's radio group we are getting 340 * 341 * Description: 342 * Gets the radio group associated with a give toggle widget. 343 * 344 * Returns: 345 * The radio group associated with this toggle group 346 */ 347static RadioGroup * 348GetRadioGroup(Widget w) 349{ 350 ToggleWidget tw = (ToggleWidget)w; 351 352 if (tw == NULL) 353 return (NULL); 354 355 return (tw->toggle.radio_group); 356} 357 358/* 359 * Function: 360 * CreateRadioGroup 361 * 362 * Parameters: 363 * w1 - toggle widgets to add to the radio group 364 * w2 - "" 365 * 366 * Description: 367 * Creates a radio group. give two widgets. 368 * 369 * Note: 370 * A pointer to the group is added to each widget's radio_group field. 371 */ 372static void 373CreateRadioGroup(Widget w1, Widget w2) 374{ 375 ToggleWidget tw1 = (ToggleWidget)w1; 376 ToggleWidget tw2 = (ToggleWidget) w2; 377 378 if (tw1->toggle.radio_group != NULL || tw2->toggle.radio_group != NULL) 379 XtAppWarning(XtWidgetToApplicationContext(w1), 380 "Toggle Widget Error - Attempting to create a " 381 "new toggle group, when one already exists."); 382 383 AddToRadioGroup(NULL, w1); 384 AddToRadioGroup(GetRadioGroup(w1), w2); 385} 386 387/* 388 * Function: 389 * AddToRadioGroup 390 * 391 * Parameters: 392 * group - element of the radio group the we are adding to 393 * w - new toggle widget to add to the group 394 * 395 * Description: 396 * Adds a toggle to the radio group. 397 */ 398static void 399AddToRadioGroup(RadioGroup *group, Widget w) 400{ 401 ToggleWidget tw = (ToggleWidget)w; 402 RadioGroup *local; 403 404 local = (RadioGroup *)XtMalloc(sizeof(RadioGroup)); 405 local->widget = w; 406 tw->toggle.radio_group = local; 407 408 if (group == NULL) { /* Creating new group */ 409 group = local; 410 group->next = NULL; 411 group->prev = NULL; 412 return; 413 } 414 local->prev = group; /* Adding to previous group */ 415 if ((local->next = group->next) != NULL) 416 local->next->prev = local; 417 group->next = local; 418} 419 420/* 421 * Function: 422 * TurnOffRadioSiblings 423 * 424 * Parameters: 425 * widget - toggle widget 426 * 427 * Description: 428 * Deactivates all radio siblings. 429 */ 430static void 431TurnOffRadioSiblings(Widget w) 432{ 433 RadioGroup *group; 434 ToggleWidgetClass cclass = (ToggleWidgetClass)w->core.widget_class; 435 436 if ((group = GetRadioGroup(w)) == NULL) /* Punt if there is no group */ 437 return; 438 439 /* Go to the top of the group */ 440 for (; group->prev != NULL ; group = group->prev) 441 ; 442 443 while (group != NULL) { 444 ToggleWidget local_tog = (ToggleWidget)group->widget; 445 446 if (local_tog->command.set) { 447 cclass->toggle_class.Unset(group->widget, NULL, NULL, NULL); 448 Notify(group->widget, NULL, NULL, NULL); 449 } 450 group = group->next; 451 } 452} 453 454/* 455 * Function: 456 * RemoveFromRadioGroup 457 * 458 * Parameters: 459 * w - toggle widget to remove 460 * 461 * Description: 462 * Removes a toggle from a RadioGroup. 463 */ 464static void 465RemoveFromRadioGroup(Widget w) 466{ 467 RadioGroup *group = GetRadioGroup(w); 468 if (group != NULL) { 469 if (group->prev != NULL) 470 (group->prev)->next = group->next; 471 if (group->next != NULL) 472 (group->next)->prev = group->prev; 473 XtFree((char *)group); 474 } 475} 476 477/* 478 * Function: 479 * XawToggleChangeRadioGroup 480 * 481 * Parameters: 482 * w - toggle widget to change groups 483 * radio_group - any widget in the new group 484 * 485 * Description: 486 * Allows a toggle widget to change radio groups. 487 */ 488void 489XawToggleChangeRadioGroup(Widget w, Widget radio_group) 490{ 491 ToggleWidget tw = (ToggleWidget)w; 492 RadioGroup *group; 493 494 RemoveFromRadioGroup(w); 495 496 /* 497 * If the toggle that we are about to add is set then we will 498 * unset all toggles in the new radio group 499 */ 500 501 if (tw->command.set && radio_group != NULL) 502 XawToggleUnsetCurrent(radio_group); 503 504 if (radio_group != NULL) { 505 if ((group = GetRadioGroup(radio_group)) == NULL) 506 CreateRadioGroup(w, radio_group); 507 else 508 AddToRadioGroup(group, w); 509 } 510} 511 512/* 513 * Function: 514 * XawToggleGetCurrent 515 * 516 * Parameters: 517 * w - any toggle widget in the toggle group 518 * 519 * Description: 520 * Returns the RadioData associated with the toggle 521 * widget that is currently active in a toggle group. 522 * 523 * Returns: 524 * The XtNradioData associated with the toggle widget 525 */ 526XtPointer 527XawToggleGetCurrent(Widget w) 528{ 529 RadioGroup *group; 530 531 if ((group = GetRadioGroup(w)) == NULL) 532 return (NULL); 533 534 for (; group->prev != NULL ; group = group->prev) 535 ; 536 537 while (group != NULL) { 538 ToggleWidget local_tog = (ToggleWidget)group->widget; 539 540 if (local_tog->command.set) 541 return (local_tog->toggle.radio_data); 542 group = group->next; 543 } 544 545 return (NULL); 546} 547 548/* 549 * Function: 550 * XawToggleSetCurrent 551 * 552 * Parameters: 553 * radio_group - any toggle widget in the toggle group 554 * radio_data - radio data of the toggle widget to set 555 * 556 * Description: 557 * Sets the Toggle widget associated with the radio_data specified. 558 */ 559void 560XawToggleSetCurrent(Widget radio_group, XtPointer radio_data) 561{ 562 RadioGroup *group; 563 ToggleWidget local_tog; 564 565 /* Special case of no radio group */ 566 567 if ((group = GetRadioGroup(radio_group)) == NULL) { 568 local_tog = (ToggleWidget)radio_group; 569 570 if (local_tog->toggle.radio_data == radio_data && 571 !local_tog->command.set) { 572 ToggleSet(radio_group, NULL, NULL, NULL); 573 Notify(radio_group, NULL, NULL, NULL); 574 } 575 return; 576 } 577 578 /* 579 * find top of radio_roup 580 */ 581 for (; group->prev != NULL ; group = group->prev) 582 ; 583 584 /* 585 * search for matching radio data 586 */ 587 while (group != NULL) { 588 local_tog = (ToggleWidget)group->widget; 589 590 if (local_tog->toggle.radio_data == radio_data) { 591 if (!local_tog->command.set) { /* if not already set */ 592 ToggleSet(group->widget, NULL, NULL, NULL); 593 Notify(group->widget, NULL, NULL, NULL); 594 } 595 return; /* found it, done */ 596 } 597 group = group->next; 598 } 599} 600 601/* 602 * Function: 603 * XawToggleUnsetCurrent 604 * 605 * Parameters: 606 * radio_group - any toggle widget in the toggle group 607 * 608 * Description: 609 * Unsets all Toggles in the radio_group specified. 610 */ 611void 612XawToggleUnsetCurrent(Widget radio_group) 613{ 614 ToggleWidgetClass cclass; 615 ToggleWidget local_tog = (ToggleWidget)radio_group; 616 617 /* Special Case no radio group */ 618 619 if (local_tog->command.set) { 620 cclass = (ToggleWidgetClass)local_tog->core.widget_class; 621 cclass->toggle_class.Unset(radio_group, NULL, NULL, NULL); 622 Notify(radio_group, NULL, NULL, NULL); 623 } 624 if (GetRadioGroup(radio_group) == NULL) 625 return; 626 627 TurnOffRadioSiblings(radio_group); 628} 629