1 /**
2  *
3  * $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/ToggleBG.c,v 1.2 2004/10/21 18:53:59 dannybackx Exp $
4  *
5  * Copyright (C) 1995 Free Software Foundation, Inc.
6  * Copyright � 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004 LessTif Development Team
7  *
8  * This file is part of the GNU LessTif Library.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the Free
22  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  **/
25 
26 static const char rcsid[] = "$Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/ToggleBG.c,v 1.2 2004/10/21 18:53:59 dannybackx Exp $";
27 
28 #include <LTconfig.h>
29 
30 #include <stdarg.h>
31 #include <string.h>
32 
33 #include <XmI/XmI.h>
34 
35 #include <Xm/XmP.h>
36 #include <Xm/ToggleBGP.h>
37 #include <Xm/CascadeB.h>
38 #include <Xm/CascadeBG.h>
39 #include <Xm/RepType.h>
40 #include <Xm/RowColumnP.h>
41 #include <Xm/MenuShell.h>
42 #include <Xm/MenuUtilP.h>
43 #include <Xm/CacheP.h>
44 #include <X11/ShellP.h>
45 #include <Xm/ToggleBP.h>
46 
47 #include <XmI/DebugUtil.h>
48 
49 
50 /* Some M*tif versions (e.g. 1.2.6 on Solaris 2.6) leave less room above and
51  * below the indicator than others (e.g. 1.2.5 on HP-UX 10, my reference).
52  */
53 #undef LESS_VERTICAL_PADDING
54 
55 #define UNSPECIFIED_TBG_BOOLEAN	((Boolean)85)
56 #define SQUARE_INDICATOR_DEC	3
57 #define SQUARE_INDICATOR_ELBOW	10
58 #define PIXMAP_INDICATOR_ELBOW	13
59 
60 #define DETAIL_SHADOW_THICKNESS(w)	TBG_DetailShadowThickness(w)
61 #define INDICATOR_BOX_MASK		0x03
62 #define NEXT_TOGGLE(w)			(TBG_ToggleMode(w) == XmTOGGLE_BOOLEAN\
63 					 || TBG_IndType(w) != XmN_OF_MANY     \
64 					 ? !TBG_Set(w) : (TBG_Set(w) + 1) % 3)
65 
66 /* Forward Declarations */
67 
68 static void class_initialize(void);
69 
70 static void class_part_initialize(WidgetClass w_class);
71 
72 static void initialize(Widget request, Widget new_w,
73 		       ArgList args, Cardinal *num_args);
74 
75 static void destroy(Widget w);
76 
77 static void resize(Widget w);
78 
79 static void expose(Widget w, XEvent *event, Region region);
80 
81 static Boolean set_values(Widget current, Widget request, Widget new_w,
82 			  ArgList args, Cardinal *num_args);
83 
84 static void input_dispatch(Widget gadget, XEvent *event, Mask event_mask);
85 
86 static void secondary_object_create(Widget request, Widget new_w,
87 				    ArgList args, Cardinal *num_args);
88 
89 static void initialize_posthook(Widget request, Widget new_w,
90 				ArgList args, Cardinal *num_args);
91 
92 static Boolean set_values_prehook(Widget old, Widget request, Widget new_w,
93 				  ArgList args, Cardinal *num_args);
94 
95 static Boolean set_values_posthook(Widget old, Widget request, Widget new_w,
96 				   ArgList args, Cardinal *num_args);
97 
98 static void get_values_prehook(Widget new_w, ArgList args, Cardinal *num_args);
99 
100 static void get_values_posthook(Widget new_w, ArgList args, Cardinal *num_args);
101 
102 static Cardinal get_sec_res_data(WidgetClass wc,
103 				 XmSecondaryResourceData **data);
104 
105 
106 static void Arm(Widget w, XEvent *event,
107 		String *params, Cardinal *num_params);
108 
109 static void Select(Widget w, XEvent *event,
110 		   String *params, Cardinal *num_params);
111 
112 static void Disarm(Widget w, XEvent *event,
113 		   String *params, Cardinal *num_params);
114 
115 static void ArmAndActivate(Widget w, XEvent *event,
116 			   String *params, Cardinal *num_params);
117 
118 static void Help(Widget w, XEvent *event,
119 		 String *params, Cardinal *num_params);
120 
121 static void EnterWindow(Widget w, XEvent *event,
122 			String *params, Cardinal *num_params);
123 
124 static void LeaveWindow(Widget w, XEvent *event,
125 			String *params, Cardinal *num_params);
126 
127 static void ButtonDown(Widget w, XEvent *event,
128 		       String *params, Cardinal *num_params);
129 
130 static void ButtonUp(Widget w, XEvent *event,
131 		     String *params, Cardinal *num_params);
132 
133 static void MenuProcEntry(int proc, Widget rc,...);
134 
135 static void draw_toggle(Widget w, XEvent *event, Region region,
136 			int is_expose, int visual_set);
137 
138 static int implicit_indicator(Widget w);
139 static void _XmUnselectColorDefault(Widget, int, XrmValue *);
140 
141 /*
142  * resources
143  */
144 #define Offset(field) XtOffsetOf(XmToggleButtonGCacheObjRec, toggle_cache.field)
145 static XtResource cache_resources[] =
146 {
147     {
148 	XmNindicatorSize, XmCIndicatorSize, XmRVerticalDimension,
149 	sizeof(Dimension), Offset(indicator_dim),
150 	XmRImmediate, (XtPointer)XmINVALID_DIMENSION
151     },
152     {
153 	XmNindicatorType, XmCIndicatorType, XmRIndicatorType,
154 	sizeof(unsigned char), Offset(ind_type),
155 	XmRImmediate, (XtPointer)((unsigned char)XmUNSPECIFIED)
156     },
157     {
158 	XmNvisibleWhenOff, XmCVisibleWhenOff, XmRBoolean,
159 	sizeof(Boolean), Offset(visible),
160 	XmRImmediate, (XtPointer)UNSPECIFIED_TBG_BOOLEAN
161     },
162     {
163 	XmNspacing, XmCSpacing, XmRHorizontalDimension,
164 	sizeof(Dimension), Offset(spacing),
165 	XmRImmediate, (XtPointer)4
166     },
167     {
168 	XmNselectPixmap, XmCSelectPixmap, XmRGadgetPixmap,
169 	sizeof(Pixmap), Offset(on_pixmap),
170 	XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP
171     },
172     {
173 	XmNselectInsensitivePixmap, XmCSelectInsensitivePixmap, XmRGadgetPixmap,
174 	sizeof(Pixmap), Offset(insen_pixmap),
175 	XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP
176     },
177     {
178 	/* The type changed to an unsigned char in 2.0..oh just lovely. */
179 	XmNindicatorOn, XmCIndicatorOn, XmRIndicatorOn,
180 	sizeof(unsigned char), Offset(ind_on),
181 	XmRImmediate, (XtPointer)True
182     },
183     {
184 	XmNfillOnSelect, XmCFillOnSelect, XmRBoolean,
185 	sizeof(Boolean), Offset(fill_on_select),
186 	XmRImmediate, (XtPointer)UNSPECIFIED_TBG_BOOLEAN
187     },
188     {
189 	XmNselectColor, XmCSelectColor, XmRPixel,
190 	sizeof(Pixel), Offset(select_color),
191 	XmRCallProc, (XtPointer)_XmSelectColorDefault
192     },
193     {
194 	XmNunselectColor, XmCUnselectColor, XmRPixel,
195 	sizeof(Pixel), Offset(unselect_color),
196 	XmRCallProc, (XtPointer)_XmUnselectColorDefault
197     }
198 };
199 
200 static XmSyntheticResource cache_syn_resources[] =
201 {
202     {
203 	XmNspacing,
204 	sizeof(Dimension), Offset(spacing),
205 	_XmFromHorizontalPixels, _XmToHorizontalPixels
206     },
207     {
208 	XmNindicatorSize,
209 	sizeof(Dimension), Offset(indicator_dim),
210 	_XmFromVerticalPixels, _XmToVerticalPixels
211     }
212 };
213 
214 XmToggleButtonGCacheObjClassRec xmToggleButtonGCacheObjClassRec = {
215     /* Object class part */
216     {
217 	/* superclass            */ (WidgetClass) &xmLabelGCacheObjClassRec,
218 	/* class_name            */ "XmToggleButtonGCacheObjClass",
219 	/* widget_size           */ sizeof(XmToggleButtonGCacheObjRec),
220 	/* class_initialize      */ NULL,
221 	/* class_part_initialize */ NULL,
222 	/* class_inited          */ False,
223 	/* initialize            */ NULL,
224 	/* initialize_hook       */ NULL,
225 	/* realize               */ NULL,
226 	/* actions               */ NULL,
227 	/* num_actions           */ 0,
228 	/* resources             */ cache_resources,
229 	/* num_resources         */ XtNumber(cache_resources),
230 	/* xrm_class             */ NULLQUARK,
231 	/* compress_motion       */ 0,
232 	/* compress_exposure     */ 0,
233 	/* compress_enterleave   */ 0,
234 	/* visible_interest      */ 0,
235 	/* destroy               */ NULL,
236 	/* resize                */ NULL,
237 	/* expose                */ NULL,
238 	/* set_values            */ NULL,
239 	/* set_values_hook       */ NULL,
240 	/* set_values_almost     */ NULL,
241 	/* get_values_hook       */ NULL,
242 	/* accept_focus          */ NULL,
243 	/* version               */ XtVersion,
244 	/* callback offsets      */ NULL,
245 	/* tm_table              */ NULL,
246 	/* query_geometry        */ NULL,
247 	/* display_accelerator   */ NULL,
248 	/* extension             */ NULL
249     },
250     /* XmExtObject part */
251     {
252 	/* syn_resources      */ cache_syn_resources,
253 	/* num_syn_resources  */ XtNumber(cache_syn_resources),
254 	/* extension          */ NULL
255     },
256     /* LabelGCacheObj part */
257     {
258 	/* foo                */ 0
259     },
260     /* ToggleButtonGCacheObj part */
261     {
262 	/* foo                */ 0
263     }
264 };
265 
266 #undef Offset
267 #define Offset(field) XtOffsetOf(XmToggleButtonGadgetRec, toggle.field)
268 
269 /* Resources for the togglebutton class */
270 static XtResource resources[] = {
271     {
272 	XmNset, XmCSet, XmRBoolean,
273 	sizeof(Boolean), Offset(set),
274 	XmRImmediate,(XtPointer)False
275     },
276     {
277 	XmNvalueChangedCallback, XmCValueChangedCallback, XmRCallback,
278 	sizeof(XtCallbackList), Offset(value_changed_CB),
279 	XmRPointer, (XtPointer)NULL
280     },
281     {
282 	XmNarmCallback, XmCArmCallback, XmRCallback,
283 	sizeof(XtCallbackList), Offset(arm_CB),
284 	XmRPointer, (XtPointer)NULL
285     },
286     {
287 	XmNdisarmCallback, XmCDisarmCallback, XmRCallback,
288 	sizeof(XtCallbackList), Offset(disarm_CB),
289 	XmRPointer, (XtPointer)NULL
290     },
291     {
292 	XmNtraversalOn, XmCTraversalOn, XmRBoolean,
293 	sizeof(Boolean), XtOffsetOf(XmToggleButtonGadgetRec, gadget.traversal_on),
294 	XmRImmediate, (XtPointer)True
295     },
296     {
297 	XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension,
298 	sizeof(Dimension),
299 	XtOffsetOf(XmToggleButtonGadgetRec,gadget.highlight_thickness),
300 	XmRImmediate, (XtPointer)2
301     },
302     /* New for 2.0 : */
303     {
304 	XmNdetailShadowThickness, XmCDetailShadowThickness,
305 	XmRDimension, sizeof(Dimension),
306 	Offset(detail_shadow_thickness),
307 	XmRImmediate, (XtPointer)2
308     },
309     {
310 	XmNindeterminatePixmap, XmCIndeterminatePixmap,
311 	XmRGadgetPixmap, sizeof(Pixmap),
312 	Offset(indeterminate_pixmap),
313 	XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP
314     },
315     {
316 	XmNtoggleMode, XmCToggleMode,
317 	XmRToggleMode, sizeof(unsigned char),
318 	Offset(toggle_mode),
319 	XmRImmediate, (XtPointer)XmTOGGLE_BOOLEAN
320     }
321 };
322 
323 static XmSyntheticResource syn_resources[] =
324 {
325     {
326 	XmNdetailShadowThickness,
327 	sizeof(Dimension), Offset(detail_shadow_thickness),
328 	_XmFromHorizontalPixels, _XmToHorizontalPixels
329      }
330 };
331 
332 static XmBaseClassExtRec _XmToggleBGRectClassExtRec = {
333     /* next_extension            */ NULL,
334     /* record_type               */ NULLQUARK,
335     /* version                   */ XmBaseClassExtVersion,
336     /* size                      */ sizeof(XmBaseClassExtRec),
337     /* initialize_prehook        */ XmInheritInitializePrehook,
338     /* set_values_prehook        */ set_values_prehook,
339     /* initialize_posthook       */ initialize_posthook,
340     /* set_values_posthook       */ set_values_posthook,
341     /* secondary_object_class    */ (WidgetClass)&xmToggleButtonGCacheObjClassRec,
342     /* secondary_object_create   */ secondary_object_create,
343     /* get_secondary_resources   */ get_sec_res_data,
344     /* fast_subclass             */ { 0 },
345     /* get_values_prehook        */ get_values_prehook,
346     /* get_values_posthook       */ get_values_posthook,
347     /* class_part_init_prehook   */ NULL,
348     /* class_part_init_posthook  */ NULL,
349     /* ext_resources             */ NULL,
350     /* compiled_ext_resources    */ NULL,
351     /* num_ext_resources         */ 0,
352     /* use_sub_resources         */ False,
353     /* widget_navigable          */ XmInheritWidgetNavigable,
354     /* focus_change              */ XmInheritFocusChange,
355     /* wrapper_data              */ NULL
356 };
357 
358 static XmCacheClassPart cache_part = {
359     /* cache head part */
360     {
361 	/* next         */ NULL,
362 	/* prev         */ NULL,
363 	/* ref_count    */ 0
364     },
365     _XmCacheCopy,
366     _XmCacheDelete,
367     _XmToggleBCacheCompare
368 };
369 
370 static XmGadgetClassExtRec _XmToggleBGadgetClassExtRec = {
371     /* next_extension            */ NULL,
372     /* record_type               */ NULLQUARK,
373     /* version                   */ XmGadgetClassExtVersion,
374     /* size                      */ sizeof(XmGadgetClassExtRec),
375     /* widget_baseline_proc      */ XmInheritBaselineProc,
376     /* display_rect_proc         */ XmInheritDisplayRectProc,
377     /* margins_proc              */ XmInheritMarginsProc,
378 };
379 
380 XmToggleButtonGadgetClassRec xmToggleButtonGadgetClassRec = {
381     /* RectObj class part */
382     {
383 	/* superclass            */ (WidgetClass) &xmLabelGadgetClassRec,
384 	/* class_name            */ "XmToggleButtonGadget",
385 	/* widget_size           */ sizeof(XmToggleButtonGadgetRec),
386 	/* class_initialize      */ class_initialize,
387 	/* class_part_initialize */ class_part_initialize,
388 	/* class_inited          */ False,
389 	/* initialize            */ initialize,
390 	/* initialize_hook       */ NULL,
391 	/* realize               */ NULL, /* FIX ME */
392 	/* actions               */ NULL,
393 	/* num_actions           */ 0,
394 	/* resources             */ resources,
395 	/* num_resources         */ XtNumber(resources),
396 	/* xrm_class             */ NULLQUARK,
397 	/* compress_motion       */ True /*False*/,
398 	/* compress_exposure     */ XtExposeCompressMaximal /*XtExposeNoCompress*/,
399 	/* compress_enterleave   */ True /*False*/,
400 	/* visible_interest      */ False,
401 	/* destroy               */ destroy,
402 	/* resize                */ resize,
403 	/* expose                */ expose,
404 	/* set_values            */ set_values,
405 	/* set_values_hook       */ NULL,
406 	/* set_values_almost     */ XtInheritSetValuesAlmost,
407 	/* get_values_hook       */ NULL,
408 	/* accept_focus          */ NULL,
409 	/* version               */ XtVersionDontCheck,
410 	/* callback offsets      */ NULL,
411 	/* tm_table              */ NULL,
412 	/* query_geometry        */ XtInheritQueryGeometry,
413 	/* display_accelerator   */ NULL,
414 	/* extension             */ (XtPointer)&_XmToggleBGRectClassExtRec
415     },
416     /* XmGadget part */
417     {
418 	/* border_highlight   */ XmInheritBorderHighlight,  /* FIX ME */
419 	/* border_unhighlight */ XmInheritBorderUnhighlight, /* FIX ME */
420 	/* arm_and_activate   */ ArmAndActivate,
421 	/* input_dispatch     */ input_dispatch,
422 	/* visual_change      */ NULL, /* FIX ME */
423 	/* syn_resources      */ syn_resources,
424 	/* num_syn_resources  */ 0,
425 	/* cache_part         */ &cache_part,
426 	/* extension          */ (XtPointer)&_XmToggleBGadgetClassExtRec
427     },
428     /* XmLabelGadget part */
429     {
430 	/* setOverrideCallback */ XmInheritSetOverrideCallback,
431 	/* menuProcs           */ XmInheritMenuProc,
432 	/* extension           */ NULL
433     },
434     /* XmToggleButtonGadget part */
435     {
436 	/* extension */ NULL
437     },
438 };
439 
440 
441 WidgetClass xmToggleButtonGadgetClass = (WidgetClass)&xmToggleButtonGadgetClassRec;
442 
443 /*
444  *  Some #defines to make the code below more readable
445  */
446 
447 #define IN_MENU(w) (LabG_MenuType(w) == XmMENU_POPUP || \
448 		    LabG_MenuType(w) == XmMENU_PULLDOWN)
449 
450 /******************************* CACHE PART *********************************/
451 static void
secondary_object_create(Widget request,Widget new_w,ArgList args,Cardinal * num_args)452 secondary_object_create(Widget request,
453 			Widget new_w,
454 			ArgList args,
455 			Cardinal *num_args)
456 {
457     XmBaseClassExt *bce;
458     XtPointer nsec, rsec;
459     XmWidgetExtData ed;
460     Cardinal size;
461 
462     DEBUGOUT(_LtDebug(__FILE__, new_w,
463 		      "ToggleButtonGCacheRec %s being initialized.\n",
464 		      XtName(new_w)));
465 
466     bce = _XmGetBaseClassExtPtr(XtClass(new_w), XmQmotif);
467 
468     size = (*bce)->secondaryObjectClass->core_class.widget_size;
469     nsec = _XmExtObjAlloc(size);
470     rsec = _XmExtObjAlloc(size);
471 
472     ((XmExtRec *)nsec)->object.self = (Widget)nsec;
473     ((XmExtRec *)nsec)->object.widget_class = (*bce)->secondaryObjectClass;
474     ((XmExtRec *)nsec)->object.parent = XtParent(new_w);
475     ((XmExtRec *)nsec)->object.xrm_name = new_w->core.xrm_name;
476     ((XmExtRec *)nsec)->object.being_destroyed = False;
477     ((XmExtRec *)nsec)->object.destroy_callbacks = NULL;
478     ((XmExtRec *)nsec)->object.constraints = NULL;
479 
480     ExtObj_LogicalParent(nsec) = new_w;
481     ExtObj_ExtensionType(nsec) = XmCACHE_EXTENSION;
482 
483     XtGetSubresources(new_w, nsec, NULL, NULL,
484 		      (*bce)->secondaryObjectClass->core_class.resources,
485 		      (*bce)->secondaryObjectClass->core_class.num_resources,
486 		      args, *num_args);
487 
488     ed = (XmWidgetExtData)XtMalloc(sizeof(XmWidgetExtDataRec));
489     ed->widget = (Widget)nsec;
490     ed->reqWidget = (Widget)rsec;
491 
492     memcpy(rsec, nsec, size);
493     ((XmExtRec *)rsec)->object.self = (Widget)rsec;
494 
495     _XmPushWidgetExtData(new_w, ed, XmCACHE_EXTENSION);
496 
497     LabG_Cache(new_w) = &(((XmLabelGCacheObject)nsec)->label_cache);
498     LabG_Cache(request) = &(((XmLabelGCacheObject)rsec)->label_cache);
499 
500     TBG_Cache(new_w) = &(((XmToggleButtonGCacheObject)nsec)->toggle_cache);
501     TBG_Cache(request) = &(((XmToggleButtonGCacheObject)rsec)->toggle_cache);
502 }
503 
504 int
_XmToggleBCacheCompare(XtPointer A,XtPointer B)505 _XmToggleBCacheCompare(XtPointer A, XtPointer B)
506 {
507     return !memcmp(((XmToggleButtonGCacheObjPart *)A),
508 		 ((XmToggleButtonGCacheObjPart *)B),
509 		 sizeof(XmToggleButtonGCacheObjPart));
510 }
511 
512 /******************************* CACHE PART *********************************/
513 static void
class_initialize(void)514 class_initialize(void)
515 {
516     XtResourceList combined, labels;
517     int ncom;
518     Cardinal nlabels;
519 
520     /* don't let the nulls fool you.  look at the header file -- the arg
521      * isn't used. */
522     ClassCacheHead(TBG_ClassCachePart(NULL)).prev =
523 	&ClassCacheHead(TBG_ClassCachePart(NULL));
524     ClassCacheHead(TBG_ClassCachePart(NULL)).next =
525 	&ClassCacheHead(TBG_ClassCachePart(NULL));
526 
527     _XmToggleBGRectClassExtRec.record_type = XmQmotif;
528 
529     /*
530      * Label subclasses (ToggleBG, PushBG, CascadeBG) have a problem.  Since
531      * we do all the subpart manipulation in the pre- and post- hooks, and
532      * since those hooks aren't chained, we have to either make multiple
533      * calls to XtGetSubresources/Xt[Get|Set]Subvalues, or merge the resource
534      * lists.  Since I just wrote _XmTransformSubresources, seems like a
535      * waste not to use it.
536      */
537     ncom = XtNumber(cache_resources) +
538 	xmLabelGCacheObjClassRec.object_class.num_resources;
539 
540     _XmTransformSubResources(xmLabelGCacheObjClassRec.object_class.resources,
541 			   xmLabelGCacheObjClassRec.object_class.num_resources,
542 			     &labels, &nlabels);
543 
544     combined = (XtResourceList)XtMalloc(sizeof(XtResource) * ncom);
545     memcpy(combined, labels, nlabels * sizeof(XtResource));
546     memcpy(&combined[nlabels],
547            cache_resources,
548 	   XtNumber(cache_resources) * sizeof(XtResource));
549     XtFree((char *)labels);
550 
551     xmToggleButtonGCacheObjClassRec.object_class.resources = combined;
552     xmToggleButtonGCacheObjClassRec.object_class.num_resources = ncom;
553 }
554 
555 static void
class_part_initialize(WidgetClass widget_class)556 class_part_initialize(WidgetClass widget_class)
557 {
558     _XmFastSubclassInit(widget_class, XmTOGGLE_BUTTON_GADGET_BIT);
559 }
560 
561 static void
CreateSelectGC(Widget w)562 CreateSelectGC(Widget w)
563 {
564     XGCValues values;
565     XtGCMask mask;
566 
567     mask = GCForeground | GCBackground | GCFillStyle | GCFunction |
568 	GCSubwindowMode | GCGraphicsExposures | GCPlaneMask;
569 
570     if (TBG_VisualSet(w) == XmINDETERMINATE)
571     {
572 	mask |= GCStipple | GCTileStipXOrigin | GCTileStipYOrigin;
573 	values.fill_style = FillOpaqueStippled;
574 	values.ts_x_origin = values.ts_y_origin = 0;
575 	values.stipple =
576 	    XmGetPixmapByDepth(XtScreen(w), "50_foreground", 1, 0, 1);
577     } else {
578 	values.fill_style = FillSolid;
579     }
580     values.function = GXcopy;
581     values.plane_mask = -1;
582     values.subwindow_mode = ClipByChildren;
583     values.graphics_exposures = False;
584     values.foreground = TBG_SelectColor(w);
585     values.background = XmParentBackground(w);
586 
587     TBG_SelectGC(w) = XtGetGC(w, mask, &values);
588 
589     values.foreground = TBG_UnselectColor(w);
590 
591     DEBUGOUT(_LtDebug(__FILE__, w, "CreateSelectGC: unselect color %p\n",
592 	TBG_UnselectColor(w)));
593 
594     TBG_UnselectGC(w) = XtGetGC(w, mask, &values);
595 }
596 
597 static void
CreateBackgroundGC(Widget w)598 CreateBackgroundGC(Widget w)
599 {
600     XGCValues values;
601     XtGCMask mask;
602 
603     mask = GCForeground | GCBackground | GCFillStyle | GCFunction |
604 	GCSubwindowMode | GCGraphicsExposures | GCPlaneMask;
605 
606     values.fill_style = FillSolid;
607     values.function = GXcopy;
608     values.plane_mask = -1;
609     values.subwindow_mode = ClipByChildren;
610     values.graphics_exposures = False;
611     values.foreground = XmParentBackground(w);
612     values.background = XmParentForeground(w);
613 
614     TBG_BackgroundGC(w) = XtGetGC(w, mask, &values);
615 }
616 
617 static void
initialize_posthook(Widget request,Widget new_w,ArgList args,Cardinal * num_args)618 initialize_posthook(Widget request, Widget new_w,
619 		    ArgList args, Cardinal *num_args)
620 {
621     XmWidgetExtData ext;
622 
623     DEBUGOUT(_LtDebug(__FILE__, new_w, "ToggleBG InitializePosthook\n"));
624 
625     /* don't let the null fool you */
626     LabG_Cache(new_w) = (XmLabelGCacheObjPart *)
627 	_XmCachePart(LabG_ClassCachePart(NULL),
628 		     (XtPointer)LabG_Cache(new_w),
629 		     sizeof(XmLabelGCacheObjPart));
630     TBG_Cache(new_w) = (XmToggleButtonGCacheObjPart *)
631 	_XmCachePart(TBG_ClassCachePart(NULL),
632 		     (XtPointer)TBG_Cache(new_w),
633 		     sizeof(XmToggleButtonGCacheObjPart));
634 
635     _XmPopWidgetExtData(new_w, &ext, XmCACHE_EXTENSION);
636     _XmExtObjFree((XtPointer)ext->widget);
637     _XmExtObjFree((XtPointer)ext->reqWidget);
638     XtFree((char *)ext);
639 }
640 
641 static void
initialize(Widget request,Widget new_w,ArgList args,Cardinal * num_args)642 initialize(Widget request, Widget new_w,
643 	   ArgList args, Cardinal *num_args)
644 {
645     if (!XtIsSubclass(XtParent(new_w), xmManagerWidgetClass))
646     {
647 	_XmError(new_w, "parent should be manager.");
648     }
649 
650     TBG_Armed(new_w) = False;
651 
652     TBG_VisualSet(new_w) = TBG_Set(new_w);
653 
654     /* Fix up the pixmaps */
655     if (LabG_Pixmap(new_w) == XmUNSPECIFIED_PIXMAP &&
656 	TBG_OnPixmap(new_w) != XmUNSPECIFIED_PIXMAP)
657 	LabG_Pixmap(new_w) = TBG_OnPixmap(new_w);
658 
659     if (LabG_PixmapInsensitive(new_w) == XmUNSPECIFIED_PIXMAP &&
660 	TBG_InsenPixmap(new_w) != XmUNSPECIFIED_PIXMAP)
661 	LabG_PixmapInsensitive(new_w) = TBG_InsenPixmap(new_w);
662 
663     if (LabG_IsPixmap(new_w) &&
664 	(TBG_IndeterminatePixmap(new_w) != XmUNSPECIFIED_PIXMAP ||
665 	 ((XtSensitive(new_w)
666 	   ? TBG_OnPixmap(new_w)
667 	   : TBG_InsenPixmap(new_w))
668 	  != XmUNSPECIFIED_PIXMAP)))
669     {
670 	Dimension width, height;
671 	Dimension iwidth, iheight;
672 
673 	_XmLabelGetPixmapSize(new_w,
674 			      (XtSensitive(new_w)
675 			       ? TBG_OnPixmap(new_w)
676 			       : TBG_InsenPixmap(new_w)),
677 			      &width, &height);
678 
679 	_XmLabelGetPixmapSize(new_w, TBG_IndeterminatePixmap(new_w),
680 			      &iwidth, &iheight);
681 	if (width < iwidth)
682 	    width = iwidth;
683 	if (height < iheight)
684 	    height = iheight;
685 
686 	if (LabG_TextRect_width(new_w) < width ||
687 	    LabG_TextRect_height(new_w) < height)
688 	{
689 	    if (LabG_TextRect_width(new_w) < width)
690 		LabG_TextRect_width(new_w) = width;
691 	    if (LabG_TextRect_height(new_w) < height)
692 		LabG_TextRect_height(new_w) = height;
693 	    if (!XtWidth(request) || !XtHeight(request))
694 	    {
695 		if (!XtWidth(request))
696 		    XtWidth(new_w) = 0;
697 		if (!XtHeight(request))
698 		    XtHeight(new_w) = 0;
699 		xmToggleButtonGadgetClassRec.rect_class.resize(new_w);
700 	    }
701 	}
702     }
703 
704     if (TBG_IndicatorDim(new_w) == XmINVALID_DIMENSION)
705     {
706 	TBG_IndicatorSet(new_w) = LabG_IsPixmap(new_w);
707 	TBG_IndicatorDim(new_w) = implicit_indicator(new_w);
708     }
709     else
710     {
711 	TBG_IndicatorSet(new_w) = True;
712     }
713 
714     CreateSelectGC(new_w);
715     CreateBackgroundGC(new_w);
716 
717     if (!XmRepTypeValidValue(XmRepTypeGetId(XmRToggleMode),
718 			     TBG_ToggleMode(new_w), new_w))
719 	TBG_ToggleMode(new_w) = XmTOGGLE_BOOLEAN;
720 
721     if (TBG_IndType(new_w) == (unsigned char)XmUNSPECIFIED ||
722 	!XmRepTypeValidValue(XmRepTypeGetId(XmRIndicatorType),
723 			     TBG_IndType(new_w), new_w))
724     {
725 	TBG_IndType(new_w) =
726 	    XmIsRowColumn(XtParent(new_w)) && RC_RadioBehavior(XtParent(new_w))
727 	    ? XmONE_OF_MANY
728 	    : XmN_OF_MANY;
729     }
730 
731     if (TBG_Visible(new_w) == UNSPECIFIED_TBG_BOOLEAN)
732 	TBG_Visible(new_w) = !IN_MENU(new_w);
733 
734     if (TBG_FillOnSelect(new_w) == UNSPECIFIED_TBG_BOOLEAN)
735 	TBG_FillOnSelect(new_w) = (TBG_IndType(new_w) == XmN_OF_MANY
736 				   ? TBG_IndOn(new_w) & INDICATOR_BOX_MASK
737 				   : TBG_IndOn(new_w)) != 0;
738 
739     if (TBG_IndOn(new_w))
740     {
741 	int margin;
742 
743 	/* Make sure there's enough room on the side for the indicator */
744 	margin = (TBG_IndicatorDim(new_w) + TBG_Spacing(new_w))
745 	    - (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R
746 	       ? LabG_MarginLeft(new_w) : LabG_MarginRight(new_w));
747 	if (margin > 0)
748 	{
749 	    if (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R)
750 	    {
751 		LabG_MarginLeft(new_w) += margin;
752 		LabG_TextRect_x(new_w) += margin;
753 		LabG_AccTextRect(new_w).x += margin;
754 	    }
755 	    else
756 		LabG_MarginRight(new_w) += margin;
757 	    if (!XtWidth(request))
758 		XtWidth(new_w) += margin;
759 	}
760 
761 	/* Make sure there's enough room vertically.
762 	 * Non-menu toggles want some padding space.
763 	 */
764 	margin = TBG_IndicatorDim(new_w) - (LabG_TextRect_height(new_w)
765 					    + LabG_MarginTop(new_w)
766 					    + LabG_MarginBottom(new_w));
767 #ifdef LESS_VERTICAL_PADDING
768 	margin -= LabG_MarginHeight(new_w) << 1;
769 #else
770 	if (!IN_MENU(new_w))
771 	    margin += (LabG_Shadow(new_w) + Xm3D_ENHANCE_PIXEL) << 1;
772 #endif
773 	if (margin > 0)
774 	{
775 	    LabG_MarginTop(new_w) += margin >> 1;
776 	    LabG_MarginBottom(new_w) += margin >> 1;
777 	    if (!XtHeight(request))
778 	    {
779 		LabG_TextRect_y(new_w) += margin >> 1;
780 		LabG_AccTextRect(new_w).y += margin >> 1;
781 		XtHeight(new_w) += margin;
782 	    }
783 	}
784     }
785 
786     if (IN_MENU(new_w))
787     {
788 	LabG_Highlight(new_w) = 0;
789 	if (LabG_Shadow(new_w) == 0)
790 	    LabG_Shadow(new_w) = 2;
791 	LabGClass_MenuProcs(XtClass(new_w)) = MenuProcEntry;
792     }
793 
794     G_EventMask(new_w) = XmARM_EVENT | XmACTIVATE_EVENT | XmENTER_EVENT |
795 	XmLEAVE_EVENT | XmMOTION_EVENT | XmFOCUS_IN_EVENT |
796 	XmFOCUS_OUT_EVENT | XmMULTI_ARM_EVENT | XmMULTI_ACTIVATE_EVENT |
797 	XmHELP_EVENT | XmBDRAG_EVENT;
798 }
799 
800 static void
destroy(Widget w)801 destroy(Widget w)
802 {
803     XtReleaseGC(w, TBG_SelectGC(w));
804     XtReleaseGC(w, TBG_BackgroundGC(w));
805     XtReleaseGC(w, TBG_UnselectGC(w));
806 
807     _XmCacheDelete((XtPointer)TBG_Cache(w));
808 }
809 
810 static Boolean
set_values_prehook(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)811 set_values_prehook(Widget old, Widget request, Widget new_w,
812 		   ArgList args, Cardinal *num_args)
813 {
814     XmBaseClassExt *bce;
815     XmWidgetExtData ed;
816     Cardinal size;
817     XtPointer nsec, rsec;
818 
819     bce = _XmGetBaseClassExtPtr(XtClass(new_w), XmQmotif);
820     size = (*bce)->secondaryObjectClass->core_class.widget_size;
821 
822     nsec = _XmExtObjAlloc(size);
823     rsec = _XmExtObjAlloc(size);
824 
825     ((XmExtRec *)nsec)->object.self = (Widget)nsec;
826     ((XmExtRec *)nsec)->object.widget_class = (*bce)->secondaryObjectClass;
827     ((XmExtRec *)nsec)->object.parent = XtParent(new_w);
828     ((XmExtRec *)nsec)->object.xrm_name = new_w->core.xrm_name;
829     ((XmExtRec *)nsec)->object.being_destroyed = False;
830     ((XmExtRec *)nsec)->object.constraints = NULL;
831 
832     ExtObj_LogicalParent(nsec) = new_w;
833     ExtObj_ExtensionType(nsec) = XmCACHE_EXTENSION;
834 
835     memcpy(&((XmLabelGCacheObject)nsec)->label_cache,
836            LabG_Cache(new_w),
837 	   sizeof(XmLabelGCacheObjPart));
838     memcpy(&((XmToggleButtonGCacheObject)nsec)->toggle_cache,
839            TBG_Cache(new_w),
840 	   sizeof(XmToggleButtonGCacheObjPart));
841 
842     ed = (XmWidgetExtData)XtMalloc(sizeof(XmWidgetExtDataRec));
843     ed->widget = (Widget)nsec;
844     ed->reqWidget = (Widget)rsec;
845 
846     _XmPushWidgetExtData(new_w, ed, XmCACHE_EXTENSION);
847 
848     _XmGadgetImportSecondaryArgs(new_w, args, num_args);
849 
850     XtSetSubvalues((XtPointer)nsec,
851 		   (*bce)->secondaryObjectClass->core_class.resources,
852 		   (*bce)->secondaryObjectClass->core_class.num_resources,
853 		   args, *num_args);
854 
855     memcpy(rsec, nsec, size);
856 
857     LabG_Cache(new_w) = &(((XmToggleButtonGCacheObject)nsec)->label_cache);
858     LabG_Cache(request) = &(((XmToggleButtonGCacheObject)rsec)->label_cache);
859     TBG_Cache(new_w) = &(((XmToggleButtonGCacheObject)nsec)->toggle_cache);
860     TBG_Cache(request) = &(((XmToggleButtonGCacheObject)rsec)->toggle_cache);
861 
862     _XmExtImportArgs((Widget)nsec, args, num_args);
863 
864     return False;
865 }
866 
867 static Boolean
set_values_posthook(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)868 set_values_posthook(Widget old, Widget request, Widget new_w,
869 		    ArgList args, Cardinal *num_args)
870 {
871     XmWidgetExtData ext;
872 
873     if (!_XmLabelCacheCompare((XtPointer)LabG_Cache(new_w),
874 			      (XtPointer)LabG_Cache(old)))
875     {
876 
877 	_XmCacheDelete((XtPointer)LabG_Cache(old));
878 
879 	LabG_Cache(new_w) = (XmLabelGCacheObjPart *)
880 	    _XmCachePart(LabG_ClassCachePart(NULL),
881 			 (XtPointer)LabG_Cache(new_w),
882 			 sizeof(XmLabelGCacheObjPart));
883     }
884     else
885     {
886 	LabG_Cache(new_w) = LabG_Cache(old);
887     }
888 
889     if (!_XmToggleBCacheCompare((XtPointer)TBG_Cache(new_w),
890 				(XtPointer)TBG_Cache(old)))
891     {
892 
893 	_XmCacheDelete((XtPointer)TBG_Cache(old));
894 
895 	TBG_Cache(new_w) = (XmToggleButtonGCacheObjPart *)
896 	    _XmCachePart(TBG_ClassCachePart(NULL),
897 			 (XtPointer)TBG_Cache(new_w),
898 			 sizeof(XmToggleButtonGCacheObjPart));
899     }
900     else
901     {
902 	TBG_Cache(new_w) = TBG_Cache(old);
903     }
904 
905     _XmPopWidgetExtData(new_w, &ext, XmCACHE_EXTENSION);
906 
907     _XmExtObjFree((XtPointer)ext->widget);
908     _XmExtObjFree((XtPointer)ext->reqWidget);
909 
910     XtFree((char *)ext);
911 
912     return False;
913 }
914 
915 static Boolean
set_values(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)916 set_values(Widget old, Widget request, Widget new_w,
917 	   ArgList args, Cardinal *num_args)
918 {
919 	Boolean		refresh_needed = False;
920 	XGCValues	gcv;
921 
922     DEBUGOUT(_LtDebug(__FILE__, new_w, "ToggleBG set_values\n"));
923 
924     if (TBG_IndType(old) != TBG_IndType(new_w) &&
925 	!XmRepTypeValidValue(XmRepTypeGetId(XmRIndicatorType),
926 			     TBG_IndType(new_w), new_w))
927 	TBG_IndType(new_w) = TBG_IndType(old);
928 
929     if (TBG_ToggleMode(old) != TBG_ToggleMode(new_w) &&
930 	!XmRepTypeValidValue(XmRepTypeGetId(XmRIndicatorType),
931 			     TBG_ToggleMode(new_w), new_w))
932 	TBG_ToggleMode(new_w) = TBG_ToggleMode(old);
933 
934 
935     if (TBG_SelectColor(new_w) != TBG_SelectColor(old))
936     {
937 	XtReleaseGC(new_w, TBG_SelectGC(new_w));
938 	CreateSelectGC(new_w);
939 	refresh_needed = True;
940     }
941 	/* See bug #772755 : need to query the old widget's values */
942 	XGetGCValues(XtDisplayOfObject(old), LabG_NormalGC(old), GCBackground, &gcv);
943 /*
944 	if (XmParentBackground(new_w) != XmParentBackground(old))
945  */
946 	if (XmParentBackground(new_w) != gcv.background) {
947 		XtReleaseGC(new_w, TBG_BackgroundGC(new_w));
948 		CreateBackgroundGC(new_w);
949 		refresh_needed = True;
950 	}
951 
952     /* Changes to the on or off pixmap */
953     if (LabG_Pixmap(new_w) == XmUNSPECIFIED_PIXMAP &&
954 	TBG_OnPixmap(new_w) != XmUNSPECIFIED_PIXMAP)
955     {
956 	LabG_Pixmap(new_w) = TBG_OnPixmap(new_w);
957 
958 	if (LabG_IsPixmap(new_w) && XtSensitive(new_w))
959 	    refresh_needed = True;
960     }
961 
962     if (LabG_PixmapInsensitive(new_w) == XmUNSPECIFIED_PIXMAP &&
963 	TBG_InsenPixmap(new_w) != XmUNSPECIFIED_PIXMAP)
964     {
965 	LabG_PixmapInsensitive(new_w) = TBG_InsenPixmap(new_w);
966 
967 	if (LabG_IsPixmap(new_w) && !XtSensitive(new_w))
968 	    refresh_needed = True;
969     }
970 
971     if (LabG_IsPixmap(new_w) && (LabG_RecomputeSize(new_w) ||
972 	TBG_IndeterminatePixmap(new_w) != XmUNSPECIFIED_PIXMAP ||
973 	(XtSensitive(new_w)
974 	 ? LabG_Pixmap(request) != LabG_Pixmap(old) ||
975 	   TBG_OnPixmap(new_w) != TBG_OnPixmap(old)
976 	 : LabG_PixmapInsensitive(request) != LabG_PixmapInsensitive(old) ||
977 	   TBG_InsenPixmap(new_w) != TBG_InsenPixmap(old))))
978     {
979 	Dimension width, height;
980 	Dimension iwidth, iheight;
981 
982 	_XmLabelGetPixmapSize(new_w,
983 			      (XtSensitive(new_w)
984 			       ? TBG_OnPixmap(new_w)
985 			       : TBG_InsenPixmap(new_w)),
986 			      &width, &height);
987 	_XmLabelGetPixmapSize(new_w, TBG_IndeterminatePixmap(new_w),
988 			      &iwidth, &iheight);
989 	if (width < iwidth)
990 	    width = iwidth;
991 	if (height < iheight)
992 	    height = iheight;
993 
994 	if (LabG_TextRect_width(new_w) < width ||
995 	    LabG_TextRect_height(new_w) < height)
996 	{
997 	    if (LabG_TextRect_width(new_w) < width)
998 		LabG_TextRect_width(new_w) = width;
999 	    if (LabG_TextRect_height(new_w) < height)
1000 		LabG_TextRect_height(new_w) = height;
1001 
1002 	    if (LabG_RecomputeSize(new_w))
1003 	    {
1004 		if (XtWidth(request) == XtWidth(old))
1005 		    XtWidth(new_w) = 0;
1006 		if (XtHeight(request) == XtHeight(old))
1007 		    XtHeight(new_w) = 0;
1008 	    }
1009 	    if (!XtWidth(request) || !XtWidth(new_w) ||
1010 		!XtHeight(request) || !XtHeight(new_w))
1011 	    {
1012 		if (!XtWidth(request))
1013 		    XtWidth(new_w) = 0;
1014 		if (!XtHeight(request))
1015 		    XtHeight(new_w) = 0;
1016 		xmToggleButtonGadgetClassRec.rect_class.resize(new_w);
1017 	    }
1018 
1019 	    width = XtWidth(new_w);
1020 	    height = XtHeight(new_w);
1021 	    XtWidth(new_w) = XtWidth(old);
1022 	    XtHeight(new_w) = XtHeight(old);
1023 	    xmToggleButtonGadgetClassRec.rect_class.resize(new_w);
1024 	    XtWidth(new_w) = width;
1025 	    XtHeight(new_w) = height;
1026 	}
1027     }
1028 
1029     if (TBG_IndicatorDim(new_w) == XmINVALID_DIMENSION)
1030 	TBG_IndicatorSet(new_w) = False;
1031 
1032     if ((!TBG_IndicatorSet(new_w) &&
1033 	 (TBG_IndicatorDim(new_w) == XmINVALID_DIMENSION ||
1034 	  TBG_IndOn(new_w) != TBG_IndOn(old) ||
1035 	  LabG_Label(new_w) != LabG_Label(old) ||
1036 	  LabG_Font(new_w) != LabG_Font(old))) ||
1037 	(TBG_IndicatorDim(new_w) == TBG_IndicatorDim(old)
1038 	 && LabG_IsPixmap(new_w)
1039 	 && LabG_TextRect_height(new_w) != LabG_TextRect_height(old)))
1040     {
1041 	TBG_IndicatorDim(new_w) = implicit_indicator(new_w);
1042     }
1043 
1044     if (LabG_IsPixmap(new_w))
1045 	TBG_IndicatorSet(new_w) = True;
1046 
1047     /* Adjust margins for the indicator size if necessary.
1048      * Margins be increased or decreased; if the margin was explicitly set
1049      * in this call, don't decrease it past that (though it can get bigger).
1050      */
1051     if (TBG_IndOn(new_w) &&
1052 	(TBG_IndicatorDim(new_w) != TBG_IndicatorDim(old)
1053 	 || TBG_Spacing(new_w) != TBG_Spacing(old)
1054 	 || (!IN_MENU(new_w) && LabG_Shadow(new_w) != LabG_Shadow(old))
1055 	 || LabG_StringDirection(new_w) != LabG_StringDirection(old)
1056 	 || (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R
1057 	     ? LabG_MarginLeft(new_w) != LabG_MarginLeft(old)
1058 	     : LabG_MarginRight(new_w) != LabG_MarginRight(old))
1059 	 || LabG_MarginTop(new_w) != LabG_MarginTop(old)
1060 	 || LabG_MarginBottom(new_w) != LabG_MarginBottom(old)))
1061     {
1062 	int margin, tm;
1063 
1064 	margin = TBG_IndicatorDim(new_w) + TBG_Spacing(new_w)
1065 	    - (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R
1066 	       ? LabG_MarginLeft(new_w) : LabG_MarginRight(new_w));
1067 	if (margin && (margin > 0 ||
1068 	    (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R
1069 	     ? LabG_MarginLeft(new_w) == LabG_MarginLeft(old)
1070 	     : LabG_MarginRight(new_w) == LabG_MarginRight(old))))
1071 	{
1072 	    if (LabG_StringDirection(new_w) == XmSTRING_DIRECTION_L_TO_R)
1073 	    {
1074 		LabG_MarginLeft(new_w) += margin;
1075 		LabG_TextRect_x(new_w) += margin;
1076 		LabG_AccTextRect(new_w).x += margin;
1077 	    }
1078 	    else
1079 		LabG_MarginRight(new_w) += margin;
1080 	    if (LabG_RecomputeSize(new_w) || !XtWidth(request))
1081 		XtWidth(new_w) += margin;
1082 	}
1083 
1084 	margin = TBG_IndicatorDim(new_w) - (LabG_TextRect_height(new_w)
1085 					    + LabG_MarginTop(new_w)
1086 					    + LabG_MarginBottom(new_w));
1087 #ifdef LESS_VERTICAL_PADDING
1088 	margin -= LabG_MarginHeight(new_w) << 1;
1089 #else
1090 	if (!IN_MENU(new_w))
1091 	    margin += (LabG_Shadow(new_w) + Xm3D_ENHANCE_PIXEL) << 1;
1092 #endif
1093 	if (margin)
1094 	{
1095 	    margin /= 2;
1096 	    tm = margin;
1097 	    if (tm < (LabG_MarginTop(new_w) == LabG_MarginTop(old)
1098 		      ? XmDEFAULT_TOP_MARGIN - (int)LabG_MarginTop(new_w)
1099 		      : 0))
1100 		tm = (LabG_MarginTop(new_w) == LabG_MarginTop(old)
1101 		      ? XmDEFAULT_TOP_MARGIN - (int)LabG_MarginTop(new_w)
1102 		      : 0);
1103 	    LabG_MarginTop(new_w) += tm;
1104 	    if (LabG_RecomputeSize(new_w) || !XtHeight(request))
1105 		XtHeight(new_w) += tm;
1106 
1107 	    if (margin < (LabG_MarginBottom(new_w) == LabG_MarginBottom(old)
1108 		      ? XmDEFAULT_BOTTOM_MARGIN - (int)LabG_MarginBottom(new_w)
1109 		      : 0))
1110 		margin = (LabG_MarginBottom(new_w) == LabG_MarginBottom(old)
1111 		      ? XmDEFAULT_BOTTOM_MARGIN - (int)LabG_MarginBottom(new_w)
1112 		      : 0);
1113 	    LabG_MarginBottom(new_w) += margin;
1114 	    if (LabG_RecomputeSize(new_w) || !XtHeight(request))
1115 		XtHeight(new_w) += margin;
1116 
1117 	    if (tm != margin)
1118 	    {
1119 		LabG_TextRect_y(new_w) += (tm - margin) / 2;
1120 		LabG_AccTextRect(new_w).y += (tm - margin) / 2;
1121 	    }
1122 	}
1123 
1124 	refresh_needed = True;
1125     }
1126 
1127     if (TBG_IndType(new_w) != TBG_IndType(old)
1128 	|| TBG_DetailShadowThickness(new_w) != TBG_DetailShadowThickness(old)
1129 	|| ((TBG_IndOn(new_w) || TBG_IndOn(old))
1130 	    && (TBG_Visible(new_w) != TBG_Visible(old)
1131 		|| TBG_FillOnSelect(new_w) != TBG_FillOnSelect(old))))
1132     {
1133 	refresh_needed = True;
1134     }
1135 
1136     if (TBG_Set(old) != TBG_Set(new_w))
1137     {
1138 	if (!refresh_needed)
1139 	    draw_toggle(new_w, NULL, NULL, False, TBG_Set(new_w));
1140 	else if ((TBG_Set(old) == XmINDETERMINATE ||
1141 		  TBG_Set(new_w) == XmINDETERMINATE)
1142 		 && TBG_SelectColor(new_w) == TBG_SelectColor(old))
1143 	{
1144 	    XtReleaseGC(new_w, TBG_SelectGC(new_w));
1145 	    CreateSelectGC(new_w);
1146 	}
1147 	TBG_VisualSet(new_w) = TBG_Set(new_w);
1148     }
1149 
1150     return refresh_needed;
1151 }
1152 
1153 static void
get_values_prehook(Widget new_w,ArgList args,Cardinal * num_args)1154 get_values_prehook(Widget new_w, ArgList args, Cardinal *num_args)
1155 {
1156     XmBaseClassExt *bce;
1157     XmWidgetExtData ed;
1158     Cardinal size;
1159     XtPointer nsec;
1160 
1161     bce = _XmGetBaseClassExtPtr(XtClass(new_w), XmQmotif);
1162     size = (*bce)->secondaryObjectClass->core_class.widget_size;
1163 
1164     nsec = _XmExtObjAlloc(size);
1165 
1166     memcpy(&((XmLabelGCacheObject)nsec)->label_cache,
1167            LabG_Cache(new_w),
1168 	   sizeof(XmLabelGCacheObjPart));
1169     memcpy(&((XmToggleButtonGCacheObject)nsec)->toggle_cache,
1170            TBG_Cache(new_w),
1171 	   sizeof(XmToggleButtonGCacheObjPart));
1172 
1173     /*
1174      * don't do this and ResInd will blow up.
1175      */
1176     ((XmExtRec *)nsec)->object.self = (Widget)nsec;
1177     ((XmExtRec *)nsec)->object.widget_class = (*bce)->secondaryObjectClass;
1178     ((XmExtRec *)nsec)->object.parent = XtParent(new_w);
1179     ((XmExtRec *)nsec)->object.xrm_name = new_w->core.xrm_name;
1180     ((XmExtRec *)nsec)->object.being_destroyed = False;
1181     ((XmExtRec *)nsec)->object.destroy_callbacks = NULL;
1182     ((XmExtRec *)nsec)->object.constraints = NULL;
1183 
1184     ExtObj_LogicalParent(nsec) = new_w;
1185     ExtObj_ExtensionType(nsec) = XmCACHE_EXTENSION;
1186 
1187     ed = (XmWidgetExtData)XtMalloc(sizeof(XmWidgetExtDataRec));
1188     ed->widget = (Widget)nsec;
1189 
1190     _XmPushWidgetExtData(new_w, ed, XmCACHE_EXTENSION);
1191 
1192     XtGetSubvalues((XtPointer)nsec,
1193 		   (*bce)->secondaryObjectClass->core_class.resources,
1194 		   (*bce)->secondaryObjectClass->core_class.num_resources,
1195 		   args, *num_args);
1196 
1197     _XmExtGetValuesHook((Widget)nsec, args, num_args);
1198 }
1199 
1200 static void
get_values_posthook(Widget new_w,ArgList args,Cardinal * num_args)1201 get_values_posthook(Widget new_w, ArgList args, Cardinal *num_args)
1202 {
1203     XmWidgetExtData ext;
1204 
1205     _XmPopWidgetExtData(new_w, &ext, XmCACHE_EXTENSION);
1206 
1207     _XmExtObjFree((XtPointer)ext->widget);
1208 
1209     XtFree((char *)ext);
1210 }
1211 
1212 static void
resize(Widget w)1213 resize(Widget w)
1214 {
1215     Position x;
1216 
1217     xmLabelGadgetClassRec.rect_class.resize(w);
1218 
1219     /* Make sure the label and toggle don't overlap */
1220 
1221     if (TBG_IndOn(w))
1222     {
1223 	if (LabG_StringDirection(w) == XmSTRING_DIRECTION_L_TO_R)
1224 	{
1225 	    x = LabG_Highlight(w) + LabG_Shadow(w) + LabG_MarginWidth(w)
1226 		+ TBG_IndicatorDim(w) + TBG_Spacing(w);
1227 	    if (LabG_TextRect_x(w) < x)
1228 	    {
1229 		LabG_AccTextRect(w).x += x - LabG_TextRect_x(w);
1230 		LabG_TextRect_x(w) = x;
1231 	    }
1232 	}
1233 	else
1234 	{
1235 	    x = XtWidth(w) - LabG_Highlight(w) - LabG_Shadow(w)
1236 		- LabG_MarginWidth(w) - TBG_IndicatorDim(w) - TBG_Spacing(w)
1237 		- LabG_TextRect_width(w);
1238 	    if (LabG_TextRect_x(w) > x)
1239 	    {
1240 		LabG_AccTextRect(w).x -= LabG_TextRect_x(w) - x;
1241 		LabG_TextRect_x(w) = x;
1242 	    }
1243 	}
1244     }
1245 }
1246 
1247 static void
expose(Widget w,XEvent * event,Region region)1248 expose(Widget w, XEvent *event, Region region)
1249 {
1250     DEBUGOUT(_LtDebug(__FILE__, w, "ToggleBG Expose\n"));
1251     draw_toggle(w, event, region, True, 0);
1252 }
1253 
1254 static Cardinal
get_sec_res_data(WidgetClass wc,XmSecondaryResourceData ** data)1255 get_sec_res_data(WidgetClass wc, XmSecondaryResourceData **data)
1256 {
1257     /* FIX ME */
1258 
1259     return _XmSecondaryResourceData(&_XmToggleBGRectClassExtRec,
1260 				    data, NULL, NULL, NULL, NULL);
1261 }
1262 
1263 static void
Arm(Widget w,XEvent * event,String * params,Cardinal * num_params)1264 Arm(Widget w, XEvent *event, String *params, Cardinal *num_params)
1265 {
1266     XmToggleButtonCallbackStruct cbs;
1267 
1268     if (!TBG_Armed(w))
1269     {
1270 	TBG_Armed(w) = True;
1271 	MGR_ActiveChild(XtParent(w)) = w;
1272 
1273 	if (TBG_ArmCallback(w))
1274 	{
1275 	    cbs.reason = XmCR_ARM;
1276 	    cbs.event = event;
1277 	    cbs.set = TBG_Set(w);
1278 
1279 	    XFlush(XtDisplay(w));
1280 	    XtCallCallbackList(w, TBG_ArmCallback(w), (XtPointer)&cbs);
1281 	}
1282     }
1283     draw_toggle(w, NULL, NULL, False, NEXT_TOGGLE(w));
1284 }
1285 
1286 static void
Select(Widget w,XEvent * event,String * params,Cardinal * num_params)1287 Select(Widget w, XEvent *event, String *params, Cardinal *num_params)
1288 {
1289     XmToggleButtonCallbackStruct cbs;
1290     XButtonEvent *ev = (XButtonEvent *)event;
1291 
1292     if (TBG_Armed(w) &&
1293 	(ev->type == KeyPress || ev->type == KeyRelease ||
1294 	 ((ev->x >= XtX(w) && ev->x < XtX(w) + XtWidth(w)) &&
1295 	  (ev->y >= XtY(w) && ev->y < XtY(w) + XtHeight(w)))))
1296     {
1297 	TBG_Armed(w) = False;
1298 
1299 	TBG_Set(w) = TBG_VisualSet(w);
1300 
1301 	if (XtIsRealized(w))
1302 	    XtClass(w)->core_class.expose(w, event, NULL);
1303 
1304 	cbs.reason = XmCR_VALUE_CHANGED;
1305 	cbs.event = event;
1306 	cbs.set = TBG_Set(w);
1307 	if (XmIsRowColumn(XtParent(w)))
1308 	{
1309 	    RC_MenuMenuCallback(w, &cbs);
1310 	}
1311 	/* Menu callback might cancel the set (radioAlwaysOne). */
1312 	cbs.set = TBG_Set(w);
1313 	if (!LabG_SkipCallback(w) && TBG_ValueChangedCallback(w))
1314 	{
1315 	    XFlush(XtDisplay(w));
1316 	    XtCallCallbackList(w,
1317 			       TBG_ValueChangedCallback(w),
1318 			       (XtPointer)&cbs);
1319 	}
1320     }
1321 }
1322 
1323 
1324 static void
Disarm(Widget w,XEvent * event,String * params,Cardinal * num_params)1325 Disarm(Widget w, XEvent *event, String *params, Cardinal *num_params)
1326 {
1327     XmToggleButtonCallbackStruct cbs;
1328 
1329     if (XtIsRealized(w))
1330 	_XmClearBorder(XtDisplay(w), XtWindow(w),
1331 		       XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1332 		       LabG_Shadow(w));
1333 
1334     if (TBG_Armed(w))
1335 	TBG_Armed(w) = False;
1336 
1337     if (TBG_DisarmCallback(w))
1338     {
1339 	cbs.reason = XmCR_DISARM;
1340 	cbs.event = event;
1341 	cbs.set = TBG_Set(w);
1342 
1343 	XFlush(XtDisplay(w));
1344 	XtCallCallbackList(w, TBG_DisarmCallback(w), (XtPointer)&cbs);
1345     }
1346 
1347     draw_toggle(w, NULL, NULL, False, TBG_Set(w));
1348 }
1349 
1350 static void
ArmAndActivate(Widget w,XEvent * event,String * params,Cardinal * num_params)1351 ArmAndActivate(Widget w, XEvent *event, String *params, Cardinal *num_params)
1352 {
1353     Boolean poppedUp;
1354 
1355     Arm(w, event, params, num_params);
1356 
1357     if (IN_MENU(w))
1358     {
1359 	RC_MenuButtonPopdown(w, event, &poppedUp);
1360     }
1361 
1362     Select(w, event, params, num_params);
1363     Disarm(w, event, params, num_params);
1364 }
1365 
1366 static void
ButtonUp(Widget w,XEvent * event,String * params,Cardinal * num_params)1367 ButtonUp(Widget w, XEvent *event, String *params, Cardinal *num_params)
1368 {
1369     Boolean validButton, poppedUp;
1370     XmToggleButtonCallbackStruct cbs;
1371 
1372     XAllowEvents(XtDisplayOfObject(w), SyncPointer, CurrentTime);
1373 
1374     if (event && (event->type == ButtonRelease))
1375     {
1376 	RC_MenuButton(w, event, &validButton);
1377     }
1378     else
1379     {
1380 	validButton = False;
1381     }
1382 
1383     if (!validButton)
1384     {
1385 	return;
1386     }
1387 
1388     if (!TBG_Armed(w))
1389     {
1390 	return;
1391     }
1392 
1393     RC_MenuButtonPopdown(w, event, &poppedUp);
1394 
1395     _XmRecordEvent(event);
1396 
1397     TBG_Armed(w) = False;
1398 
1399     if (XtIsRealized(w))
1400 	_XmClearBorder(XtDisplay(w), XtWindow(w),
1401 		       XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1402 		       LabG_Shadow(w));
1403 
1404     TBG_Set(w) = NEXT_TOGGLE(w);
1405     draw_toggle(w, NULL, NULL, False, TBG_Set(w));
1406 
1407     cbs.reason = XmCR_VALUE_CHANGED;
1408     cbs.event = event;
1409     cbs.set = TBG_Set(w);
1410     if (XmIsRowColumn(XtParent(w)))
1411     {
1412 	RC_MenuMenuCallback(w, &cbs);
1413     }
1414     if (!LabG_SkipCallback(w) && TBG_ValueChangedCallback(w))
1415     {
1416 	XFlush(XtDisplay(w));
1417 	XtCallCallbackList(w, TBG_ValueChangedCallback(w), (XtPointer)&cbs);
1418     }
1419     if (TBG_DisarmCallback(w))
1420     {
1421 	cbs.reason = XmCR_DISARM;
1422 	cbs.event = event;
1423 	cbs.set = TBG_Set(w);
1424 
1425 	XFlush(XtDisplay(w));
1426 	XtCallCallbackList(w, TBG_DisarmCallback(w), (XtPointer)&cbs);
1427     }
1428 
1429     _XmSetInDragMode(w, False);
1430 }
1431 
1432 
1433 static void
ButtonDown(Widget w,XEvent * event,String * params,Cardinal * num_params)1434 ButtonDown(Widget w, XEvent *event, String *params, Cardinal *num_params)
1435 {
1436     int validButton;
1437     XmToggleButtonCallbackStruct cbs;
1438 
1439     XAllowEvents(XtDisplayOfObject(w), SyncPointer, CurrentTime);
1440 
1441     if (event && (event->type == ButtonPress))
1442     {
1443 	RC_MenuButton(w, event, &validButton);
1444 	if (!validButton)
1445 	    return;
1446     }
1447 
1448     _XmSetInDragMode(w, True);
1449 
1450     {
1451 	Boolean poppedUp;
1452 
1453 	RC_MenuShellPopdown(w, event, &poppedUp);
1454     }
1455     {
1456 	Cardinal i;
1457 	Widget menu = XtParent(w);
1458 
1459 	for (i = 0; i < MGR_NumChildren(menu); i++)
1460 	{
1461 	    Widget w1 = MGR_Children(menu)[i];
1462 
1463 	    if (w1 && (w1 != w))
1464 	    {
1465 		_XmMenuDisarmItem(w1);
1466 	    }
1467 	}
1468     }
1469 
1470     if (!TBG_Armed(w))
1471     {
1472 	TBG_Armed(w) = True;
1473 
1474 	if (XtIsRealized(w))
1475 	    _XmDrawShadows(XtDisplay(w), XtWindow(w),
1476 			   XmParentTopShadowGC(w), XmParentBottomShadowGC(w),
1477 			   XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1478 			   LabG_Shadow(w), XmSHADOW_OUT);
1479 
1480 	if (TBG_ArmCallback(w))
1481 	{
1482 	    cbs.reason = XmCR_ARM;
1483 	    cbs.event = event;
1484 	    cbs.set = TBG_Set(w);
1485 
1486 	    XFlush(XtDisplay(w));
1487 	    XtCallCallbackList(w, TBG_ArmCallback(w), (XtPointer)&cbs);
1488 	}
1489     }
1490 
1491     _XmRecordEvent(event);
1492 }
1493 
1494 static void
Help(Widget w,XEvent * event,String * params,Cardinal * num_params)1495 Help(Widget w, XEvent *event, String *params, Cardinal *num_params)
1496 {
1497     Widget cur = w;
1498     XmAnyCallbackStruct cbs;
1499 
1500     cbs.reason = XmCR_HELP;
1501     cbs.event = event;
1502 
1503     while (cur != NULL)
1504     {
1505 	if (XtHasCallbacks(w, XmNhelpCallback) == XtCallbackHasSome)
1506 	{
1507 	    XtCallCallbacks(w, XmNhelpCallback, (XtPointer)&cbs);
1508 	    return;
1509 	}
1510 	cur = XtParent(cur);
1511     }
1512 }
1513 
1514 static void
EnterWindow(Widget w,XEvent * event,String * params,Cardinal * num_params)1515 EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
1516 {
1517     XmToggleButtonCallbackStruct cbs;
1518 
1519     if (!IN_MENU(w))
1520     {
1521 	_XmEnterGadget(w, event, NULL, NULL);
1522 	if (TBG_Armed(w))
1523 	    draw_toggle(w, NULL, NULL, False, NEXT_TOGGLE(w));
1524     }
1525     else
1526     {
1527 	if (_XmGetInDragMode(w))
1528 	{
1529 	    Boolean poppedUp;
1530 
1531 	    RC_MenuShellPopdown(w, event, &poppedUp);
1532 
1533 	    TBG_Armed(w) = True;
1534 
1535 	    if (XtIsRealized(w))
1536 		_XmDrawShadows(XtDisplay(w), XtWindow(w),
1537 			       XmParentTopShadowGC(w),
1538 			       XmParentBottomShadowGC(w),
1539 			       XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1540 			       LabG_Shadow(w), XmSHADOW_OUT);
1541 
1542 	    if (TBG_ArmCallback(w))
1543 	    {
1544 		cbs.reason = XmCR_ARM;
1545 		cbs.event = event;
1546 		cbs.set = TBG_Set(w);
1547 
1548 		XFlush(XtDisplay(w));
1549 		XtCallCallbackList(w, TBG_ArmCallback(w), (XtPointer)&cbs);
1550 	    }
1551 	}
1552     }
1553 }
1554 
1555 static void
LeaveWindow(Widget w,XEvent * event,String * params,Cardinal * num_params)1556 LeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
1557 {
1558     XmToggleButtonCallbackStruct cbs;
1559 
1560     if (!IN_MENU(w))
1561     {
1562 	_XmLeaveGadget(w, event, NULL, NULL);
1563 	if (TBG_Armed(w))
1564 	    draw_toggle(w, NULL, NULL, False, TBG_Set(w));
1565     }
1566     else
1567     {
1568 	if (_XmGetInDragMode(w))
1569 	{
1570 	    TBG_Armed(w) = False;
1571 
1572 	    if (XtIsRealized(w))
1573 		_XmClearBorder(XtDisplay(w), XtWindow(w),
1574 			       XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1575 			       LabG_Shadow(w));
1576 
1577 	    if (TBG_DisarmCallback(w))
1578 	    {
1579 		cbs.reason = XmCR_DISARM;
1580 		cbs.event = event;
1581 		cbs.set = TBG_Set(w);
1582 
1583 		XFlush(XtDisplay(w));
1584 		XtCallCallbackList(w, TBG_DisarmCallback(w), (XtPointer)&cbs);
1585 	    }
1586 	}
1587     }
1588 }
1589 
1590 static void
input_dispatch(Widget gadget,XEvent * event,Mask event_mask)1591 input_dispatch(Widget gadget, XEvent *event, Mask event_mask)
1592 {
1593     Cardinal num_params = 0;
1594 
1595     switch (event_mask)
1596     {
1597     case XmARM_EVENT:
1598     case XmMULTI_ARM_EVENT:
1599 	DEBUGOUT(_LtDebug(__FILE__, gadget,
1600 			  "ToggleButtonGadget got arm event\n"));
1601 	if (IN_MENU(gadget))
1602 	{
1603 	    ButtonDown(gadget, event, NULL, &num_params);
1604 	}
1605 	else
1606 	{
1607 	    Arm(gadget, event, NULL, &num_params);
1608 	}
1609 	break;
1610 
1611     case XmACTIVATE_EVENT:
1612     case XmMULTI_ACTIVATE_EVENT:
1613 	DEBUGOUT(_LtDebug(__FILE__, gadget,
1614 			  "ToggleButtonGadget got activate event\n"));
1615 	if (IN_MENU(gadget))
1616 	{
1617 	    ButtonUp(gadget, event, NULL, &num_params);
1618 	}
1619 	else
1620 	{
1621 	    Select(gadget, event, NULL, &num_params);
1622 	    Disarm(gadget, event, NULL, &num_params);
1623 	}
1624 	break;
1625 
1626     case XmENTER_EVENT:
1627 	DEBUGOUT(_LtDebug(__FILE__, gadget,
1628 			  "ToggleButtonGadget enter window\n"));
1629 	EnterWindow(gadget, event, NULL, &num_params);
1630 	break;
1631 
1632     case XmLEAVE_EVENT:
1633 	DEBUGOUT(_LtDebug(__FILE__, gadget,
1634 			  "ToggleButtonGadget leave window\n"));
1635 	LeaveWindow(gadget, event, NULL, &num_params);
1636 	break;
1637 
1638     case XmMOTION_EVENT:
1639 	DEBUGOUT(_LtDebug(__FILE__, gadget,
1640 			  "ToggleButtonGadget motion event\n"));
1641 	break;
1642 
1643     case XmFOCUS_IN_EVENT:
1644 	_XmFocusInGadget(gadget, event, NULL, &num_params);
1645 	break;
1646 
1647     case XmFOCUS_OUT_EVENT:
1648 	_XmFocusOutGadget(gadget, event, NULL, &num_params);
1649 	break;
1650 
1651     case XmHELP_EVENT:
1652 	Help(gadget, event, NULL, &num_params);
1653 	break;
1654 
1655     case XmBDRAG_EVENT:
1656 	_XmProcessDrag(gadget, event, NULL, NULL);
1657 	break;
1658 
1659     default:
1660 	_XmWarning(gadget, "ToggleButtonGadget got unknown event\n");
1661     }
1662 }
1663 
1664 static void
MenuProcEntry(int proc,Widget w,...)1665 MenuProcEntry(int proc, Widget w,...)
1666 {
1667     va_list arg_list;
1668     /*
1669     Cardinal num_params = 0;
1670     */
1671 
1672     va_start(arg_list, w);
1673 
1674     switch (proc)
1675     {
1676     case XmMENU_ARM:
1677 	{
1678 	    Boolean poppedUp;
1679 
1680 	    if (!TBG_Armed(w))
1681 	    {
1682 		RC_MenuShellPopdown(w, NULL, &poppedUp);
1683 
1684 		TBG_Armed(w) = True;
1685 
1686 		if (XtIsRealized(w))
1687 		    _XmDrawShadows(XtDisplay(w), XtWindow(w),
1688 				   XmParentTopShadowGC(w),
1689 				   XmParentBottomShadowGC(w),
1690 				   XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1691 				   LabG_Shadow(w), XmSHADOW_OUT);
1692 
1693 		MGR_ActiveChild(XtParent(w)) = w;
1694 		if (TBG_ArmCallback(w))
1695 		{
1696 		XmToggleButtonCallbackStruct cbs;
1697 
1698 		    cbs.reason = XmCR_ARM;
1699 		    cbs.event = NULL;
1700 		    cbs.set = TBG_Set(w);
1701 
1702 		    XFlush(XtDisplay(w));
1703 		    XtCallCallbackList(w, TBG_ArmCallback(w), (XtPointer)&cbs);
1704 		}
1705 	    }
1706 	}
1707 	break;
1708     case XmMENU_DISARM:
1709 	{
1710 	    if (TBG_Armed(w))
1711 	    {
1712 		TBG_Armed(w) = False;
1713 
1714 		if (XtIsRealized(w))
1715 		    _XmClearBorder(XtDisplay(w), XtWindow(w),
1716 				   XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1717 				   LabG_Shadow(w));
1718 
1719 		MGR_ActiveChild(XtParent(w)) = w;
1720 		if (TBG_DisarmCallback(w))
1721 		{
1722 		XmToggleButtonCallbackStruct cbs;
1723 
1724 		    cbs.reason = XmCR_DISARM;
1725 		    cbs.event = NULL;
1726 		    cbs.set = TBG_Set(w);
1727 
1728 		    XFlush(XtDisplay(w));
1729 		    XtCallCallbackList(w, TBG_DisarmCallback(w), (XtPointer)&cbs);
1730 		}
1731 	    }
1732 	}
1733 	break;
1734     default:
1735 	_XmWarning(w, "%s(%d) - Invalid menuProc function", __FILE__, __LINE__);
1736 	break;
1737     }
1738 
1739     va_end(arg_list);
1740 }
1741 
1742 /* This may be called from expose, in which case everything is drawn,
1743  * but there's generally no reason to erase anything;
1744  * or it could be called by an action or such, in which case the only
1745  * things drawn are what got changed by toggling, but things may be
1746  * erased as well.
1747  */
1748 
1749 static void
draw_toggle(Widget w,XEvent * event,Region region,int is_expose,int visual_set)1750 draw_toggle(Widget w, XEvent *event, Region region, int is_expose,
1751 	    int visual_set)
1752 {
1753     Dimension dim, delta, fill;
1754     Position x, y;
1755     Pixmap tmp_pix = XmUNSPECIFIED_PIXMAP;
1756 
1757     if (is_expose)
1758     {
1759 	/* Called from expose: get visual_set and draw everything */
1760 	visual_set = TBG_VisualSet(w);
1761     }
1762     else
1763     {
1764 	/* Called from an action: set visual_set and draw some stuff */
1765 	if (TBG_VisualSet(w) == visual_set)
1766 	    return;
1767 	if (TBG_VisualSet(w) == XmINDETERMINATE ||
1768 	    visual_set == XmINDETERMINATE)
1769 	{
1770 	    /* FIX ME: Change the GC for a toggle?  That's ridiculous!
1771 	     * Yet it seems necessary - there's no field available
1772 	     * for an indeterminateGC.  - JHG
1773 	     */
1774 	    XtReleaseGC(w, TBG_SelectGC(w));
1775 	    TBG_VisualSet(w) = visual_set;
1776 	    CreateSelectGC(w);
1777 	} else {
1778 	    TBG_VisualSet(w) = visual_set;
1779 	}
1780 	if (!XtIsRealized(w))
1781 	    return;
1782     }
1783 
1784     /* Fill in the widget only if toggling the background */
1785     if (LabG_IsText(w) && !TBG_IndOn(w) && TBG_FillOnSelect(w))
1786     {
1787 	XFillRectangle(XtDisplay(w), XtWindow(w),
1788 	    visual_set ? TBG_SelectGC(w) : TBG_BackgroundGC(w),
1789 	    XtX(w) + LabG_Highlight(w) + LabG_Shadow(w),
1790 	    XtY(w) + LabG_Highlight(w) + LabG_Shadow(w),
1791 	    XtWidth(w) - ((LabG_Highlight(w) + LabG_Shadow(w)) << 1),
1792 	    XtHeight(w) - ((LabG_Highlight(w) + LabG_Shadow(w)) << 1));
1793     }
1794 
1795     if (is_expose || (!TBG_IndOn(w) && TBG_FillOnSelect(w)) ||
1796 	(LabG_IsPixmap(w) && (
1797 	 TBG_IndeterminatePixmap(w) != XmUNSPECIFIED_PIXMAP ||
1798 	 (XtSensitive(w) ? TBG_OnPixmap(w) :
1799 	  TBG_InsenPixmap(w)) != XmUNSPECIFIED_PIXMAP)))
1800     {
1801 	if (LabG_IsPixmap(w))
1802 	{
1803 	    if (visual_set)
1804 	    {
1805 		/* Switch pixmaps before drawing label */
1806 		if (XtSensitive(w))
1807 		{
1808 		    if (visual_set == XmINDETERMINATE &&
1809 			TBG_IndeterminatePixmap(w) != XmUNSPECIFIED_PIXMAP) {
1810 			tmp_pix = LabG_Pixmap(w);
1811 			LabG_Pixmap(w) = TBG_IndeterminatePixmap(w);
1812 		    } else if (TBG_OnPixmap(w) != XmUNSPECIFIED_PIXMAP) {
1813 			tmp_pix = LabG_Pixmap(w);
1814 			LabG_Pixmap(w) = TBG_OnPixmap(w);
1815 		    }
1816 		} else {
1817 		    if (visual_set == XmINDETERMINATE &&
1818 			TBG_IndeterminatePixmap(w) != XmUNSPECIFIED_PIXMAP) {
1819 			tmp_pix = LabG_Pixmap(w);
1820 			LabG_Pixmap(w) = TBG_IndeterminatePixmap(w);
1821 		    } else if (TBG_InsenPixmap(w) != XmUNSPECIFIED_PIXMAP)
1822 		    {
1823 			tmp_pix = LabG_PixmapInsensitive(w);
1824 			LabG_PixmapInsensitive(w) = TBG_InsenPixmap(w);
1825 		    }
1826 		}
1827 	    }
1828 	    if (!is_expose && (TBG_IndOn(w) || !TBG_FillOnSelect(w))) {
1829 		XRectangle cliprect;
1830 
1831 		/* Changing pixmaps: erase the TextRect just in case
1832 		 * they're different sizes.  Take a bit of trouble here
1833 		 * to avoid excess drawing, which causes more work later.
1834 		 * Based on similar work in Label's expose.
1835 		 */
1836 		cliprect.x =
1837 		    LabG_Highlight(w) + LabG_Shadow(w) + LabG_MarginLeft(w);
1838 		cliprect.y =
1839 		    LabG_Highlight(w) + LabG_Shadow(w) + LabG_MarginTop(w);
1840 		cliprect.width  = XtWidth(w)
1841 		    - ((LabG_Shadow(w) + LabG_Highlight(w)) << 1)
1842 		    - LabG_MarginLeft(w) - LabG_MarginRight(w);
1843 		cliprect.height = XtHeight(w)
1844 		    - ((LabG_Shadow(w) + LabG_Highlight(w)) << 1)
1845 		    - LabG_MarginTop(w) - LabG_MarginBottom(w);
1846 		if (cliprect.x + cliprect.width > LabG_TextRect_x(w) &&
1847 		    cliprect.x < LabG_TextRect_x(w) + LabG_TextRect_width(w) &&
1848 		    cliprect.y + cliprect.height > LabG_TextRect_y(w) &&
1849 		    cliprect.y < LabG_TextRect_y(w) + LabG_TextRect_height(w))
1850 		{
1851 		    if (cliprect.x < LabG_TextRect_x(w))
1852 		    {
1853 			cliprect.width -= LabG_TextRect_x(w) - cliprect.x;
1854 			cliprect.x = LabG_TextRect_x(w);
1855 		    }
1856 		    if (cliprect.x + cliprect.width >
1857 			LabG_TextRect_x(w) + LabG_TextRect_width(w))
1858 		    {
1859 			cliprect.width = (LabG_TextRect_x(w)
1860 			    + LabG_TextRect_width(w)) - cliprect.x;
1861 		    }
1862 		    if (cliprect.y < LabG_TextRect_y(w))
1863 		    {
1864 			cliprect.height -= LabG_TextRect_y(w) - cliprect.y;
1865 			cliprect.y = LabG_TextRect_y(w);
1866 		    }
1867 		    if (cliprect.y + cliprect.height >
1868 			LabG_TextRect_y(w) + LabG_TextRect_height(w))
1869 		    {
1870 			cliprect.height = (LabG_TextRect_y(w)
1871 			    + LabG_TextRect_height(w)) - cliprect.y;
1872 		    }
1873 		    XFillRectangle(XtDisplay(w), XtWindow(w),
1874 				   TBG_BackgroundGC(w),
1875 				   XtX(w) + cliprect.x,
1876 				   XtY(w) + cliprect.y,
1877 				   cliprect.width, cliprect.height);
1878 		}
1879 	    }
1880 	}
1881 #define superclass (&xmLabelGadgetClassRec)
1882 	(*superclass->rect_class.expose) (w, event, region);
1883 #undef superclass
1884 	if (LabG_IsPixmap(w) && visual_set)
1885 	{
1886 	    /* Switch pixmaps back after drawing label */
1887 	    if (tmp_pix != XmUNSPECIFIED_PIXMAP)
1888 	    {
1889 		if (XtSensitive(w))
1890 		{
1891 		    LabG_Pixmap(w) = tmp_pix;
1892 		}
1893 		else
1894 		{
1895 		    LabG_PixmapInsensitive(w) = tmp_pix;
1896 		}
1897 	    }
1898 	}
1899     }
1900 
1901     if (IN_MENU(w))
1902     {
1903 	if (is_expose)
1904 	{
1905 	    /* Exposing in a menu: draw or erase shadows */
1906 	    if (TBG_Armed(w))
1907 	    {
1908 		_XmDrawShadows(XtDisplay(w), XtWindow(w),
1909 			       XmParentTopShadowGC(w),
1910 			       XmParentBottomShadowGC(w),
1911 			       XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1912 			       LabG_Shadow(w), XmSHADOW_OUT);
1913 	    }
1914 	    else
1915 	    {
1916 		_XmClearBorder(XtDisplay(w), XtWindow(w),
1917 			       XtX(w), XtY(w), XtWidth(w), XtHeight(w),
1918 			       LabG_Shadow(w));
1919 	    }
1920 	}
1921     }
1922     else
1923     {
1924 	if (is_expose || !TBG_IndOn(w))
1925 	{
1926 	    /* Non-menu: draw shadows in or out */
1927 	    _XmDrawShadows(XtDisplay(w), XtWindow(w),
1928 			   visual_set == XmINDETERMINATE
1929 			    ? LabG_InsensitiveGC(w)
1930 			    : XmParentTopShadowGC(w),
1931 			   visual_set == XmINDETERMINATE
1932 			    ? LabG_InsensitiveGC(w)
1933 			    : XmParentBottomShadowGC(w),
1934 			   XtX(w) + LabG_Highlight(w),
1935 			   XtY(w) + LabG_Highlight(w),
1936 			   XtWidth(w) - (LabG_Highlight(w) << 1),
1937 			   XtHeight(w) - (LabG_Highlight(w) << 1),
1938 			   LabG_Shadow(w), visual_set && !TBG_IndOn(w)
1939 			   ? XmSHADOW_IN : XmSHADOW_OUT);
1940 	}
1941     }
1942 
1943     if (TBG_IndOn(w) && (visual_set || !is_expose || TBG_Visible(w)))
1944     {
1945 	/* Draw (or erase) the indicator */
1946 
1947 	x = XtX(w) + LabG_Highlight(w) + LabG_Shadow(w) + LabG_MarginWidth(w);
1948 	dim = TBG_IndicatorDim(w);
1949 
1950 	if (TBG_IndicatorSet(w) || !LabG_TextRect_height(w))
1951 	{
1952 	    /* Center indicator on label */
1953 	    y = (LabG_MarginTop(w) << 1) + XtHeight(w)
1954 		- LabG_MarginTop(w) - LabG_MarginBottom(w) - dim;
1955 	}
1956 	else
1957 	{
1958 	    /* Make sure implicit indicator isn't too big to fit.
1959 	     * Align it with top line of text.
1960 	     */
1961 	    y = LabG_TextRect_y(w) << 1;
1962 	    if (IN_MENU(w))
1963 	    {
1964 		/* For the smaller menu indicators.
1965 		 * The "true" formula is (fullsize - smaller) / 2,
1966 		 * but that would require the _XmString calls every time.
1967 		 * This formula is much quicker and usually correct,
1968 		 * with only 1 pixel rounded up 1/6 of the time.
1969 		 * You see, I couldn't sleep, and had nothing better to do...
1970 		 */
1971 		y += (dim + 1) >> 1;
1972 	    }
1973 	    if (dim > XtHeight(w) -
1974 		((LabG_Highlight(w) + LabG_Shadow(w) + LabG_MarginHeight(w))
1975 		 >> 1) - LabG_MarginTop(w) - LabG_MarginBottom(w))
1976 		dim = XtHeight(w) - ((LabG_Highlight(w) + LabG_Shadow(w)
1977 		      + LabG_MarginHeight(w)) >> 1)
1978 		    - LabG_MarginTop(w) - LabG_MarginBottom(w);
1979 	}
1980 
1981 	/* Monochrome displays (or anything with the select color the same
1982 	 * as a shadow) get inset by one pixel to make things easier to see.
1983 	 */
1984 	fill = XmParentTopShadowColor(w) != TBG_SelectColor(w) &&
1985 	    XmParentBottomShadowColor(w) != TBG_SelectColor(w);
1986 
1987 	if (TBG_IndType(w) == XmN_OF_MANY)
1988 	{
1989 	    /* Make square indicators a bit smaller then they really are */
1990 	    delta = dim <= SQUARE_INDICATOR_DEC + Xm3D_ENHANCE_PIXEL
1991 		? dim >> 1
1992 		: SQUARE_INDICATOR_DEC +
1993 		  (dim >= SQUARE_INDICATOR_ELBOW << 1
1994 		   ? (dim - SQUARE_INDICATOR_ELBOW) / SQUARE_INDICATOR_ELBOW
1995 		   : 0);
1996 	    x += delta >> 1;
1997 	    y += delta;
1998 	    dim -= delta;
1999 	}
2000 	y = XtY(w) + (y >> 1);
2001 
2002 	if (LabG_StringDirection(w) == XmSTRING_DIRECTION_R_TO_L)
2003 	    x = XtWidth(w) - x - dim;
2004 
2005 	switch (TBG_IndType(w))
2006 	{
2007 	case XmN_OF_MANY:
2008 	    if (visual_set || TBG_Visible(w))
2009 	    {
2010 		if (TBG_IndOn(w) & INDICATOR_BOX_MASK)
2011 		{
2012 		    _XmDrawShadows(XtDisplay(w), XtWindow(w),
2013 				   visual_set == XmINDETERMINATE
2014 				   ? LabG_InsensitiveGC(w)
2015 				   : (TBG_IndOn(w) & INDICATOR_BOX_MASK)
2016 				     == XmINDICATOR_FLAT_BOX
2017 				     ? XmParentBottomShadowGC(w)
2018 				     : XmParentTopShadowGC(w),
2019 				   visual_set == XmINDETERMINATE
2020 				   ? LabG_InsensitiveGC(w)
2021 				   : XmParentBottomShadowGC(w),
2022 				   x, y, dim, dim, DETAIL_SHADOW_THICKNESS(w),
2023 				   visual_set ? XmSHADOW_IN : XmSHADOW_OUT);
2024 		    delta = DETAIL_SHADOW_THICKNESS(w) + (1 - fill);
2025 		} else {
2026 		    delta = 0;
2027 		}
2028 		if (dim > delta << 1) {
2029 		    if (is_expose || TBG_FillOnSelect(w)) {
2030 			XFillRectangle(XtDisplay(w), XtWindow(w),
2031 				       visual_set && TBG_FillOnSelect(w)
2032 				       ? TBG_SelectGC(w) : TBG_BackgroundGC(w),
2033 				       x + delta, y + delta,
2034 				       dim - (delta << 1), dim - (delta << 1));
2035 		    }
2036 		    if (visual_set == XmUNSET) {
2037 				XFillRectangle(XtDisplayOfObject(w),
2038 					XtWindowOfObject(w),
2039 					TBG_UnselectGC(w),
2040 					x, y, dim, dim);
2041 
2042 				_XmDrawShadows(XtDisplay(w), XtWindow(w),
2043 				   visual_set == XmINDETERMINATE
2044 				   ? LabG_InsensitiveGC(w)
2045 				   : (TBG_IndOn(w) & INDICATOR_BOX_MASK)
2046 				   == XmINDICATOR_FLAT_BOX
2047 				   ? XmParentBottomShadowGC(w)
2048 				   : XmParentTopShadowGC(w),
2049 				   visual_set == XmINDETERMINATE
2050 				   ? LabG_InsensitiveGC(w)
2051 				   : XmParentBottomShadowGC(w),
2052 				   x, y, dim, dim, DETAIL_SHADOW_THICKNESS(w),
2053 				   visual_set ? XmSHADOW_IN : XmSHADOW_OUT);
2054 			}
2055 		}
2056 	    } else {
2057 		XFillRectangle(XtDisplay(w), XtWindow(w),
2058 			       TBG_BackgroundGC(w), x, y, dim, dim);
2059 	    }
2060 	    break;
2061 
2062 	case XmONE_OF_MANY_ROUND:
2063 	    XmeDrawCircle(XtDisplay(w), XtWindow(w),
2064 		visual_set ? XmParentBottomShadowGC(w) : TBG_Visible(w)
2065 		  ? XmParentTopShadowGC(w) : TBG_BackgroundGC(w),
2066 		visual_set ? XmParentTopShadowGC(w) : TBG_Visible(w)
2067 		  ? XmParentBottomShadowGC(w) : TBG_BackgroundGC(w),
2068 		(is_expose || TBG_FillOnSelect(w))
2069 		? visual_set && TBG_FillOnSelect(w)
2070 		  ? TBG_SelectGC(w) : TBG_BackgroundGC(w) : NULL,
2071 		x, y, dim, dim, TBG_DetailShadowThickness(w), 1);
2072 		break;
2073 
2074 	default: /* XmONE_OF_MANY[_DIAMOND] */
2075 	    _XmDrawDiamond(XtDisplay(w), XtWindow(w),
2076 		visual_set ? XmParentBottomShadowGC(w) :
2077 			TBG_Visible(w) ? XmParentTopShadowGC(w) : TBG_BackgroundGC(w),
2078 		visual_set ? XmParentTopShadowGC(w) :
2079 			TBG_Visible(w) ? XmParentBottomShadowGC(w) : TBG_BackgroundGC(w),
2080 		(is_expose || TBG_FillOnSelect(w))
2081 			? (visual_set && TBG_FillOnSelect(w))
2082 				? TBG_SelectGC(w)
2083 				: TBG_UnselectGC(w)
2084 			: NULL,
2085 		x, y, dim, dim, DETAIL_SHADOW_THICKNESS(w),
2086 			   !fill);
2087 	}
2088     }
2089 }
2090 
2091 static int
implicit_indicator(Widget w)2092 implicit_indicator(Widget w)
2093 {
2094     int dim;
2095 
2096     /* For a text button, the default indicator size is the height of
2097      * the first line of text.  For a pixmap, it's related to the pixmap
2098      * height.  For small pixmaps, just make it the same size.
2099      * Why 13 for size & slope?  You got me. -- JHG
2100      */
2101 
2102     if (LabG_IsText(w))
2103     {
2104 	dim = _XmStringHeight(LabG_Font(w), LabG_Label(w))
2105 	    / _XmStringLineCount(LabG_Label(w));
2106 	if (IN_MENU(w))
2107 	{
2108 	    /* Menu indicators are a bit smaller */
2109 	    dim = (dim << 1) / 3;
2110 	}
2111 	if (dim < XmDEFAULT_INDICATOR_DIM)
2112 	    dim = XmDEFAULT_INDICATOR_DIM;
2113 	return dim;
2114     }
2115     else
2116     {
2117 	return LabG_TextRect_height(w) < PIXMAP_INDICATOR_ELBOW
2118 	    ? LabG_TextRect_height(w)
2119 	    : PIXMAP_INDICATOR_ELBOW +
2120 	      LabG_TextRect_height(w) / PIXMAP_INDICATOR_ELBOW;
2121     }
2122 }
2123 
2124 Widget
XmCreateToggleButtonGadget(Widget parent,char * name,Arg * arglist,Cardinal argcount)2125 XmCreateToggleButtonGadget(Widget parent, char *name,
2126 			   Arg *arglist, Cardinal argcount)
2127 {
2128     Widget w;
2129 
2130     _XmObjectLock(parent);
2131     w = XtCreateWidget(name, xmToggleButtonGadgetClass, parent,
2132 		       arglist, argcount);
2133 
2134     _XmObjectUnlock(parent);
2135     return w;
2136 }
2137 
2138 Boolean
XmToggleButtonGadgetGetState(Widget w)2139 XmToggleButtonGadgetGetState(Widget w)
2140 {
2141     Boolean r;
2142 
2143     _XmObjectLock(w);
2144     r = XmIsToggleButtonGadget(w)
2145 	? TBG_Set(w)
2146 	: XmIsToggleButton(w)
2147 	? XmToggleButtonGetState(w)
2148 	: False;
2149 
2150     _XmObjectUnlock(w);
2151     return r;
2152 }
2153 
2154 void
XmToggleButtonGadgetSetState(Widget w,Boolean state,Boolean notify)2155 XmToggleButtonGadgetSetState(Widget w, Boolean state, Boolean notify)
2156 {
2157     XmToggleButtonCallbackStruct cbs;
2158 
2159     _XmObjectLock(w);
2160     if (XtIsWidget(w))
2161     {
2162 	XmToggleButtonSetState(w, state, notify);
2163 	_XmObjectUnlock(w);
2164 	return;
2165     }
2166     if (XmIsToggleButtonGadget(w) && TBG_Set(w) != state)
2167     {
2168 	TBG_Set(w) = state;
2169 	draw_toggle(w, NULL, NULL, False, state);
2170 	if (notify)
2171 	{
2172 	    cbs.reason = XmCR_VALUE_CHANGED;
2173 	    cbs.event = NULL;
2174 	    cbs.set = TBG_Set(w);
2175 	    if (XmIsRowColumn(XtParent(w)))
2176 	    {
2177 		RC_MenuMenuCallback(w, &cbs);
2178 	    }
2179 	    /* Menu callback might cancel the set (radioAlwaysOne). */
2180 	    cbs.set = TBG_Set(w);
2181 	    if (!LabG_SkipCallback(w) && TBG_ValueChangedCallback(w))
2182 	    {
2183 		XFlush(XtDisplay(w));
2184 		XtCallCallbackList(w, TBG_ValueChangedCallback(w),
2185 				   (XtPointer)&cbs);
2186 	    }
2187 	}
2188     }
2189     _XmObjectUnlock(w);
2190 }
2191 
2192 static void
_XmUnselectColorDefault(Widget w,int offset,XrmValue * val)2193 _XmUnselectColorDefault(Widget w, int offset, XrmValue *val)
2194 {
2195 	/*
2196 	 * XmNunselectColor
2197 	 * This resource's default for a color display is XmNbackground.
2198 	 * For a monochrome display, the default is set to the background color.
2199 	 * To set the background of the button to XmNunselectColor when
2200 	 * XmNindicatorOn is XmINDICATOR_NONE, the value of XmNfillOnSelect must
2201 	 * be explicitly set to True.
2202 	 */
2203 	val->size = sizeof(Pixel);
2204 	val->addr = (XtPointer)&CoreBackground(w);
2205 
2206 #define XmParentBackgroundPixel(w) (((XmManagerWidget) \
2207         (((XmGadget)(w))->object.parent))->core.background_pixel)
2208 
2209 	val->addr = (XtPointer)&XmParentBackgroundPixel(w);
2210 #if 0
2211 	if (DefaultDepth(XtDisplay(w), 0) == 1) {	/* Mono */
2212 	} else {					/* Colour */
2213 	}
2214 #endif
2215 
2216 	DEBUGOUT(_LtDebug(__FILE__, w, "_XmUnselectColorDefault(%p)\n",
2217 		*(Pixel *)(val->addr)));
2218 }
2219