1 /**
2  *
3  * $Id: ArrowBG.c,v 1.1 2004/08/28 19:22:43 dannybackx Exp $
4  *
5  * Copyright (C) 1995 Free Software Foundation, Inc.
6  * Copyright (C) 1995-2001 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[] = "$Id: ArrowBG.c,v 1.1 2004/08/28 19:22:43 dannybackx Exp $";
27 
28 #include <LTconfig.h>
29 
30 #include <XmI/XmI.h>
31 #include <Xm/XmP.h>
32 #include <Xm/ArrowBGP.h>
33 #include <Xm/RepType.h>
34 
35 #include <XmI/DebugUtil.h>
36 
37 /*
38  * Experiment
39  *
40  * Try to add trait stuff by #ifdeffing it.
41  */
42 #if XmVERSION > 1
43 #include <Xm/TraitP.h>
44 #include <Xm/ActivatableT.h>
45 
46 void _XmArrowBG_TraitAddCallback(Widget, XtCallbackProc, XtPointer, Boolean);
47 
48 static XmActivatableTraitRec _XmArrowBGTraitRec = {
49 	/* version      */      0,
50 	/* cb           */      _XmArrowBG_TraitAddCallback
51 };
52 #endif
53 
54 #if XmVERSION > 1
55 #define PUSH_GC(w)			(XtSensitive(w)		\
56 					 ? ABG_ArrowGC(w)	\
57 					 : ABG_InsensitiveGC(w))
58 #define DETAIL_SHADOW_THICKNESS(w)	ABG_DetailShadowThickness(w)
59 #else
60 #define PUSH_GC(w)			NULL
61 #define DETAIL_SHADOW_THICKNESS(w)	Xm3D_ENHANCE_PIXEL
62 #endif
63 
64 /* Forward Declarations */
65 
66 
67 #if XmVERSION > 1
68 static void class_initialize(void);
69 #endif
70 
71 static void class_part_initialize(WidgetClass w_class);
72 
73 static void initialize(Widget request, Widget w_new,
74 		       ArgList args, Cardinal *num_args);
75 
76 static void destroy(Widget w);
77 
78 static void expose(Widget w, XEvent *event, Region region);
79 
80 #if 0
81 static XtGeometryResult query_geometry(Widget w,
82 				       XtWidgetGeometry *proposed,
83 				       XtWidgetGeometry *answer);
84 #endif
85 
86 static Boolean set_values(Widget current, Widget request, Widget new_w,
87 			  ArgList args, Cardinal *num_args);
88 
89 static void input_dispatch(Widget gadget, XEvent *event, Mask event_mask);
90 
91 /*
92  * Resources for the arrowbuttongadget class
93  */
94 #define Offset(field) XtOffsetOf(XmArrowButtonGadgetRec, arrowbutton.field)
95 static XtResource resources[] =
96 {
97     {
98 	XmNmultiClick, XmCMultiClick, XmRMultiClick,
99 	sizeof(unsigned char), Offset(multiClick),
100 	XmRImmediate, (XtPointer)XmMULTICLICK_KEEP
101     },
102     {
103 	XmNarrowDirection, XmCArrowDirection, XmRArrowDirection,
104 	sizeof(unsigned char), Offset(direction),
105 	XmRImmediate, (XtPointer)XmARROW_UP
106     },
107     {
108 	XmNactivateCallback, XmCCallback, XmRCallback,
109 	sizeof(XtCallbackList), Offset(activate_callback),
110 	XmRPointer, (XtPointer)NULL
111     },
112     {
113 	XmNarmCallback, XmCCallback, XmRCallback,
114 	sizeof(XtCallbackList), Offset(arm_callback),
115 	XmRPointer, (XtPointer)NULL
116     },
117     {
118 	XmNdisarmCallback, XmCCallback, XmRCallback,
119 	sizeof(XtCallbackList), Offset(disarm_callback),
120 	XmRPointer, (XtPointer)NULL
121     },
122 #if XmVERSION > 1
123     {
124 	XmNdetailShadowThickness, XmCShadowThickness, XmRHorizontalDimension,
125 	sizeof(Dimension), Offset(detail_shadow_thickness),
126 	XmRImmediate, (XtPointer)2 /* FIX ME */
127     }
128 #endif
129 };
130 
131 #if XmVERSION > 1
132 static XmSyntheticResource syn_resources[] =
133 {
134     {
135 	XmNdetailShadowThickness,
136 	sizeof(Dimension), Offset(detail_shadow_thickness),
137 	_XmFromHorizontalPixels, _XmToHorizontalPixels
138     }
139 };
140 #endif
141 
142 static void Arm(Widget w, XEvent *event,
143 		String *params, Cardinal *num_params);
144 
145 static void Activate(Widget w, XEvent *event,
146 		     String *params, Cardinal *num_params);
147 
148 static void Disarm(Widget w, XEvent *event,
149 		   String *params, Cardinal *num_params);
150 
151 static void ArmAndActivate(Widget w, XEvent *event,
152 			   String *params, Cardinal *num_params);
153 
154 static void Help(Widget w, XEvent *event,
155 		 String *params, Cardinal *num_params);
156 
157 static void EnterWindow(Widget w, XEvent *event,
158 			String *params, Cardinal *num_params);
159 
160 static void LeaveWindow(Widget w, XEvent *event,
161 			String *params, Cardinal *num_params);
162 
163 
164 #if 0
165 static XmBaseClassExtRec _XmArrowBGRectClassExtRec = {
166     /* next_extension            */ NULL,
167     /* record_type               */ NULLQUARK,
168     /* version                   */ XmBaseClassExtVersion,
169     /* size                      */ sizeof(XmBaseClassExtRec),
170     /* initialize_prehook        */ NULL,
171     /* set_values_prehook        */ NULL,
172     /* initialize_posthook       */ NULL,
173     /* set_values_posthook       */ NULL,
174     /* secondary_object_class    */ NULL,
175     /* secondary_object_create   */ NULL,
176     /* get_secondary_resources   */ NULL,
177     /* fast_subclass             */ { 0 },
178     /* get_values_prehook        */ NULL,
179     /* get_values_posthook       */ NULL,
180     /* class_part_init_prehook   */ NULL,
181     /* class_part_init_posthook  */ NULL,
182     /* ext_resources             */ NULL,
183     /* compiled_ext_resources    */ NULL,
184     /* num_ext_resources         */ 0,
185     /* use_sub_resources         */ False,
186     /* widget_navigable          */ XmInheritWidgetNavigable,
187     /* focus_change              */ XmInheritFocusChange,
188     /* wrapper_data              */ NULL
189 };
190 
191 static XmGadgetClassExtRec _XmArrowBGadgetClassExtRec = {
192     /* next_extension            */ NULL,
193     /* record_type               */ NULLQUARK,
194     /* version                   */ XmGadgetClassExtVersion,
195     /* size                      */ sizeof(XmGadgetClassExtRec),
196     /* widget_baseline_proc      */ NULL,
197     /* display_rect_proc         */ NULL,
198 };
199 #endif
200 
201 XmArrowButtonGadgetClassRec xmArrowButtonGadgetClassRec = {
202     /* RectObj class part */
203     {
204 	/* superclass            */ (WidgetClass) &xmGadgetClassRec,
205 	/* class_name            */ "XmArrowButtonGadget",
206 	/* widget_size           */ sizeof(XmArrowButtonGadgetRec),
207 #if XmVERSION > 1
208 	/* class_initialize      */ class_initialize,
209 #else
210 	/* class_initialize      */ NULL,
211 #endif
212 	/* class_part_initialize */ class_part_initialize,
213 	/* class_inited          */ False,
214 	/* initialize            */ initialize,
215 	/* initialize_hook       */ NULL,
216 	/* realize               */ NULL,
217 	/* actions               */ NULL,
218 	/* num_actions           */ 0,
219 	/* resources             */ resources,
220 	/* num_resources         */ XtNumber(resources),
221 	/* xrm_class             */ NULLQUARK,
222 	/* compress_motion       */ True /*False*/,
223 	/* compress_exposure     */ XtExposeCompressMaximal,
224 	/* compress_enterleave   */ True /*False*/,
225 	/* visible_interest      */ False,
226 	/* destroy               */ destroy,
227 	/* resize                */ NULL,
228 	/* expose                */ expose,
229 	/* set_values            */ set_values,
230 	/* set_values_hook       */ NULL,
231 	/* set_values_almost     */ XtInheritSetValuesAlmost,
232 	/* get_values_hook       */ NULL,
233 	/* accept_focus          */ NULL,
234 	/* version               */ XtVersionDontCheck,
235 	/* callback offsets      */ NULL,
236 	/* tm_table              */ NULL,
237 	/* query_geometry        */ NULL /* query_geometry */,
238 	/* display_accelerator   */ NULL,
239 	/* extension             */ (XtPointer)NULL /*&_XmArrowBGRectClassExtRec*/
240     },
241     /* XmGadget part */
242     {
243 	/* border_highlight   */ XmInheritBorderHighlight,
244 	/* border_unhighlight */ XmInheritBorderUnhighlight,
245 	/* arm_and_activate   */ ArmAndActivate,
246 	/* input_dispatch     */ input_dispatch,
247 	/* visual_change      */ NULL, /* FIX ME */
248 #if XmVERSION > 1
249 	/* syn_resources      */ syn_resources,
250 #else
251 	/* syn_resources      */ NULL,
252 #endif
253 	/* num_syn_resources  */ 0,
254 	/* cache_part         */ NULL,
255 	/* extension          */ (XtPointer)NULL /*&_XmArrowBGadgetClassExtRec*/
256     },
257     /* XmArrowButtonGadget part */
258     {
259 	/* extension */ NULL
260     },
261 };
262 
263 
264 WidgetClass xmArrowButtonGadgetClass =
265 			(WidgetClass)&xmArrowButtonGadgetClassRec;
266 
267 #if XmVERSION > 1
268 static void
class_initialize(void)269 class_initialize(void)
270 {
271 #if 0
272     _XmArrowBGRectClassExtRec.record_type = XmQmotif;
273 #endif
274 
275     if (! XmeTraitSet((XtPointer)xmArrowButtonGadgetClass, XmQTactivatable,
276 		(XtPointer)&_XmArrowBGTraitRec)) {
277 	_XmWarning(NULL,
278 	    "XmArrowButtonGadget ClassInitialize: XmeTraitSet failed\n");
279     }
280 }
281 #endif
282 
283 static void
class_part_initialize(WidgetClass widget_class)284 class_part_initialize(WidgetClass widget_class)
285 {
286     _XmFastSubclassInit(widget_class, XmARROW_BUTTON_GADGET_BIT);
287 }
288 
289 static void
CreateArrowGC(Widget w)290 CreateArrowGC(Widget w)
291 {
292     XGCValues values;
293     XtGCMask mask;
294 
295     mask = GCForeground | GCBackground | GCFillStyle | GCFunction |
296 	GCSubwindowMode | GCGraphicsExposures | GCPlaneMask;
297 
298     values.function = GXcopy;
299     values.plane_mask = -1;
300     values.subwindow_mode = ClipByChildren;
301     values.graphics_exposures = False;
302     values.foreground = XmParentForeground(w);
303     values.background = XmParentBackground(w);
304     values.fill_style = FillSolid;
305 
306     ABG_ArrowGC(w) = XtGetGC(w, mask, &values);
307 }
308 
309 static void
CreateInsensitiveGC(Widget w)310 CreateInsensitiveGC(Widget w)
311 {
312     XGCValues values;
313     XtGCMask mask;
314 
315     mask = GCForeground | GCBackground | GCFillStyle | GCFunction | GCStipple |
316 	GCSubwindowMode | GCGraphicsExposures | GCPlaneMask |
317 	GCTileStipXOrigin | GCTileStipYOrigin;
318 
319     values.function = GXcopy;
320     values.plane_mask = -1;
321     values.subwindow_mode = ClipByChildren;
322     values.graphics_exposures = False;
323     values.foreground = XmParentForeground(w);
324     values.background = XmParentBackground(w);
325     values.fill_style = FillStippled;
326     values.ts_x_origin = values.ts_y_origin = 0;
327 
328     values.stipple =
329 	XmGetPixmapByDepth(XtScreen(w), "50_foreground", 1, 0, 1);
330 
331     ABG_InsensitiveGC(w) = XtGetGC(w, mask, &values);
332 }
333 
334 static void
initialize(Widget request,Widget new_w,ArgList args,Cardinal * num_args)335 initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
336 {
337     if (!XtIsSubclass(XtParent(new_w), xmManagerWidgetClass))
338     {
339 	_XmError(new_w, "parent should be manager.");
340     }
341 
342     if (!XmRepTypeValidValue(XmRepTypeGetId(XmRArrowDirection),
343 			     ABG_Direction(new_w), new_w))
344 	ABG_Direction(new_w) = XmARROW_UP;
345 
346     if (!XmRepTypeValidValue(XmRepTypeGetId(XmRMultiClick),
347 			     ABG_MultiClick(new_w), new_w))
348 	ABG_MultiClick(new_w) = XmMULTICLICK_KEEP;
349 
350     if (XtWidth(request) == 0)
351     {
352 	XtWidth(new_w) += 15;
353     }
354 
355     if (XtHeight(request) == 0)
356     {
357 	XtHeight(new_w) += 15;
358     }
359 
360     /* Gadget override */
361     G_HighlightOnEnter(new_w) = True;
362 
363     ABG_Armed(new_w) = False;
364 
365     CreateArrowGC(new_w);
366     CreateInsensitiveGC(new_w);
367 
368     G_EventMask(new_w) = XmARM_EVENT | XmACTIVATE_EVENT | XmENTER_EVENT |
369 	XmLEAVE_EVENT | XmFOCUS_IN_EVENT |
370 	XmFOCUS_OUT_EVENT | XmMULTI_ARM_EVENT |
371 	XmMULTI_ACTIVATE_EVENT | XmHELP_EVENT;
372 
373     ABG_Timer(new_w) = 0;
374 }
375 
376 static void
destroy(Widget w)377 destroy(Widget w)
378 {
379     if (ABG_Timer(w) != 0)
380     {
381 	XtRemoveTimeOut(ABG_Timer(w));
382 	ABG_Timer(w) = 0;
383     }
384 
385     XtReleaseGC(w, ABG_ArrowGC(w));
386     XtReleaseGC(w, ABG_InsensitiveGC(w));
387 }
388 
389 static Boolean
set_values(Widget old,Widget request,Widget new_w,ArgList args,Cardinal * num_args)390 set_values(Widget old, Widget request, Widget new_w,
391 	   ArgList args, Cardinal *num_args)
392 {
393 	XGCValues	gcv;
394 	Boolean		refresh_needed = False;
395 
396 	if (!XmRepTypeValidValue(XmRepTypeGetId(XmRArrowDirection),
397 			     ABG_Direction(new_w), new_w))
398 		ABG_Direction(new_w) = ABG_Direction(old);
399 
400 	if (!XmRepTypeValidValue(XmRepTypeGetId(XmRMultiClick),
401 			     ABG_MultiClick(new_w), new_w))
402 		ABG_MultiClick(new_w) = ABG_MultiClick(old);
403 
404 	/* See bug #772755 : need to query the old widget's values */
405 	XGetGCValues(XtDisplayOfObject(old), ABG_ArrowGC(old), GCForeground, &gcv);
406 	if (XmParentForeground(new_w) != gcv.foreground) {
407 		XtReleaseGC(new_w, ABG_ArrowGC(new_w));
408 		XtReleaseGC(new_w, ABG_InsensitiveGC(new_w));
409 
410 		CreateArrowGC(new_w);
411 		CreateInsensitiveGC(new_w);
412 
413 		refresh_needed = True;
414 	}
415 
416 	if (ABG_Direction(new_w) != ABG_Direction(old) ||
417 #if XmVERSION > 1
418 		ABG_DetailShadowThickness(old) != ABG_DetailShadowThickness(new_w) ||
419 #endif
420 		XtSensitive(new_w) != XtSensitive(old))
421 	{
422 		refresh_needed = True;
423 	}
424 
425 	return refresh_needed;
426 }
427 
428 static void
expose(Widget w,XEvent * event,Region region)429 expose(Widget w, XEvent *event, Region region)
430 {
431     Dimension margin = G_ShadowThickness(w) + G_HighlightThickness(w);
432     GC myGC;
433 
434     /* use the right GC */
435     if (XtIsSensitive(w))
436     {
437 	myGC = ABG_ArrowGC(w);
438     }
439     else
440     {
441 	myGC = ABG_InsensitiveGC(w);
442     }
443 
444     if (G_Highlighted(w))
445     {
446 	(*GC_BorderHighlight(XtClass(w))) (w);
447     }
448     else
449     {
450 	(*GC_BorderUnhighlight(XtClass(w))) (w);
451     }
452 
453 
454     _XmDrawShadows(XtDisplayOfObject(w),
455 		   XtWindowOfObject(w),
456 		   XmParentTopShadowGC(w),
457 		   XmParentBottomShadowGC(w),
458 		   XtX(w) + G_HighlightThickness(w),
459 		   XtY(w) + G_HighlightThickness(w),
460 		   XtWidth(w) - 2 * G_HighlightThickness(w),
461 		   XtHeight(w) - 2 * G_HighlightThickness(w),
462 		   G_ShadowThickness(w),
463 		   XmSHADOW_OUT);
464 
465     if (ABG_Armed(w))
466     {
467 	_XmDrawArrow(XtDisplayOfObject(w),
468 		     XtWindowOfObject(w),
469 		     XmParentBottomShadowGC(w),
470 		     XmParentTopShadowGC(w),
471 		     myGC,
472 		     XtX(w) + margin, XtY(w) + margin,
473 		     XtWidth(w) - (margin << 1), XtHeight(w) - (margin << 1),
474 		     DETAIL_SHADOW_THICKNESS(w),
475 		     ABG_Direction(w));
476     }
477     else
478     {
479 	_XmDrawArrow(XtDisplayOfObject(w),
480 		     XtWindowOfObject(w),
481 		     XmParentTopShadowGC(w),
482 		     XmParentBottomShadowGC(w),
483 		     myGC,
484 		     XtX(w) + margin, XtY(w) + margin,
485 		     XtWidth(w) - (margin << 1), XtHeight(w) - (margin << 1),
486 		     DETAIL_SHADOW_THICKNESS(w),
487 		     ABG_Direction(w));
488     }
489 }
490 
491 #if 0
492 static XtGeometryResult
493 query_geometry(Widget w, XtWidgetGeometry *proposed, XtWidgetGeometry *answer)
494 {
495     /* Motif does not have this method */
496     answer->request_mode = CWWidth | CWHeight;
497 
498     answer->width = XtWidth(w);
499 
500     answer->height = XtHeight(w);
501 
502     if (((proposed->request_mode & (CWWidth | CWHeight))
503 	 == (CWWidth | CWHeight)) &&
504 	proposed->width == answer->width &&
505 	proposed->height == answer->height)
506     {
507 	return XtGeometryYes;
508     }
509     else if (answer->width == XtWidth(w) && answer->height == XtHeight(w))
510     {
511 	return XtGeometryNo;
512     }
513     else
514     {
515 	return XtGeometryAlmost;
516     }
517 }
518 #endif
519 
520 static void
Arm(Widget w,XEvent * event,String * params,Cardinal * num_params)521 Arm(Widget w, XEvent *event, String *params, Cardinal *num_params)
522 {
523     int margin;
524     XmArrowButtonCallbackStruct cbs;
525 
526     if (!ABG_Armed(w))
527     {
528 	ABG_Armed(w) = True;
529 
530 	if (XtIsRealized(w))
531 	{
532 	    margin = G_ShadowThickness(w) + G_HighlightThickness(w);
533 	    _XmDrawArrow(XtDisplayOfObject(w),
534 			 XtWindowOfObject(w),
535 			 XmParentBottomShadowGC(w),
536 			 XmParentTopShadowGC(w),
537 			 PUSH_GC(w),
538 			 XtX(w) + margin, XtY(w) + margin,
539 			 XtWidth(w) - (margin << 1),
540 			 XtHeight(w) - (margin << 1),
541 			 DETAIL_SHADOW_THICKNESS(w),
542 			 ABG_Direction(w));
543 	}
544 
545 	if (ABG_ArmCallback(w))
546 	{
547 	    cbs.reason = XmCR_ARM;
548 	    cbs.event = event;
549 	    cbs.click_count = ABG_ClickCount(w);
550 
551 	    XFlush(XtDisplay(w));
552 
553 	    XtCallCallbackList(w,
554 			       ABG_ArmCallback(w),
555 			       (XtPointer)&cbs);
556 	}
557     }
558 }
559 
560 static void
Disarm(Widget w,XEvent * event,String * params,Cardinal * num_params)561 Disarm(Widget w, XEvent *event, String *params, Cardinal *num_params)
562 {
563     int margin;
564     XmArrowButtonCallbackStruct cbs;
565 
566     if (XtIsRealized(w))
567     {
568 	margin = G_ShadowThickness(w) + G_HighlightThickness(w);
569 	_XmDrawArrow(XtDisplayOfObject(w),
570 		     XtWindowOfObject(w),
571 		     XmParentTopShadowGC(w),
572 		     XmParentBottomShadowGC(w),
573 		     PUSH_GC(w),
574 		     XtX(w) + margin, XtY(w) + margin,
575 		     XtWidth(w) - (margin << 1),
576 		     XtHeight(w) - (margin << 1),
577 		     DETAIL_SHADOW_THICKNESS(w),
578 		     ABG_Direction(w));
579     }
580 
581     if (ABG_DisarmCallback(w))
582     {
583 	cbs.reason = XmCR_DISARM;
584 	cbs.event = event;
585 	cbs.click_count = ABG_ClickCount(w);
586 
587 	XFlush(XtDisplay(w));
588 
589 	XtCallCallbackList(w,
590 			   ABG_DisarmCallback(w),
591 			   (XtPointer)&cbs);
592     }
593     ABG_Armed(w) = False;
594 }
595 
596 static void
Activate(Widget w,XEvent * event,String * params,Cardinal * num_params)597 Activate(Widget w,
598 	 XEvent *event,
599 	 String *params,
600 	 Cardinal *num_params)
601 {
602     int margin;
603     XButtonEvent *ev = (XButtonEvent *)event;
604     XmArrowButtonCallbackStruct cbs;
605 
606     if ((ev->x >= XtX(w) && ev->x < XtX(w) + XtWidth(w)) &&
607 	(ev->y >= XtY(w) && ev->y < XtY(w) + XtHeight(w)))
608     {
609 	cbs.reason = XmCR_ACTIVATE;
610 	cbs.event = event;
611 	cbs.click_count = ABG_ClickCount(w);
612 
613 	if (ABG_ActivateCallback(w))
614 	{
615 	    if (XtIsRealized(w))
616 	    {
617 		margin = G_ShadowThickness(w) + G_HighlightThickness(w);
618 		_XmDrawArrow(XtDisplayOfObject(w),
619 			     XtWindowOfObject(w),
620 			     XmParentBottomShadowGC(w),
621 			     XmParentTopShadowGC(w),
622 			     PUSH_GC(w),
623 			     XtX(w) + margin, XtY(w) + margin,
624 			     XtWidth(w) - (margin << 1),
625 			     XtHeight(w) - (margin << 1),
626 			     DETAIL_SHADOW_THICKNESS(w),
627 			     ABG_Direction(w));
628 		XFlush(XtDisplay(w));
629 	    }
630 
631 	    XtCallCallbackList(w,
632 			       ABG_ActivateCallback(w),
633 			       (XtPointer)&cbs);
634 	}
635     }
636 
637     Disarm(w, event, params, num_params);
638 }
639 
640 static void
ArmTimeout(XtPointer data,XtIntervalId * id)641 ArmTimeout(XtPointer data, XtIntervalId *id)
642 {
643     int margin;
644     Widget w = (Widget)data;
645 
646     DEBUGOUT(_LtDebug(__FILE__, w, "ArmTimeout\n"));
647 
648     ABG_Timer(w) = 0;
649 
650     if (XtIsRealized(w))
651     {
652 	margin = G_ShadowThickness(w) + G_HighlightThickness(w);
653 	if (ABG_Armed(w))
654 	{
655 	    _XmDrawArrow(XtDisplayOfObject(w),
656 			 XtWindowOfObject(w),
657 			 XmParentBottomShadowGC(w),
658 			 XmParentTopShadowGC(w),
659 			 PUSH_GC(w),
660 			 XtX(w) + margin, XtY(w) + margin,
661 			 XtWidth(w) - (margin << 1),
662 			 XtHeight(w) - (margin << 1),
663 			 DETAIL_SHADOW_THICKNESS(w),
664 			 ABG_Direction(w));
665 	}
666 	else
667 	{
668 	    _XmDrawArrow(XtDisplayOfObject(w),
669 			 XtWindowOfObject(w),
670 			 XmParentTopShadowGC(w),
671 			 XmParentBottomShadowGC(w),
672 			 PUSH_GC(w),
673 			 XtX(w) + margin, XtY(w) + margin,
674 			 XtWidth(w) - (margin << 1),
675 			 XtHeight(w) - (margin << 1),
676 			 DETAIL_SHADOW_THICKNESS(w),
677 			 ABG_Direction(w));
678 	}
679 	XFlush(XtDisplayOfObject(w));
680     }
681 }
682 
683 static void
ArmAndActivate(Widget w,XEvent * event,String * params,Cardinal * num_params)684 ArmAndActivate(Widget w, XEvent *event, String *params, Cardinal *num_params)
685 {
686     XmArrowButtonCallbackStruct cbs;
687 
688     DEBUGOUT(_LtDebug(__FILE__, w, "ArmAndActivate\n"));
689 
690     /* Arm, Activate, and Disarm now, but draw the disarmed state later */
691 
692     Arm(w, event, params, num_params);
693     ABG_Armed(w) = False;
694     if (ABG_ActivateCallback(w))
695     {
696 	XFlush(XtDisplayOfObject(w));
697 	cbs.reason = XmCR_ACTIVATE;
698 	cbs.event = event;
699 	cbs.click_count = 1;
700 	XtCallCallbackList(w,
701 			   ABG_ActivateCallback(w),
702 			   (XtPointer)&cbs);
703     }
704     if (ABG_DisarmCallback(w))
705     {
706 	XFlush(XtDisplayOfObject(w));
707 	cbs.reason = XmCR_DISARM;
708 	cbs.event = event;
709 	cbs.click_count = 1;
710 	XtCallCallbackList(w,
711 			   ABG_DisarmCallback(w),
712 			   (XtPointer)&cbs);
713     }
714 
715     if (ABG_Timer(w) != 0)
716     {
717 	XtRemoveTimeOut(ABG_Timer(w));
718 	ABG_Timer(w) = 0;
719     }
720 
721     ABG_Timer(w) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
722 				   ACTIVATE_DELAY, ArmTimeout, (XtPointer)w);
723 }
724 
725 static void
EnterWindow(Widget w,XEvent * event,String * params,Cardinal * num_params)726 EnterWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
727 {
728     int margin = G_ShadowThickness(w) + G_HighlightThickness(w);
729 
730     if (ABG_Armed(w))
731     {
732 	_XmDrawArrow(XtDisplayOfObject(w),
733 		     XtWindowOfObject(w),
734 		     XmParentBottomShadowGC(w),
735 		     XmParentTopShadowGC(w),
736 		     PUSH_GC(w),
737 		     XtX(w) + margin, XtY(w) + margin,
738 		     XtWidth(w) - (margin << 1), XtHeight(w) - (margin << 1),
739 		     DETAIL_SHADOW_THICKNESS(w),
740 		     ABG_Direction(w));
741     }
742 }
743 
744 static void
LeaveWindow(Widget w,XEvent * event,String * params,Cardinal * num_params)745 LeaveWindow(Widget w, XEvent *event, String *params, Cardinal *num_params)
746 {
747     int margin = G_ShadowThickness(w) + G_HighlightThickness(w);
748 
749     if (ABG_Armed(w))
750     {
751 	_XmDrawArrow(XtDisplayOfObject(w),
752 		     XtWindowOfObject(w),
753 		     XmParentTopShadowGC(w),
754 		     XmParentBottomShadowGC(w),
755 		     PUSH_GC(w),
756 		     XtX(w) + margin, XtY(w) + margin,
757 		     XtWidth(w) - (margin << 1), XtHeight(w) - (margin << 1),
758 		     DETAIL_SHADOW_THICKNESS(w),
759 		     ABG_Direction(w));
760     }
761 }
762 
763 static void
Help(Widget w,XEvent * event,String * params,Cardinal * num_params)764 Help(Widget w, XEvent *event, String *params, Cardinal *num_params)
765 {
766     Widget cur = w;
767     XmAnyCallbackStruct cbs;
768 
769     cbs.reason = XmCR_HELP;
770     cbs.event = event;
771 
772     while (cur != NULL)
773     {
774 	if (XtHasCallbacks(w, XmNhelpCallback) == XtCallbackHasSome)
775 	{
776 	    XtCallCallbacks(w, XmNhelpCallback, (XtPointer)&cbs);
777 
778 	    return;
779 	}
780 
781 	cur = XtParent(cur);
782     }
783 }
784 
785 static void
input_dispatch(Widget gadget,XEvent * event,Mask event_mask)786 input_dispatch(Widget gadget, XEvent *event, Mask event_mask)
787 {
788     Cardinal num_params = 0;
789 
790     switch (event_mask)
791     {
792     case XmARM_EVENT:
793 	DEBUGOUT(_LtDebug(__FILE__, gadget,
794 		 "ArrowButtonGadget got arm event\n"));
795 	Arm(gadget, event, NULL, &num_params);
796 	break;
797 
798     case XmACTIVATE_EVENT:
799 	DEBUGOUT(_LtDebug(__FILE__, gadget,
800 		 "ArrowButtonGadget got activate event\n"));
801 	ABG_ClickCount(gadget) = 1;
802 	Activate(gadget, event, NULL, &num_params);
803 	break;
804 
805     case XmENTER_EVENT:
806 	DEBUGOUT(_LtDebug(__FILE__, gadget,
807 		 "ArrowButtonGadget got enter event\n"));
808 	EnterWindow(gadget, event, NULL, &num_params);
809 	break;
810 
811     case XmLEAVE_EVENT:
812 	DEBUGOUT(_LtDebug(__FILE__, gadget,
813 		 "ArrowButtonGadget got leave event\n"));
814 	LeaveWindow(gadget, event, NULL, &num_params);
815 	break;
816 
817     case XmFOCUS_IN_EVENT:
818 	_XmFocusInGadget(gadget, event, NULL, &num_params);
819 	break;
820 
821     case XmFOCUS_OUT_EVENT:
822 	_XmFocusOutGadget(gadget, event, NULL, &num_params);
823 	break;
824 
825     case XmHELP_EVENT:
826 	Help(gadget, event, NULL, &num_params);
827 	break;
828 
829     case XmMULTI_ARM_EVENT:
830 	if (ABG_MultiClick(gadget) == XmMULTICLICK_KEEP)
831 	{
832 	    Arm(gadget, event, NULL, &num_params);
833 	}
834 	break;
835 
836     case XmMULTI_ACTIVATE_EVENT:
837 	if (ABG_MultiClick(gadget) == XmMULTICLICK_KEEP)
838 	{
839 	    ABG_ClickCount(gadget)++;
840 	    Activate(gadget, event, NULL, &num_params);
841 	}
842 	break;
843 
844     default:
845 	_XmError(gadget, "Unexpected event in ArrowButton gadget\n");
846 	break;
847     }
848 }
849 
850 Widget
XmCreateArrowButtonGadget(Widget parent,char * name,Arg * arglist,Cardinal argcount)851 XmCreateArrowButtonGadget(Widget parent, char *name,
852 			  Arg *arglist, Cardinal argcount)
853 {
854     return XtCreateWidget(name,
855 			  xmArrowButtonGadgetClass,
856 			  parent,
857 			  arglist,
858 			  argcount);
859 }
860 
861 #if XmVERSION > 1
_XmArrowBG_TraitAddCallback(Widget w,XtCallbackProc cb,XtPointer cbp,Boolean set)862 void _XmArrowBG_TraitAddCallback(Widget w,
863 				 XtCallbackProc cb,
864 				 XtPointer cbp,
865 				 Boolean set)
866 {
867 	if (set)
868 	    XtAddCallback(w, XmNactivateCallback, cb, cbp);
869 	else
870 	    XtRemoveCallback(w, XmNactivateCallback, cb, cbp);
871 }
872 #endif
873