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