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