upload tizen2.0 source
[framework/uifw/xorg/lib/libxaw.git] / src / Toggle.c
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@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     "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   },
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
179 WidgetClass toggleWidgetClass = (WidgetClass)&toggleClassRec;
180
181 /*
182  * Impelementation
183  */
184 static void
185 XawToggleClassInitialize(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*/
226 static void
227 XawToggleInitialize(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*/
261 static void
262 ToggleSet(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
270 static void
271 Toggle(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*/
283 static void
284 Notify(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*/
293 static Boolean
294 XawToggleSetValues(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*/
328 static void
329 XawToggleDestroy(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  */
347 static RadioGroup *
348 GetRadioGroup(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  */
372 static void
373 CreateRadioGroup(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  */
398 static void
399 AddToRadioGroup(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  */
430 static void
431 TurnOffRadioSiblings(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  */
464 static void
465 RemoveFromRadioGroup(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  */
488 void
489 XawToggleChangeRadioGroup(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  */
526 XtPointer
527 XawToggleGetCurrent(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  */
559 void
560 XawToggleSetCurrent(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  */
611 void
612 XawToggleUnsetCurrent(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 }