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