Home | History | Annotate | Line # | Download | only in src
      1 /*
      2 
      3 Copyright 1989, 1994, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in 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 (at) 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  */
     50 static void XawToggleClassInitialize(void);
     51 static void XawToggleInitialize(Widget, Widget, ArgList, Cardinal*);
     52 static Boolean XawToggleSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
     53 
     54 /*
     55  * Prototypes
     56  */
     57 static void AddToRadioGroup(RadioGroup*, Widget);
     58 static void CreateRadioGroup(Widget, Widget);
     59 static RadioGroup *GetRadioGroup(Widget);
     60 static void RemoveFromRadioGroup(Widget);
     61 static void TurnOffRadioSiblings(Widget);
     62 static void XawToggleDestroy(Widget, XtPointer, XtPointer);
     63 
     64 /*
     65  * Actions
     66  */
     67 static void Notify(Widget, XEvent*, String*, Cardinal*);
     68 static void Toggle(Widget, XEvent*, String*, Cardinal*);
     69 static 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  */
     78 static 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)
     85 static 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 
    116 static XtActionsRec actionsList[] = {
    117   {"toggle",		Toggle},
    118   {"notify",		Notify},
    119   {"set",		ToggleSet},
    120 };
    121 
    122 #define Superclass	((CommandWidgetClass)&commandClassRec)
    123 ToggleClassRec 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 
    182 WidgetClass toggleWidgetClass = (WidgetClass)&toggleClassRec;
    183 
    184 /*
    185  * Implementation
    186  */
    187 static void
    188 XawToggleClassInitialize(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*/
    229 static void
    230 XawToggleInitialize(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*/
    264 static void
    265 ToggleSet(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 
    273 static void
    274 Toggle(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*/
    286 static void
    287 Notify(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*/
    296 static Boolean
    297 XawToggleSetValues(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*/
    331 static void
    332 XawToggleDestroy(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  */
    350 static RadioGroup *
    351 GetRadioGroup(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  */
    375 static void
    376 CreateRadioGroup(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  */
    401 static void
    402 AddToRadioGroup(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  */
    433 static void
    434 TurnOffRadioSiblings(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  */
    467 static void
    468 RemoveFromRadioGroup(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  */
    491 void
    492 XawToggleChangeRadioGroup(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  */
    530 XtPointer
    531 XawToggleGetCurrent(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  */
    563 void
    564 XawToggleSetCurrent(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  */
    615 void
    616 XawToggleUnsetCurrent(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