xref: /vim-8.2.3635/src/gui_xmebw.c (revision 2bf24176)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 /*
10  *
11  * (C) 2002,2005 by Marcin Dalecki <[email protected]>
12  *
13  * MARCIN DALECKI ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE ANY
14  * OF THIS SOFTWARE . THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
15  * KIND, AND MARCIN DALECKI EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES,
16  * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 
20 /*
21  * Enhanced Motif PushButton widget with move over behavior.
22  */
23 
24 #include "vim.h"
25 
26 #ifdef FEAT_TOOLBAR
27 
28 #include <Xm/XmP.h>
29 #include <Xm/DrawP.h>
30 #if defined(HAVE_XM_TRAITP_H) && defined(HAVE_XM_MANAGER_H) \
31 	&& defined(HAVE_XM_UNHIGHLIGHTT_H) && defined(HAVE_XM_XPMP_H)
32 # include <Xm/TraitP.h>
33 # include <Xm/Manager.h>
34 # include <Xm/UnhighlightT.h>
35 # include <Xm/XpmP.h>
36 # define UNHIGHLIGHTT
37 #else
38 # include <X11/xpm.h>
39 #endif
40 #include <Xm/ManagerP.h>
41 #include <Xm/Display.h>
42 #include <Xm/DisplayP.h>
43 
44 #include <X11/Shell.h>
45 #include <X11/ShellP.h>
46 
47 #include "gui_xmebwp.h"
48 
49 /* Provide some missing wrappers, which are missed from the LessTif
50  * implementation.  Also missing in Motif 1.2 and earlier.
51  *
52  * We neither use XmeGetPixmapData or _XmGetPixmapData, since with LessTif the
53  * pixmap will not appear in it's caches properly. We cache the interesting
54  * values in XmEnhancedButtonPart instead ourself.
55  */
56 #if defined(LESSTIF_VERSION) || (XmVersion <= 1002)
57 # ifndef Lab_IsMenupane
58 #  define Lab_IsMenupane(w) (Lab_MenuType(w) == (int)XmMENU_POPUP || \
59 		    Lab_MenuType(w) == (int)XmMENU_PULLDOWN)
60 # endif
61 # define XmeClearBorder	    _XmClearBorder
62 # define XmeDrawShadows	    _XmDrawShadows
63 # define XmeDrawHighlight(a, b, c, d, e, f, g, h) \
64     _XmDrawHighlight(a, b, c, d, e, f, g, h, LineSolid)
65 #endif
66 
67 /*
68  * Motif internals we have to cheat around with.
69  */
70 
71 /* Hopefully this will never change... */
72 #ifndef XmFOCUS_IGNORE
73 # define XmFOCUS_IGNORE       1<<1
74 #endif
75 
76 extern Boolean _XmGetInDragMode(Widget widget);
77 extern void _XmPrimitiveEnter(Widget wid,
78 			      XEvent * event,
79 			      String * params, Cardinal * num_params);
80 extern void _XmPrimitiveLeave(Widget wid,
81 			      XEvent * event,
82 			      String * params, Cardinal * num_params);
83 extern void _XmSetFocusFlag(Widget w, unsigned int mask, Boolean value);
84 extern void _XmCalcLabelDimensions(Widget wid);
85 
86 /*
87  * Declaration of class methods.
88  */
89 static void Destroy(Widget w);
90 static void Initialize(Widget rq, Widget eb, ArgList args, Cardinal *n);
91 static Boolean SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *n);
92 static void Redisplay(Widget, XEvent *, Region);
93 
94 /*
95  * Declaration of action methods.
96  */
97 static void Enter(Widget, XEvent *, String *, Cardinal *);
98 static void Leave(Widget, XEvent *, String *, Cardinal *);
99 static void BorderHighlight(Widget);
100 static void BorderUnhighlight(Widget);
101 
102 /*
103  * 4 x 4 stipple for desensitized widgets
104  */
105 #define stipple_width  4
106 #define stipple_height 4
107 static char stipple_bits[] = { 0x0a, 0x05, 0x0a, 0x05 };
108 #define STIPPLE_BITMAP	xmEnhancedButtonClassRec.enhancedbutton_class.stipple_bitmap
109 
110 /*
111  * Override actions.
112  */
113 static XtActionsRec actionsList[] =
114 {
115     {"Enter", Enter},
116     {"Leave", Leave},
117 };
118 
119 static XtResource resources[] =
120 {
121     {
122 	XmNpixmapData, XmCPixmap, XmRString, sizeof(String),
123 	XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.pixmap_data),
124 	XmRImmediate, (XtPointer) NULL
125     }, {
126 	XmNpixmapFile, XmCPixmap, XmRString, sizeof(String),
127 	XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.pixmap_file),
128 	XmRImmediate, (XtPointer) NULL
129     }, {
130 	XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof(Dimension),
131 	XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.spacing),
132 	XmRImmediate, (XtPointer) 2
133     },
134     {
135 	XmNlabelLocation, XmCLocation, XmRInt, sizeof(int),
136 	XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.label_location),
137 	XtRImmediate, (XtPointer) XmRIGHT
138     }
139 };
140 
141 /* This is needed to work around a bug in Lesstif 2, leaving the extension
142  * NULL somehow results in getting it set to an invalid pointer. */
143 XmPrimitiveClassExtRec xmEnhancedButtonPrimClassExtRec =
144 {
145     /* next_extension      */ NULL,
146     /* record_type	   */ NULLQUARK,
147     /* version		   */ XmPrimitiveClassExtVersion,
148     /* record_size	   */ sizeof(XmPrimitiveClassExtRec),
149     /* widget_baseline	   */ XmInheritBaselineProc,
150     /* widget_display_rect */ XmInheritDisplayRectProc,
151     /* widget_margins      */ NULL
152 };
153 
154 XmEnhancedButtonClassRec xmEnhancedButtonClassRec =
155 {
156     {
157 	/* core_class fields */
158 	/* superclass		 */ (WidgetClass) & xmPushButtonClassRec,
159 	/* class_name		 */ "XmEnhancedButton",
160 	/* widget_size		 */ sizeof(XmEnhancedButtonRec),
161 	/* class_initialize	 */ NULL,
162 	/* class_part_initialize */ NULL,
163 	/* class_inited		 */ False,
164 	/* initialize		 */ Initialize,
165 	/* initialize_hook	 */ NULL,
166 	/* realize		 */ XtInheritRealize,
167 	/* actions		 */ actionsList,
168 	/* num_actions		 */ XtNumber(actionsList),
169 	/* resources		 */ resources,
170 	/* num_resources	 */ XtNumber(resources),
171 	/* xrm_class		 */ NULLQUARK,
172 	/* compress_motion	 */ True,
173 	/* compress_exposure	 */ XtExposeCompressMaximal,
174 	/* compress_enterleave	 */ True,
175 	/* visible_interest	 */ False,
176 	/* destroy		 */ Destroy,
177 	/* resize		 */ XtInheritResize,
178 	/* expose		 */ Redisplay,
179 	/* set_values		 */ SetValues,
180 	/* set_values_hook	 */ NULL,
181 	/* set_values_almost	 */ XtInheritSetValuesAlmost,
182 	/* get_values_hook	 */ NULL,
183 	/* accept_focus		 */ XtInheritAcceptFocus,
184 	/* version		 */ XtVersion,
185 	/* callback_private	 */ NULL,
186 	/* tm_table		 */ NULL,
187 	/* query_geometry	 */ NULL,
188 	/* display_accelerator	 */ XtInheritDisplayAccelerator,
189 	/* extension		 */ NULL
190     },
191 
192     /* primitive_class fields */
193     {
194 	/* border highlight	 */ BorderHighlight,
195 	/* border_unhighlight	 */ BorderUnhighlight,
196 	/* translations		 */ XtInheritTranslations,
197 	/* arm and activate	 */ XmInheritArmAndActivate,
198 	/* synthetic resources	 */ NULL,
199 	/* number of syn res	 */ 0,
200 	/* extension		 */ (XtPointer)&xmEnhancedButtonPrimClassExtRec,
201     },
202 
203     /* label_class fields */
204     {
205 	/* setOverrideCallback	 */ XmInheritSetOverrideCallback,
206 	/* menuProcs		 */ XmInheritMenuProc,
207 	/* translations		 */ XtInheritTranslations,
208 	/* extension		 */ NULL,
209     },
210 
211     /* pushbutton_class record */
212     {
213 	/* extension		 */ (XtPointer) NULL,
214     },
215 
216     /* enhancedbutton_class fields */
217     {
218 	/* stipple_bitmap	 */ None
219     }
220 };
221 
222 
223 WidgetClass xmEnhancedButtonWidgetClass =
224 				       (WidgetClass)&xmEnhancedButtonClassRec;
225 
226 
227 /*
228  * Create a slightly fainter pixmap to be shown on button entry.
229  */
230     static unsigned short
231 bump_color(unsigned short value)
232 {
233     int tmp = 2 * (((int) value - 65535) / 3) + 65535;
234 
235     return tmp;
236 }
237 
238     static int
239 alloc_color(Display	*display,
240 	Colormap	colormap,
241 	char		*colorname,
242 	XColor		*xcolor,
243 	void		*closure UNUSED)
244 {
245     int status;
246 
247     if (colorname)
248 	if (!XParseColor(display, colormap, colorname, xcolor))
249 	    return -1;
250 
251     xcolor->red = bump_color(xcolor->red);
252     xcolor->green = bump_color(xcolor->green);
253     xcolor->blue = bump_color(xcolor->blue);
254 
255     status = XAllocColor(display, colormap, xcolor);
256     return status != 0 ? 1 : 0;
257 }
258 
259 /* XPM */
260 static char * blank_xpm[] =
261 {
262 /* width height ncolors cpp [x_hot y_hot] */
263 "12 12 4 1 0 0",
264 /* colors */
265 " 	s iconColor1	m black	c #000000",
266 ".	s none	m none	c none",
267 "X	s topShadowColor	m none	c #DCDEE5",
268 "o	s bottomShadowColor	m black	c #5D6069",
269 /* pixels */
270 "          ..",
271 " XXXXXXXX ..",
272 " X....... o.",
273 " X....... o.",
274 " X....... o.",
275 " X....... o.",
276 " X....... o.",
277 " X....... o.",
278 " X....... o.",
279 "          o.",
280 "..ooooooooo.",
281 "............"};
282 
283 /*
284  * Set the pixmap.
285  */
286     static void
287 set_pixmap(XmEnhancedButtonWidget eb)
288 {
289     /* Configure defines XPMATTRIBUTES_TYPE as XpmAttributes or as
290      * XpmAttributes_21, depending on what is in Xm/XpmP.h. */
291     XPMATTRIBUTES_TYPE   attr;
292     Pixmap	    sen_pix;
293     Window	    root;
294     static XpmColorSymbol color[8] = {
295 	{"none", "none", 0},
296 	{"None", "none", 0},
297 	{"background", NULL, 0},
298 	{"foreground", NULL, 0},
299 	{"bottomShadowColor", NULL, 0},
300 	{"topShadowColor", NULL, 0},
301 	{"highlightColor", NULL, 0},
302 	{"armColor", NULL, 0}
303     };
304     int		    scr;
305     Display	    *dpy = XtDisplay(eb);
306     int		    x;
307     int		    y;
308     unsigned int    height, width, border, depth;
309     int		    status = 0;
310     Pixmap	    mask;
311     Pixmap	    pix = None;
312     Pixmap	    arm_pix = None;
313     Pixmap	    ins_pix = None;
314     Pixmap	    high_pix = None;
315     char	    **data = (char **) eb->enhancedbutton.pixmap_data;
316     char	    *fname = (char *) eb->enhancedbutton.pixmap_file;
317     int		    shift;
318     GC		    gc;
319 
320     /* Make sure there is a default value for the pixmap.
321      */
322     if (!data)
323 	return;
324 
325     gc = XtGetGC((Widget)eb, (XtGCMask)0, NULL);
326 
327     scr = DefaultScreen(dpy);
328     root = RootWindow(dpy, scr);
329 
330     eb->label.pixmap = None;
331 
332     eb->enhancedbutton.pixmap_depth = 0;
333     eb->enhancedbutton.pixmap_width = 0;
334     eb->enhancedbutton.pixmap_height = 0;
335     eb->enhancedbutton.normal_pixmap = None;
336     eb->enhancedbutton.armed_pixmap = None;
337     eb->enhancedbutton.highlight_pixmap = None;
338     eb->enhancedbutton.insensitive_pixmap = None;
339 
340     /* We use dynamic colors, get them now. */
341     motif_get_toolbar_colors(
342 	    &eb->core.background_pixel,
343 	    &eb->primitive.foreground,
344 	    &eb->primitive.bottom_shadow_color,
345 	    &eb->primitive.top_shadow_color,
346 	    &eb->primitive.highlight_color);
347 
348     /* Setup color substitution table. */
349     color[0].pixel = eb->core.background_pixel;
350     color[1].pixel = eb->core.background_pixel;
351     color[2].pixel = eb->core.background_pixel;
352     color[3].pixel = eb->primitive.foreground;
353     color[4].pixel = eb->core.background_pixel;
354     color[5].pixel = eb->primitive.top_shadow_color;
355     color[6].pixel = eb->primitive.highlight_color;
356     color[7].pixel = eb->pushbutton.arm_color;
357 
358     /* Create the "sensitive" pixmap. */
359     attr.valuemask = XpmColorSymbols | XpmCloseness;
360     attr.closeness = 65535;	/* accuracy isn't crucial */
361     attr.colorsymbols = color;
362     attr.numsymbols = XtNumber(color);
363 
364     if (fname)
365 	status = XpmReadFileToPixmap(dpy, root, fname, &pix, &mask, &attr);
366     if (!fname || status != XpmSuccess)
367 	status = XpmCreatePixmapFromData(dpy, root, data, &pix, &mask, &attr);
368 
369     /* If something failed, we will fill in the default pixmap. */
370     if (status != XpmSuccess)
371 	status = XpmCreatePixmapFromData(dpy, root, blank_xpm, &pix,
372 								&mask, &attr);
373 
374     XpmFreeAttributes(&attr);
375 
376     XGetGeometry(dpy, pix, &root, &x, &y, &width, &height, &border, &depth);
377 
378     /* TODO: does the shift depend on label_location somehow? */
379     shift = eb->primitive.shadow_thickness / 2;
380 
381     if (shift < 1)
382 	shift = 1;
383 
384     sen_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth);
385 
386     XSetForeground(dpy, gc, eb->core.background_pixel);
387     XFillRectangle(dpy, sen_pix, gc, 0, 0, width + shift, height + shift);
388     XSetClipMask(dpy, gc, mask);
389     XSetClipOrigin(dpy, gc, shift, shift);
390     XCopyArea(dpy, pix, sen_pix, gc, 0, 0, width, height, shift, shift);
391 
392     /* Create the "highlight" pixmap. */
393     color[4].pixel = eb->primitive.bottom_shadow_color;
394 #ifdef XpmAllocColor /* SGI doesn't have it */
395     attr.valuemask = XpmColorSymbols | XpmCloseness | XpmAllocColor;
396     attr.alloc_color = alloc_color;
397 #else
398     attr.valuemask = XpmColorSymbols | XpmCloseness;
399 #endif
400     attr.closeness = 65535;	/* accuracy isn't crucial */
401     attr.colorsymbols = color;
402     attr.numsymbols = XtNumber(color);
403 
404     status = XpmCreatePixmapFromData(dpy, root, data, &pix, NULL, &attr);
405     XpmFreeAttributes(&attr);
406 
407     high_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth);
408 
409 #if 1
410     XSetForeground(dpy, gc, eb->core.background_pixel);
411 #else
412     XSetForeground(dpy, gc, eb->primitive.top_shadow_color);
413 #endif
414     XSetClipMask(dpy, gc, None);
415     XFillRectangle(dpy, high_pix, gc, 0, 0, width + shift, height + shift);
416     XSetClipMask(dpy, gc, mask);
417     XSetClipOrigin(dpy, gc, 0, 0);
418     XCopyArea(dpy, pix, high_pix, gc, 0, 0, width, height, 0, 0);
419 
420     arm_pix = XCreatePixmap(dpy, pix, width + shift, height + shift, depth);
421 
422     if (eb->pushbutton.fill_on_arm)
423 	XSetForeground(dpy, gc, eb->pushbutton.arm_color);
424     else
425 	XSetForeground(dpy, gc, eb->core.background_pixel);
426     XSetClipOrigin(dpy, gc, shift, shift);
427     XSetClipMask(dpy, gc, None);
428     XFillRectangle(dpy, arm_pix, gc, 0, 0, width + shift, height + shift);
429     XSetClipMask(dpy, gc, mask);
430     XSetClipOrigin(dpy, gc, 2 * shift, 2 * shift);
431     XCopyArea(dpy, pix, arm_pix, gc, 0, 0, width, height, 2 * shift, 2 * shift);
432 
433     XFreePixmap(dpy, pix);
434     XFreePixmap(dpy, mask);
435 
436     /* Create the "insensitive" pixmap. */
437     attr.valuemask = XpmColorSymbols | XpmCloseness | XpmColorKey;
438     attr.closeness = 65535;	/* accuracy isn't crucial */
439     attr.colorsymbols = color;
440     attr.numsymbols = sizeof(color) / sizeof(color[0]);
441     attr.color_key = XPM_MONO;
442     status = XpmCreatePixmapFromData(dpy, root, data, &pix, &mask, &attr);
443 
444     /* Need to create new Pixmaps with the mask applied. */
445 
446     ins_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth);
447 
448     XSetForeground(dpy, gc, eb->core.background_pixel);
449     XSetClipOrigin(dpy, gc, 0, 0);
450     XSetClipMask(dpy, gc, None);
451     XFillRectangle(dpy, ins_pix, gc, 0, 0, width + shift, height + shift);
452     XSetClipMask(dpy, gc, mask);
453     XSetForeground(dpy, gc, eb->primitive.top_shadow_color);
454     XSetClipOrigin(dpy, gc, 2 * shift, 2 * shift);
455     XFillRectangle(dpy, ins_pix, gc, 2 * shift, 2 * shift, width, height);
456     XSetForeground(dpy, gc, eb->primitive.bottom_shadow_color);
457     XSetClipOrigin(dpy, gc, shift, shift);
458     XFillRectangle(dpy, ins_pix, gc, 0, 0, width + shift, height + shift);
459     XtReleaseGC((Widget) eb, gc);
460 
461     XpmFreeAttributes(&attr);
462 
463     eb->enhancedbutton.pixmap_depth = depth;
464     eb->enhancedbutton.pixmap_width = width;
465     eb->enhancedbutton.pixmap_height = height;
466     eb->enhancedbutton.normal_pixmap = sen_pix;
467     eb->enhancedbutton.highlight_pixmap = high_pix;
468     eb->enhancedbutton.insensitive_pixmap = ins_pix;
469     eb->enhancedbutton.armed_pixmap = arm_pix;
470 
471     eb->enhancedbutton.doing_setvalues = True;
472     eb->enhancedbutton.doing_setvalues = False;
473 
474     XFreePixmap(dpy, pix);
475     XFreePixmap(dpy, mask);
476 }
477 
478 #define	BUTTON_MASK ( \
479 	Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask \
480 )
481 
482     static void
483 draw_shadows(XmEnhancedButtonWidget eb)
484 {
485     GC		top_gc;
486     GC		bottom_gc;
487     Boolean	etched_in;
488 
489     if (!eb->primitive.shadow_thickness)
490        return;
491 
492     if ((eb->core.width <= 2 * eb->primitive.highlight_thickness)
493 	    || (eb->core.height <= 2 * eb->primitive.highlight_thickness))
494 	return;
495 
496 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
497     {
498 	XmDisplay	dpy;
499 
500 	dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(eb));
501 	etched_in = dpy->display.enable_etched_in_menu;
502     }
503 #else
504     etched_in = False;
505 #endif
506     if (!etched_in ^ eb->pushbutton.armed)
507     {
508 	top_gc = eb->primitive.top_shadow_GC;
509 	bottom_gc = eb->primitive.bottom_shadow_GC;
510     }
511     else
512     {
513 	top_gc = eb->primitive.bottom_shadow_GC;
514 	bottom_gc = eb->primitive.top_shadow_GC;
515     }
516 
517     XmeDrawShadows(XtDisplay(eb), XtWindow(eb),
518 	    top_gc,
519 	    bottom_gc,
520 	    eb->primitive.highlight_thickness,
521 	    eb->primitive.highlight_thickness,
522 	    eb->core.width - 2 * eb->primitive.highlight_thickness,
523 	    eb->core.height - 2 * eb->primitive.highlight_thickness,
524 	    eb->primitive.shadow_thickness,
525 	    (unsigned)(etched_in ? XmSHADOW_IN : XmSHADOW_OUT));
526 }
527 
528     static void
529 draw_highlight(XmEnhancedButtonWidget eb)
530 {
531     eb->primitive.highlighted = True;
532     eb->primitive.highlight_drawn = True;
533 
534     if (!XtWidth(eb) || !XtHeight(eb) || !eb->primitive.highlight_thickness)
535 	return;
536 
537     XmeDrawHighlight(XtDisplay(eb), XtWindow(eb),
538 	    eb->primitive.highlight_GC, 0, 0,
539 	    XtWidth(eb), XtHeight(eb),
540 	    eb->primitive.highlight_thickness);
541 }
542 
543     static void
544 draw_unhighlight(XmEnhancedButtonWidget eb)
545 {
546     GC manager_background_GC;
547 
548     eb->primitive.highlighted = False;
549     eb->primitive.highlight_drawn = False;
550 
551     if (!XtWidth(eb) || !XtHeight(eb) || !eb->primitive.highlight_thickness)
552 	return;
553 
554     if (XmIsManager(eb->core.parent))
555     {
556 #ifdef UNHIGHLIGHTT
557 	XmSpecifyUnhighlightTrait UnhighlightT;
558 
559 	if (((UnhighlightT = (XmSpecifyUnhighlightTrait) XmeTraitGet((XtPointer)
560 			    XtClass(eb->core.parent), XmQTspecifyUnhighlight))
561 		    != NULL) && (UnhighlightT->getUnhighlightGC != NULL))
562 	{
563 	    /* if unhighlight trait in parent use specified GC... */
564 	    manager_background_GC =
565 		 UnhighlightT->getUnhighlightGC(eb->core.parent, (Widget) eb);
566 	}
567 	else
568 	{
569 	    /* ...otherwise, use parent's background GC */
570 	    manager_background_GC = ((XmManagerWidget)
571 				    (eb->core.parent))->manager.background_GC;
572 	}
573 #else
574 	manager_background_GC = ((XmManagerWidget)
575 				    (eb->core.parent))->manager.background_GC;
576 #endif
577 	XmeDrawHighlight(XtDisplay(eb), XtWindow(eb),
578 			 manager_background_GC,
579 			 0, 0, XtWidth(eb), XtHeight(eb),
580 			 eb->primitive.highlight_thickness);
581 	if (!eb->pushbutton.armed && eb->primitive.shadow_thickness)
582 	    XmeClearBorder(XtDisplay(eb), XtWindow(eb),
583 		    eb->primitive.highlight_thickness,
584 		    eb->primitive.highlight_thickness,
585 		    eb->core.width - 2 * eb->primitive.highlight_thickness,
586 		    eb->core.height - 2 * eb->primitive.highlight_thickness,
587 		    eb->primitive.shadow_thickness);
588     }
589     else
590 	XmeClearBorder(XtDisplay(eb), XtWindow(eb), 0, 0, XtWidth(eb),
591 		       XtHeight(eb), eb->primitive.highlight_thickness);
592 }
593 
594     static void
595 draw_pixmap(XmEnhancedButtonWidget eb,
596 	    XEvent *event UNUSED,
597 	    Region region UNUSED)
598 {
599     Pixmap	pix;
600     GC		gc = eb->label.normal_GC;
601     int		depth;
602     Cardinal	width;
603     Cardinal	height;
604     Cardinal	w;
605     Cardinal	h;
606     int		x;
607     int		y;
608 
609     if (!XtIsSensitive((Widget) eb))
610 	pix = eb->enhancedbutton.insensitive_pixmap;
611     else
612     {
613 	if (eb->primitive.highlighted && !eb->pushbutton.armed)
614 	    pix = eb->enhancedbutton.highlight_pixmap;
615 	else if (eb->pushbutton.armed)
616 	    pix = eb->enhancedbutton.armed_pixmap;
617 	else
618 	    pix = eb->enhancedbutton.normal_pixmap;
619     }
620 
621     if (pix == None || !eb->enhancedbutton.pixmap_data)
622 	return;
623 
624     depth = eb->enhancedbutton.pixmap_depth;
625     w = eb->enhancedbutton.pixmap_width;
626     h = eb->enhancedbutton.pixmap_height;
627 
628     gc = eb->label.normal_GC;
629     x = eb->primitive.highlight_thickness
630 	+ eb->primitive.shadow_thickness
631 	+ eb->label.margin_width;
632     y = eb->primitive.highlight_thickness
633 	+ eb->primitive.shadow_thickness
634 	+ eb->label.margin_height;
635     width = eb->core.width - 2 * x;
636     if (w < width)
637 	width = w;
638     height = eb->core.height - 2 * y;
639     if (h < height)
640 	height = h;
641     if (depth == (int)eb->core.depth)
642 	XCopyArea(XtDisplay(eb), pix, XtWindow(eb), gc, 0, 0,
643 		width, height, x, y);
644     else if (depth == 1)
645 	XCopyPlane(XtDisplay(eb), pix, XtWindow(eb), gc, 0, 0,
646 		width, height, x, y, (unsigned long)1);
647 }
648 
649 /*
650  * Draw the label contained in the pushbutton.
651  */
652     static void
653 draw_label(XmEnhancedButtonWidget eb, XEvent *event, Region region)
654 {
655     GC		tmp_gc = NULL;
656     Boolean	replaceGC = False;
657     Boolean	deadjusted = False;
658 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
659     XmDisplay	dpy = (XmDisplay)XmGetXmDisplay(XtDisplay(eb));
660     Boolean	etched_in = dpy->display.enable_etched_in_menu;
661 #else
662     Boolean	etched_in = False;
663 #endif
664 
665     if (eb->pushbutton.armed
666 	    && ((!Lab_IsMenupane(eb) && eb->pushbutton.fill_on_arm)
667 		|| (Lab_IsMenupane(eb) && etched_in)))
668     {
669 	if (eb->label.label_type == (int)XmSTRING
670 		&& eb->pushbutton.arm_color == eb->primitive.foreground)
671 	{
672 	    tmp_gc = eb->label.normal_GC;
673 	    eb->label.normal_GC = eb->pushbutton.background_gc;
674 	    replaceGC = True;
675 	}
676     }
677 
678     /*
679      * If the button contains a labeled pixmap, we will take it instead of our
680      * own pixmap.
681      */
682 
683     if (eb->label.label_type == (int)XmPIXMAP)
684     {
685 	if (eb->pushbutton.armed)
686 	{
687 	    if (eb->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP)
688 		eb->label.pixmap = eb->pushbutton.arm_pixmap;
689 	    else
690 		eb->label.pixmap = eb->pushbutton.unarm_pixmap;
691 	}
692 	else
693 	    /* pushbutton is not armed */
694 	    eb->label.pixmap = eb->pushbutton.unarm_pixmap;
695     }
696 
697     /*
698      *	Temporarily remove the Xm3D_ENHANCE_PIXEL hack ("adjustment") from the
699      *	margin values, so we don't confuse Label.
700      */
701     if (eb->pushbutton.default_button_shadow_thickness > 0)
702     {
703 	deadjusted = True;
704 	Lab_MarginLeft(eb) -= Xm3D_ENHANCE_PIXEL;
705 	Lab_MarginRight(eb) -= Xm3D_ENHANCE_PIXEL;
706 	Lab_MarginTop(eb) -= Xm3D_ENHANCE_PIXEL;
707 	Lab_MarginBottom(eb) -= Xm3D_ENHANCE_PIXEL;
708     }
709 
710     {
711 	XtExposeProc expose;
712 
713 	XtProcessLock();
714 	expose = xmLabelClassRec.core_class.expose;
715 	XtProcessUnlock();
716 	(*expose)((Widget) eb, event, region);
717     }
718 
719     if (deadjusted)
720     {
721 	Lab_MarginLeft(eb) += Xm3D_ENHANCE_PIXEL;
722 	Lab_MarginRight(eb) += Xm3D_ENHANCE_PIXEL;
723 	Lab_MarginTop(eb) += Xm3D_ENHANCE_PIXEL;
724 	Lab_MarginBottom(eb) += Xm3D_ENHANCE_PIXEL;
725     }
726 
727     if (replaceGC)
728 	eb->label.normal_GC = tmp_gc;
729 }
730 
731     static void
732 Enter(Widget wid,
733       XEvent *event,
734       String *params UNUSED,
735       Cardinal *num_params UNUSED)
736 {
737     XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget) wid;
738     XmPushButtonCallbackStruct call_value;
739 
740     if (Lab_IsMenupane(eb))
741     {
742 	if ((((ShellWidget) XtParent(XtParent(eb)))->shell.popped_up)
743 		&& _XmGetInDragMode((Widget) eb))
744 	{
745 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
746 	    XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid));
747 	    Boolean etched_in = dpy->display.enable_etched_in_menu;
748 #else
749 	    Boolean etched_in = False;
750 #endif
751 
752 	    if (eb->pushbutton.armed)
753 		return;
754 
755 	    /* ...so KHelp event is delivered correctly. */
756 	    _XmSetFocusFlag(XtParent(XtParent(eb)), XmFOCUS_IGNORE, TRUE);
757 	    XtSetKeyboardFocus(XtParent(XtParent(eb)), (Widget) eb);
758 	    _XmSetFocusFlag(XtParent(XtParent(eb)), XmFOCUS_IGNORE, FALSE);
759 
760 	    eb->pushbutton.armed = TRUE;
761 
762 	    ((XmManagerWidget) XtParent(wid))->manager.active_child = wid;
763 
764 	    /* etched in menu button */
765 	    if (etched_in && !XmIsTearOffButton(eb))
766 	    {
767 		XFillRectangle(XtDisplay(eb), XtWindow(eb),
768 			       eb->pushbutton.fill_gc,
769 			       0, 0, eb->core.width, eb->core.height);
770 		draw_label(eb, event, NULL);
771 		draw_pixmap(eb, event, NULL);
772 	    }
773 
774 	    if ((eb->core.width > 2 * eb->primitive.highlight_thickness)
775 		    && (eb->core.height >
776 				       2 * eb->primitive.highlight_thickness))
777 	    {
778 		XmeDrawShadows(XtDisplay(eb), XtWindow(eb),
779 			eb->primitive.top_shadow_GC,
780 			eb->primitive.bottom_shadow_GC,
781 			eb->primitive.highlight_thickness,
782 			eb->primitive.highlight_thickness,
783 			eb->core.width - 2 * eb->primitive.highlight_thickness,
784 			eb->core.height - 2 * eb->primitive.highlight_thickness,
785 			eb->primitive.shadow_thickness,
786 			(unsigned)(etched_in ? XmSHADOW_IN : XmSHADOW_OUT));
787 	    }
788 
789 	    if (eb->pushbutton.arm_callback)
790 	    {
791 		XFlush(XtDisplay(eb));
792 
793 		call_value.reason = (int)XmCR_ARM;
794 		call_value.event = event;
795 		XtCallCallbackList((Widget) eb,
796 				   eb->pushbutton.arm_callback,
797 				   &call_value);
798 	    }
799 	}
800     }
801     else
802     {
803 	XtExposeProc expose;
804 
805 	_XmPrimitiveEnter((Widget) eb, event, NULL, NULL);
806 	if (eb->pushbutton.armed == TRUE)
807 	{
808 	    XtProcessLock();
809 	    expose = XtClass(eb)->core_class.expose;
810 	    XtProcessUnlock();
811 	    (*expose) (wid, event, (Region) NULL);
812 	}
813 
814 	draw_highlight(eb);
815 	draw_shadows(eb);
816 	draw_pixmap(eb, event, NULL);
817     }
818 }
819 
820     static void
821 Leave(Widget wid,
822       XEvent *event,
823       String *params UNUSED,
824       Cardinal *num_params UNUSED)
825 {
826     XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)wid;
827     XmPushButtonCallbackStruct call_value;
828 
829     if (Lab_IsMenupane(eb))
830     {
831 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
832 	XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid));
833 	Boolean etched_in = dpy->display.enable_etched_in_menu;
834 #else
835 	Boolean etched_in = False;
836 #endif
837 
838 	if (_XmGetInDragMode((Widget)eb)
839 		&& eb->pushbutton.armed
840 		&& ( /* !ActiveTearOff || */
841 				       event->xcrossing.mode == NotifyNormal))
842 	{
843 	    eb->pushbutton.armed = FALSE;
844 
845 	    ((XmManagerWidget) XtParent(wid))->manager.active_child = NULL;
846 
847 	    if (etched_in && !XmIsTearOffButton(eb))
848 	    {
849 		XFillRectangle(XtDisplay(eb), XtWindow(eb),
850 			       eb->pushbutton.background_gc,
851 			       0, 0, eb->core.width, eb->core.height);
852 		draw_label(eb, event, NULL);
853 		draw_pixmap(eb, event, NULL);
854 	    }
855 	    else
856 		XmeClearBorder
857 		    (XtDisplay(eb), XtWindow(eb),
858 		     eb->primitive.highlight_thickness,
859 		     eb->primitive.highlight_thickness,
860 		     eb->core.width -
861 		     2 * eb->primitive.highlight_thickness,
862 		     eb->core.height -
863 		     2 * eb->primitive.highlight_thickness,
864 		     eb->primitive.shadow_thickness);
865 
866 	    if (eb->pushbutton.disarm_callback)
867 	    {
868 		XFlush(XtDisplay(eb));
869 
870 		call_value.reason = (int)XmCR_DISARM;
871 		call_value.event = event;
872 		XtCallCallbackList((Widget) eb,
873 				   eb->pushbutton.disarm_callback,
874 				   &call_value);
875 	    }
876 	}
877     }
878     else
879     {
880 	_XmPrimitiveLeave((Widget) eb, event, NULL, NULL);
881 
882 	if (eb->pushbutton.armed == TRUE)
883 	{
884 	    XtExposeProc expose;
885 	    eb->pushbutton.armed = FALSE;
886 	    XtProcessLock();
887 	    expose = XtClass(eb)->core_class.expose;
888 	    XtProcessUnlock();
889 	    (*expose) (wid, event, (Region)NULL);
890 	    draw_unhighlight(eb);
891 	    draw_pixmap(eb, event, NULL);
892 	    eb->pushbutton.armed = TRUE;
893 	}
894 	else
895 	{
896 	    draw_unhighlight(eb);
897 	    draw_pixmap(eb, event, NULL);
898 	}
899     }
900 }
901 
902 #define IsNull(p)   ((p) == XmUNSPECIFIED_PIXMAP)
903 
904     static void
905 set_size(XmEnhancedButtonWidget newtb)
906 {
907     unsigned int w = 0;
908     unsigned int h = 0;
909 
910     _XmCalcLabelDimensions((Widget) newtb);
911 
912     /* Find out how big the pixmap is */
913     if (newtb->enhancedbutton.pixmap_data
914 	    && !IsNull(newtb->label.pixmap)
915 	    && !IsNull(newtb->enhancedbutton.normal_pixmap))
916     {
917 	w = newtb->enhancedbutton.pixmap_width;
918 	h = newtb->enhancedbutton.pixmap_height;
919     }
920 
921     /*
922      * Please note that we manipulate the width only in case of push buttons
923      * not used in the context of a menu pane.
924      */
925     if (Lab_IsMenupane(newtb))
926     {
927 	newtb->label.margin_left = w + 2 * (newtb->primitive.shadow_thickness
928 		+ newtb->primitive.highlight_thickness)
929 	    + newtb->label.margin_width;
930     }
931     else
932     {
933 	newtb->label.margin_left = w;
934 	newtb->core.width = w + 2 * (newtb->primitive.shadow_thickness
935 		+ newtb->primitive.highlight_thickness
936 		+ newtb->label.margin_width)
937 	    + newtb->label.TextRect.width;
938 
939 	if (newtb->label.TextRect.width > 0)
940 	{
941 	    newtb->label.margin_left += newtb->label.margin_width
942 					  + newtb->primitive.shadow_thickness;
943 	    newtb->core.width += newtb->label.margin_width
944 					  + newtb->primitive.shadow_thickness;
945 	}
946     }
947     if (newtb->label.TextRect.height < h)
948     {
949 	newtb->core.height = h  + 2 * (newtb->primitive.shadow_thickness
950 		+ newtb->primitive.highlight_thickness
951 		+ newtb->label.margin_height);
952     }
953     else
954     {
955 	/* FIXME: We should calculate an drawing offset for the pixmap here to
956 	 * adjust it.  */
957     }
958 
959 #if 0
960     printf("%d %d %d %d %d %d - %d %d\n", newtb->enhancedbutton.normal_pixmap,
961 	    h, newtb->core.height,
962 	    newtb->primitive.shadow_thickness,
963 	    newtb->primitive.highlight_thickness,
964 	    newtb->label.margin_height,
965 	    newtb->core.width,
966 	    newtb->core.height);
967 #endif
968 
969     /* Invoke Label's Resize procedure. */
970     {
971 	XtWidgetProc resize;
972 	XtProcessLock();
973 	resize = xmLabelClassRec.core_class.resize;
974 	XtProcessUnlock();
975 
976 	(* resize) ((Widget) newtb);
977     }
978 }
979 
980     static void
981 Initialize(Widget rq, Widget ebw, ArgList args UNUSED, Cardinal *n UNUSED)
982 {
983     XmEnhancedButtonWidget  request = (XmEnhancedButtonWidget)rq;
984     XmEnhancedButtonWidget  eb = (XmEnhancedButtonWidget)ebw;
985     XtWidgetProc	    resize;
986 
987     XtProcessLock();
988     resize = xmLabelClassRec.core_class.resize;
989     XtProcessUnlock();
990 
991     /* Create a bitmap for stippling (Drawable resources are cheap).  */
992     if (STIPPLE_BITMAP == None)
993     {
994 	Display *dpy = XtDisplay((Widget) request);
995 	Window	rootW = DefaultRootWindow(dpy);
996 
997 	STIPPLE_BITMAP = XCreateBitmapFromData(dpy, rootW, stipple_bits,
998 		stipple_width, stipple_height);
999     }
1000     eb->enhancedbutton.doing_setvalues = False;
1001 
1002     /* First see what type of extended label this is.
1003      */
1004     if (eb->enhancedbutton.pixmap_data)
1005     {
1006 	XmString str;
1007 	set_pixmap(eb);
1008 
1009 	/* FIXME: this is not the perfect way to deal with menus, which do not
1010 	 * have any string set right now.  */
1011 	str = XmStringCreateLocalized("");
1012 	XtVaSetValues((Widget) eb, XmNlabelString, str, NULL);
1013 	XmStringFree(str);
1014     }
1015     eb->label.pixmap = eb->enhancedbutton.normal_pixmap;
1016 
1017     if (request->core.width == 0)
1018 	eb->core.width = 0;
1019     if (request->core.height == 0)
1020 	eb->core.height = 0;
1021     set_size(eb);
1022 
1023     (* resize)((Widget)eb);
1024 }
1025 
1026     static void
1027 free_pixmaps(XmEnhancedButtonWidget eb)
1028 {
1029     /*
1030      * Clear the old pixmaps.
1031      */
1032     Pixmap norm_pix = eb->enhancedbutton.normal_pixmap;
1033     Pixmap arm_pix = eb->enhancedbutton.armed_pixmap;
1034     Pixmap insen_pix = eb->enhancedbutton.insensitive_pixmap;
1035     Pixmap high_pix = eb->enhancedbutton.highlight_pixmap;
1036 
1037     if (norm_pix != None && norm_pix != XmUNSPECIFIED_PIXMAP)
1038 	XFreePixmap(XtDisplay(eb), norm_pix);
1039 
1040     if (arm_pix != None && arm_pix != XmUNSPECIFIED_PIXMAP)
1041 	XFreePixmap(XtDisplay(eb), arm_pix);
1042 
1043     if (insen_pix != None && insen_pix != XmUNSPECIFIED_PIXMAP)
1044 	XFreePixmap(XtDisplay(eb), insen_pix);
1045 
1046     if (high_pix != None && high_pix != XmUNSPECIFIED_PIXMAP)
1047 	XFreePixmap(XtDisplay(eb), high_pix);
1048 }
1049 
1050     static void
1051 Destroy(Widget w)
1052 {
1053     if (!XmIsEnhancedButton(w))
1054 	return;
1055 
1056     free_pixmaps((XmEnhancedButtonWidget)w);
1057 }
1058 
1059     static Boolean
1060 SetValues(Widget current,
1061 	  Widget request UNUSED,
1062 	  Widget new,
1063 	  ArgList args UNUSED,
1064 	  Cardinal *n UNUSED)
1065 {
1066     XmEnhancedButtonWidget  cur = (XmEnhancedButtonWidget) current;
1067     XmEnhancedButtonWidget  eb = (XmEnhancedButtonWidget) new;
1068     Boolean		    redraw = False;
1069     Boolean		    change = True;
1070     Display		    *dpy = XtDisplay(current);
1071 
1072 #define NOT_EQUAL(field)       (cur->field != eb->field)
1073 
1074     /*
1075      * Make sure that lost sensitivity is causing the border to vanish as well.
1076      */
1077     if (NOT_EQUAL(core.sensitive) && !Lab_IsMenupane(current))
1078     {
1079 	if (cur->core.sensitive == True)
1080 	{
1081 	    draw_unhighlight(eb);
1082 	}
1083 	else
1084 	{
1085 	    int		    r_x;
1086 	    int		    r_y;
1087 	    unsigned int    r_height;
1088 	    unsigned int    r_width;
1089 	    unsigned int    r_border;
1090 	    unsigned int    r_depth;
1091 	    int		    root_x;
1092 	    int		    root_y;
1093 	    int		    win_x;
1094 	    int		    win_y;
1095 	    Window	    root;
1096 	    Window	    root_q;
1097 	    Window	    child;
1098 	    unsigned int    mask;
1099 
1100 	    /*
1101 	     * Artificially let the highlight appear if the mouse is over us.
1102 	     */
1103 	    /* Best way to get the root window of object: */
1104 	    XGetGeometry(dpy, XtWindow(cur), &root, &r_x, &r_y, &r_width,
1105 			 &r_height, &r_border, &r_depth);
1106 	    XQueryPointer(XtDisplay(cur), XtWindow(cur), &root_q, &child,
1107 			  &root_x, &root_y, &win_x, &win_y, &mask);
1108 
1109 	    if (root == root_q)
1110 	    {
1111 		if ((win_x < 0) || (win_y < 0))
1112 		    return False;
1113 
1114 		if ((win_x > (int)r_width) || (win_y > (int)r_height))
1115 		    return False;
1116 		draw_highlight(eb);
1117 		draw_shadows(eb);
1118 	    }
1119 	}
1120 
1121 	return True;
1122     }
1123 
1124     /*
1125      * Check for changed ExtLabelString.
1126      */
1127     if (NOT_EQUAL(primitive.shadow_thickness))
1128     {
1129 	redraw = True;
1130 	/* Don't change the pixmaps */
1131 	change = False;
1132     }
1133 
1134     if (NOT_EQUAL(primitive.foreground))
1135 	redraw = True;
1136     if (NOT_EQUAL(core.background_pixel))
1137 	redraw = True;
1138     if (NOT_EQUAL(pushbutton.fill_on_arm))
1139 	redraw = True;
1140     if (NOT_EQUAL(enhancedbutton.spacing))
1141 	redraw = True;
1142     if (NOT_EQUAL(enhancedbutton.label_location))
1143     {
1144 	redraw = True;
1145 	change = False;
1146     }
1147     if (NOT_EQUAL(label._label))
1148     {
1149 	redraw = True;
1150 	set_size(eb);
1151     }
1152 
1153     if (redraw == True)
1154     {
1155 	if (change)
1156 	    set_pixmap(eb);
1157 	if (eb->primitive.highlighted)
1158 	    eb->label.pixmap = eb->enhancedbutton.highlight_pixmap;
1159 	else
1160 	    eb->label.pixmap = eb->enhancedbutton.normal_pixmap;
1161 	if (change)
1162 	    set_size(eb);
1163 	redraw = False;
1164     }
1165 
1166     return redraw;
1167 }
1168 
1169     static void
1170 Redisplay(Widget w, XEvent *event, Region region)
1171 {
1172     XmEnhancedButtonWidget  eb = (XmEnhancedButtonWidget) w;
1173 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1174     XmDisplay		    dpy;
1175     XtEnum		    default_button_emphasis;
1176 #endif
1177     XRectangle		    box;
1178     int			    dx;
1179     int			    adjust;
1180     short		    fill = 0;
1181 
1182     if (!XtIsRealized((Widget)eb))
1183 	return;
1184 
1185 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1186     dpy = (XmDisplay)XmGetXmDisplay(XtDisplay(eb));
1187     default_button_emphasis = dpy->display.default_button_emphasis;
1188 #endif
1189 
1190     /*
1191      * Compute the area allocated to the label of the pushbutton; fill in the
1192      * dimensions in the box.
1193      */
1194 
1195     if ((eb->pushbutton.arm_color == eb->primitive.top_shadow_color)
1196 	    || (eb->pushbutton.arm_color == eb->primitive.bottom_shadow_color))
1197 	fill = 1;
1198 
1199     if (eb->pushbutton.compatible)
1200 	adjust = eb->pushbutton.show_as_default;
1201     else
1202 	adjust = eb->pushbutton.default_button_shadow_thickness;
1203 
1204     if (adjust > 0)
1205     {
1206 	adjust = adjust + eb->primitive.shadow_thickness;
1207 	adjust = (adjust << 1);
1208 	dx = eb->primitive.highlight_thickness + adjust + fill;
1209     }
1210     else
1211 	dx = (eb->primitive.highlight_thickness
1212 		+ eb->primitive.shadow_thickness + fill);
1213 
1214     box.x = dx;
1215     box.y = dx;
1216     adjust = (dx << 1);
1217     box.width  = eb->core.width - adjust;
1218     box.height = eb->core.height - adjust;
1219 
1220     /*
1221      * Redraw the background.
1222      */
1223     if (!Lab_IsMenupane(eb))
1224     {
1225 	GC  gc;
1226 
1227 	/* Don't shade if the button contains a label with a pixmap, since
1228 	 * there is no variant of the label available with the needed
1229 	 * background.
1230 	 */
1231 	if (eb->pushbutton.armed && eb->pushbutton.fill_on_arm)
1232 	{
1233 		if (eb->label.label_type == (int)XmPIXMAP)
1234 		{
1235 		    if (eb->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP)
1236 			gc = eb->pushbutton.fill_gc;
1237 		    else
1238 			gc = eb->pushbutton.background_gc;
1239 		}
1240 		else
1241 		    gc = eb->pushbutton.fill_gc;
1242 	}
1243 	else
1244 	    gc = eb->pushbutton.background_gc;
1245 	/* really need to fill with background if not armed ? */
1246 	if (gc)
1247 	    XFillRectangle(XtDisplay(eb), XtWindow(eb), gc,
1248 		    box.x, box.y, box.width, box.height);
1249     }
1250 
1251     draw_label(eb, event, region);
1252 
1253     if (Lab_IsMenupane(eb))
1254     {
1255 	if (eb->pushbutton.armed)
1256 	    (*(((XmPushButtonWidgetClass)XtClass(eb))
1257 	       ->primitive_class.border_highlight))(w);
1258 	draw_pixmap(eb, event, region);
1259     }
1260     else
1261     {
1262 	adjust = 0;
1263 
1264 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1265 	/*
1266 	 *  NOTE: PushButton has two types of shadows: primitive-shadow and
1267 	 *  default-button-shadow.  If pushbutton is in a menu only primitive
1268 	 *  shadows are drawn.
1269 	 */
1270 	switch (default_button_emphasis)
1271 	{
1272 	    case XmEXTERNAL_HIGHLIGHT:
1273 		adjust = (eb->primitive.highlight_thickness -
1274 			 (eb->pushbutton.default_button_shadow_thickness
1275 			  ?  Xm3D_ENHANCE_PIXEL : 0));
1276 		break;
1277 
1278 	    case XmINTERNAL_HIGHLIGHT:
1279 		break;
1280 
1281 	    default:
1282 		assert(FALSE);
1283 		return;
1284 	}
1285 #endif
1286 
1287 	/*
1288 	 * Clear the area not occupied by label with parents background color.
1289 	 * Label will invoke BorderUnhighlight() on the highlight_thickness
1290 	 * area, which is redundant when XmEXTERNAL_HIGHLIGHT default button
1291 	 * shadow emphasis is used.
1292 	 */
1293 	if (box.x > adjust)
1294 	{
1295 	    int borderwidth =box.x - adjust;
1296 	    int rectwidth = eb->core.width - 2 * adjust;
1297 	    int rectheight = eb->core.height - 2 * adjust;
1298 
1299 	    if (XmIsManager(XtParent(eb)))
1300 	    {
1301 		XmeDrawHighlight(XtDisplay(eb), XtWindow(eb),
1302 						     XmParentBackgroundGC(eb),
1303 			adjust, adjust, rectwidth, rectheight, borderwidth);
1304 	    }
1305 	    else
1306 	    {
1307 		XmeClearBorder(XtDisplay(eb), XtWindow(eb),
1308 			  adjust, adjust, rectwidth, rectheight, borderwidth);
1309 	    }
1310 
1311 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1312 	    switch (default_button_emphasis)
1313 	    {
1314 		case XmINTERNAL_HIGHLIGHT:
1315 		    /* The call above erases the border highlighting. */
1316 		    if (eb->primitive.highlight_drawn)
1317 			(*(((XmPushButtonWidgetClass) XtClass (eb))
1318 			   ->primitive_class.border_highlight)) ((Widget) eb) ;
1319 		    break;
1320 
1321 		default:
1322 		    break;
1323 	    }
1324 #endif
1325 	}
1326 
1327 	if (eb->pushbutton.default_button_shadow_thickness)
1328 	{
1329 	    if (eb->pushbutton.show_as_default)
1330 	    {
1331 		/*
1332 		 *  - get the topShadowColor and bottomShadowColor from the
1333 		 *  parent; use those colors to construct top and bottom gc;
1334 		 *  use these GCs to draw the shadows of the button.
1335 		 *
1336 		 *  - Should not be called if pushbutton is in a row column or
1337 		 *  in a menu.
1338 		 *
1339 		 *  - Should be called only if a defaultbuttonshadow is to be
1340 		 *  drawn.
1341 		 */
1342 		GC	    top_gc;
1343 		GC	    bottom_gc;
1344 		int	    default_button_shadow_thickness;
1345 		int	    x, y, width, height, delta;
1346 		Widget	    parent;
1347 
1348 		if (eb->pushbutton.compatible
1349 				     && (eb->pushbutton.show_as_default == 0))
1350 		    return;
1351 
1352 		if (!eb->pushbutton.compatible
1353 			&& (eb->pushbutton.default_button_shadow_thickness
1354 									== 0))
1355 		    return;
1356 
1357 		delta = eb->primitive.highlight_thickness;
1358 
1359 		/*
1360 		 * May need more complex computation for getting the GCs.
1361 		 */
1362 		parent = XtParent(eb);
1363 		if (XmIsManager(parent))
1364 		{
1365 		    /* Use the parent's GC so monochrome works. */
1366 		    bottom_gc = XmParentTopShadowGC(eb);
1367 		    top_gc = XmParentBottomShadowGC(eb);
1368 		}
1369 		else
1370 		{
1371 		    /* Use your own pixel for drawing. */
1372 		    bottom_gc = eb->primitive.top_shadow_GC;
1373 		    top_gc = eb->primitive.bottom_shadow_GC;
1374 		}
1375 
1376 		if ((bottom_gc == None) || (top_gc == None))
1377 		    return;
1378 
1379 
1380 		if (eb->pushbutton.compatible)
1381 		    default_button_shadow_thickness =
1382 					       eb->pushbutton.show_as_default;
1383 		else
1384 		    default_button_shadow_thickness =
1385 			       eb->pushbutton.default_button_shadow_thickness;
1386 
1387 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1388 		/*
1389 		 * Compute location of bounding box to contain the
1390 		 * defaultButtonShadow.
1391 		 */
1392 		switch (default_button_emphasis)
1393 		{
1394 		    case XmEXTERNAL_HIGHLIGHT:
1395 			delta = eb->primitive.highlight_thickness;
1396 			break;
1397 
1398 		    case XmINTERNAL_HIGHLIGHT:
1399 			delta = Xm3D_ENHANCE_PIXEL;
1400 			break;
1401 
1402 		    default:
1403 			assert(FALSE);
1404 			return;
1405 		}
1406 #endif
1407 
1408 		x = y = delta;
1409 		width = eb->core.width - 2 * delta;
1410 		height = eb->core.height - 2 * delta;
1411 
1412 		if ((width > 0) && (height > 0))
1413 		    XmeDrawShadows(XtDisplay(eb), XtWindow(eb),
1414 			    top_gc, bottom_gc, x, y, width, height,
1415 			    default_button_shadow_thickness,
1416 			    (unsigned)XmSHADOW_OUT);
1417 	    }
1418 	}
1419 
1420 	if (eb->primitive.highlight_drawn)
1421 	    draw_shadows(eb);
1422 	draw_pixmap(eb, event, region);
1423     }
1424 }
1425 
1426     static void
1427 BorderHighlight(Widget w)
1428 {
1429     XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)w;
1430 
1431     (*(xmPushButtonClassRec.primitive_class.border_highlight))(w);
1432     draw_pixmap(eb, NULL, NULL);
1433 }
1434 
1435     static void
1436 BorderUnhighlight(Widget w)
1437 {
1438     XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)w;
1439 
1440     (*(xmPushButtonClassRec.primitive_class.border_unhighlight))(w);
1441     draw_pixmap(eb, NULL, NULL);
1442 }
1443 
1444 #endif /* FEAT_TOOLBAR */
1445