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