/* 
 *  @OPENGROUP_COPYRIGHT@
 *  COPYRIGHT NOTICE
 *  Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
 *  Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
 *  ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
 *  the full copyright text.
 *  
 *  This software is subject to an open license. It may only be
 *  used on, with or for operating systems which are themselves open
 *  source systems. You must contact The Open Group for a license
 *  allowing distribution and sublicensing of this software on, with,
 *  or for operating systems which are not Open Source programs.
 *  
 *  See http://www.opengroup.org/openmotif/license for full
 *  details of the license agreement. Any use, reproduction, or
 *  distribution of the program constitutes recipient's acceptance of
 *  this agreement.
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
 *  PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 *  WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
 *  OR FITNESS FOR A PARTICULAR PURPOSE
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
 *  NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
 *  EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: ArrowBG.c /main/20 1999/01/26 15:30:15 mgreess $"
#endif
#endif
/* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */

#include <stdio.h>
#include <Xm/ArrowBGP.h>
#include <Xm/DrawP.h>
#include <Xm/ManagerP.h>
#include <Xm/TraitP.h>
#include <Xm/AccColorT.h>
#include <Xm/ActivatableT.h>
#include <Xm/CareVisualT.h>
#include "ColorI.h"
#include "PixConvI.h"
#include "PrimitiveI.h"
#include "RepTypeI.h"
#include "ScreenI.h"
#include "TravActI.h"
#include "TraversalI.h"
#include "XmI.h"

#define DELAY_DEFAULT	100
#define INVALID_PIXEL	((Pixel) -1)
#define INVALID_PIXMAP	((Pixmap) -1)

/********    Static Function Declarations    ********/

static Pixmap GetHighlightPixmapDefault(XmArrowButtonGadget ag);
static Pixmap GetTopShadowPixmapDefault(XmArrowButtonGadget ag);

static void ClassPartInitialize(WidgetClass wc);
static void Initialize(Widget    rw,
		       Widget    nw,
		       ArgList   args,
		       Cardinal *num_args);
static void GetArrowGC(XmArrowButtonGadget ag);
static void GetBackgroundGC(XmArrowButtonGadget ag);
static void Redisplay(Widget w, XEvent *event, Region region);
static void Destroy(Widget w);
static Boolean SetValues(Widget    cw,
			 Widget    rw,
			 Widget    nw,
			 ArgList   args,
			 Cardinal *num_args);
static void HighlightBorder(Widget w);
static void InputDispatch(Widget wid, XEvent *event, Mask event_mask);
static void Arm(XmArrowButtonGadget aw, XEvent *event);
static void Activate(Widget    wid,
		     XEvent   *event,
		     String   *params,
		     Cardinal *num_params);
static void ArmAndActivate(Widget    w,
			   XEvent   *event,
			   String   *params,
			   Cardinal *num_params);
static void ArmTimeout(XtPointer data, XtIntervalId *id);
static void Disarm(XmArrowButtonGadget aw, XEvent *event);
static void Enter(XmArrowButtonGadget aw, XEvent *event);
static void Leave(XmArrowButtonGadget aw, XEvent *event);
static void Help(XmArrowButtonGadget aw, XEvent *event);
static void ActivateCommonG(XmArrowButtonGadget ag, 
			    XEvent             *event,
			    Mask                event_mask);

static void ChangeCB(Widget         w, 
		     XtCallbackProc activCB,
		     XtPointer      closure,
		     Boolean        setunset);
static Boolean HandleRedraw(Widget kid, 
			    Widget cur_parent,
			    Widget new_parent,
			    Mask   visual_flag);
static void InitNewColorBehavior(XmArrowButtonGadget ag);
static void DealWithColors(XmArrowButtonGadget ag);
static void DealWithPixmaps(XmArrowButtonGadget ag);
static void InitNewPixmapBehavior(XmArrowButtonGadget ag);

static void DrawArrowG(XmArrowButtonGadget ag,
		       GC                  top_gc,
		       GC                  bottom_gc,
		       GC                  center_gc);
static void GetColors(Widget widget, XmAccessColorData color_data);

/********    End Static Function Declarations    ********/

/*  Resource list for Arrow  */

static XtResource resources[] = 
{
  {
    XmNmultiClick, XmCMultiClick, XmRMultiClick,
    sizeof(unsigned char),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.multiClick),
    XmRImmediate, (XtPointer) XmMULTICLICK_KEEP
  },

  {
    XmNarrowDirection, XmCArrowDirection, XmRArrowDirection, 
    sizeof(unsigned char),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.direction), 
    XmRImmediate, (XtPointer) XmARROW_UP
  },

  {
    XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.activate_callback),
    XmRPointer, (XtPointer) NULL
  },

  {
    XmNarmCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.arm_callback),
    XmRPointer, (XtPointer) NULL
  },

  {
    XmNdisarmCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.disarm_callback),
    XmRPointer, (XtPointer) NULL
  },
   
  {
    XmNbackground, XmCBackground, XmRPixel, 
    sizeof(Pixel),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.background),
    XmRImmediate, (XtPointer) INVALID_PIXEL
  },
   
  {
    XmNforeground, XmCForeground, XmRPixel, 
    sizeof(Pixel),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.foreground),
    XmRImmediate, (XtPointer) INVALID_PIXEL
  },
   
  {
    XmNtopShadowColor, XmCTopShadowColor, XmRPixel, 
    sizeof(Pixel),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.top_shadow_color),
    XmRImmediate, (XtPointer) INVALID_PIXEL
  },

  {
    XmNtopShadowPixmap, XmCTopShadowPixmap, XmRNoScalingDynamicPixmap,
    sizeof(Pixmap),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.top_shadow_pixmap),
    XmRImmediate, (XtPointer) INVALID_PIXMAP
  },

  {
    XmNbottomShadowColor, XmCBottomShadowColor, XmRPixel, 
    sizeof(Pixel),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.bottom_shadow_color),
    XmRImmediate, (XtPointer) INVALID_PIXEL
  },

  {
    XmNbottomShadowPixmap, XmCBottomShadowPixmap, XmRNoScalingDynamicPixmap,
    sizeof(Pixmap),
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.bottom_shadow_pixmap),
    XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
  },

  {
    XmNhighlightColor, XmCHighlightColor, XmRPixel, 
    sizeof(Pixel), 
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.highlight_color),
    XmRImmediate, (XtPointer) INVALID_PIXEL
  },

  {
    XmNhighlightPixmap, XmCHighlightPixmap, XmRNoScalingDynamicPixmap,
    sizeof(Pixmap), 
    XtOffsetOf(struct _XmArrowButtonGadgetRec, arrowbutton.highlight_pixmap),
    XmRImmediate, (XtPointer) INVALID_PIXMAP
  },
   {
     XmNdetailShadowThickness, XmCShadowThickness, XmRHorizontalDimension,
     sizeof (Dimension), 
     XtOffsetOf(XmArrowButtonGadgetRec, arrowbutton.detail_shadow_thickness),
     XmRCallProc, (XtPointer) _XmSetThickness
   }
};

static XmSyntheticResource syn_resources[] =
{
    {
        XmNdetailShadowThickness,
        sizeof(Dimension),
        XtOffsetOf(XmArrowButtonGadgetRec, arrowbutton.detail_shadow_thickness),
        XmeFromHorizontalPixels,XmeToHorizontalPixels
    }
};


/*  The Arrow class record definition  */

externaldef(xmarrowbuttongadgetclassrec) XmArrowButtonGadgetClassRec
	xmArrowButtonGadgetClassRec =
{
  { /* object fields */
    (WidgetClass) &xmGadgetClassRec,	/* superclass            */
    "XmArrowButtonGadget",		/* class_name	         */
    sizeof(XmArrowButtonGadgetRec),	/* widget_size	         */
    (XtProc)NULL,			/* class_initialize      */
    ClassPartInitialize,		/* class_part_initialize */
    FALSE,				/* class_inited          */
    Initialize,				/* initialize	         */
    (XtArgsProc)NULL,			/* initialize_hook       */
    NULL,				/* realize	         */
    NULL,				/* actions               */
    0,			        	/* num_actions    	 */
    resources,				/* resources	         */
    XtNumber(resources),		/* num_resources         */
    NULLQUARK,				/* xrm_class	         */
    TRUE,				/* compress_motion       */
    XtExposeCompressMaximal,		/* compress_exposure     */
    TRUE,				/* compress_enterleave   */
    FALSE,				/* visible_interest      */
    Destroy,				/* destroy               */
    (XtWidgetProc)NULL,			/* resize                */
    Redisplay,				/* expose                */
    SetValues,				/* set_values	         */
    (XtArgsFunc)NULL,			/* set_values_hook       */
    XtInheritSetValuesAlmost,		/* set_values_almost     */
    (XtArgsProc)NULL,			/* get_values_hook       */
    NULL,				/* accept_focus          */
    XtVersion,				/* version               */
    (XtPointer)NULL,			/* callback private      */
    (String)NULL,			/* tm_table              */
    (XtGeometryHandler)NULL,		/* query_geometry        */
    NULL,				/* display_accelerator   */
    (XtPointer)NULL			/* extension             */
  },
  
  { /* XmGadget fields */
    HighlightBorder,			/* border highlight   */
    XmInheritBorderUnhighlight,		/* border_unhighlight */
    ArmAndActivate,			/* arm_and_activate   */
    InputDispatch,			/* input dispatch     */
    XmInheritVisualChange,		/* visual_change      */
    syn_resources,         		/* syn_resources */
    XtNumber(syn_resources),	        /* num_syn_resources */
    (XmCacheClassPartPtr)NULL,		/* class cache part   */
    (XtPointer)NULL			/* extension          */
  },
  
  { /* XmArrowButtonGadget fields */
    (XtPointer)NULL			/* extension	      */
  }
};

externaldef(xmarrowbuttongadgetclass) WidgetClass xmArrowButtonGadgetClass = 
   (WidgetClass) &xmArrowButtonGadgetClassRec;


/* Trait record for arrowBG */
static XmConst XmActivatableTraitRec arrowBGAT = 
{
  0,				/* version	*/
  ChangeCB			/* changeCB	*/
};

static XmConst XmCareVisualTraitRec arrowBGCVT = 
{
  0,				/* version	*/
  HandleRedraw			/* redraw	*/
};

/* Access Colors Trait record for arrow button gadget */
static XmConst XmAccessColorsTraitRec arrowBGACT = 
{
  0,				/* version	*/
  GetColors,			/* getColors	*/
  NULL				/* setColors	*/
};
 
static Pixmap
GetHighlightPixmapDefault(XmArrowButtonGadget ag)
{
  XmManagerWidget mw = (XmManagerWidget)XtParent(ag);
  Pixmap result = XmUNSPECIFIED_PIXMAP;
  
  if (ag->arrowbutton.highlight_color == ag->arrowbutton.background)
    result = XmGetPixmapByDepth(XtScreen(ag), XmS50_foreground,
				ag->arrowbutton.highlight_color,
				ag->arrowbutton.foreground,
				mw->core.depth);

  return result;
}

static Pixmap
GetTopShadowPixmapDefault(XmArrowButtonGadget ag)
{
  XmManagerWidget mw = (XmManagerWidget)XtParent(ag);
  Pixmap result = XmUNSPECIFIED_PIXMAP;

  if (ag->arrowbutton.top_shadow_color == ag->arrowbutton.background)
    result = XmGetPixmapByDepth(XtScreen(ag), XmS50_foreground,
				ag->arrowbutton.top_shadow_color,
				ag->arrowbutton.foreground,
				mw->core.depth);

  else if (DefaultDepthOfScreen(XtScreen(ag)) == 1)
    result = XmGetPixmapByDepth(XtScreen(ag), XmS50_foreground,
				ag->arrowbutton.top_shadow_color,
				ag->arrowbutton.background,
				mw->core.depth);

  return result;
}

/************************************************************************
 *
 *  ClassPartInitialize
 *     Set up the fast subclassing for the widget
 *
 ************************************************************************/

static void 
ClassPartInitialize(
        WidgetClass wc)
{
  _XmFastSubclassInit (wc, XmARROW_BUTTON_GADGET_BIT);
  
  /* Install the activatable trait for all subclasses */
  XmeTraitSet((XtPointer)wc, XmQTactivatable, (XtPointer)&arrowBGAT);
  
  /* Install the careParentVisual trait for all subclasses as well. */
  XmeTraitSet((XtPointer)wc, XmQTcareParentVisual, (XtPointer)&arrowBGCVT);
  
  /* Install the accessColors trait for all subclasses as well. */
  XmeTraitSet((XtPointer)wc, XmQTaccessColors, (XtPointer)&arrowBGACT);
}

/************************************************************************
 *
 *  Initialize
 *     The main widget instance initialization routine.
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
Initialize(
        Widget rw,
        Widget nw,
        ArgList args,		/* unused */
        Cardinal *num_args)	/* unused */
{
  XmArrowButtonGadget request = (XmArrowButtonGadget) rw;
  XmArrowButtonGadget new_w = (XmArrowButtonGadget) nw;
  
  /*
   *  Check the data put into the new widget from .Xdefaults
   *  or through the arg list.
   */
  if (!XmRepTypeValidValue(XmRID_ARROW_DIRECTION, 
			   new_w->arrowbutton.direction, (Widget) new_w))
    {
      new_w->arrowbutton.direction = XmARROW_UP;
    }
  
  
  /*  Set up a geometry for the widget if it is currently 0.  */
  if (request->rectangle.width == 0) 
    new_w->rectangle.width += 15;
  if (request->rectangle.height == 0)
    new_w->rectangle.height += 15;
  
  /*  Set the internal arrow variables */
  new_w->arrowbutton.timer = 0;
  new_w->arrowbutton.selected = False;
  
  /*  Get the drawing graphics contexts.  */
  DealWithColors(new_w);
  DealWithPixmaps(new_w);
  
  GetArrowGC (new_w);
  GetBackgroundGC (new_w);
  new_w->arrowbutton.highlight_GC =
    _XmGetPixmapBasedGC (XtParent(nw), 
			 new_w->arrowbutton.highlight_color,
			 new_w->arrowbutton.background,
			 new_w->arrowbutton.highlight_pixmap);
  
  new_w->arrowbutton.top_shadow_GC =
    _XmGetPixmapBasedGC (XtParent(nw), 
			 new_w->arrowbutton.top_shadow_color,
			 new_w->arrowbutton.background,
			 new_w->arrowbutton.top_shadow_pixmap);
  
  new_w->arrowbutton.bottom_shadow_GC =
    _XmGetPixmapBasedGC (XtParent(nw), 
			 new_w->arrowbutton.bottom_shadow_color,
			 new_w->arrowbutton.background,
			 new_w->arrowbutton.bottom_shadow_pixmap);
  
  /*  Initialize the interesting input types.  */
  new_w->gadget.event_mask =  XmARM_EVENT | XmACTIVATE_EVENT | XmHELP_EVENT |
    XmFOCUS_IN_EVENT | XmFOCUS_OUT_EVENT | XmENTER_EVENT | XmLEAVE_EVENT
      | XmMULTI_ARM_EVENT|  XmMULTI_ACTIVATE_EVENT;
}

/************************************************************************
 *
 *  GetBackgroundGC
 *     Get the graphics context used for drawing the background.
 *
 ************************************************************************/

static void 
GetBackgroundGC(
        XmArrowButtonGadget ag)
{
  XGCValues values;
  XtGCMask  valueMask;
  XmManagerWidget mw = (XmManagerWidget) XtParent(ag);
  
  ag->arrowbutton.fill_bg_box = 
    ((mw->core.background_pixel != ag->arrowbutton.background) &&
     (mw->core.background_pixmap == XmUNSPECIFIED_PIXMAP));
  
  if (!ag->arrowbutton.fill_bg_box)
    return;
  
  valueMask = GCForeground | GCBackground;
  values.foreground = ag->arrowbutton.background;
  values.background = ag->arrowbutton.foreground; 
  
  ag->arrowbutton.background_GC = XtGetGC ((Widget) mw, valueMask, &values);
}

/************************************************************************
 *
 *  GetArrowGC
 *     Get the graphics context used for drawing the arrowbutton.
 *
 ************************************************************************/

static void 
GetArrowGC(
        XmArrowButtonGadget ag)
{
  XGCValues values;
  XtGCMask  valueMask, unusedMask;
  XmManagerWidget mw = (XmManagerWidget) XtParent(ag);
  
  valueMask = GCForeground | GCBackground | GCGraphicsExposures;
  unusedMask = GCClipXOrigin | GCClipYOrigin | GCFont;

  values.foreground = ag->arrowbutton.foreground;
  values.background = ag->arrowbutton.background;
  values.graphics_exposures = False;
  
  ag->arrowbutton.arrow_GC = XtAllocateGC ((Widget) mw, 0, valueMask, &values,
					   GCClipMask, unusedMask);
  
  valueMask |= GCFillStyle | GCStipple;
  values.fill_style = FillOpaqueStippled;
  values.stipple = _XmGetInsensitiveStippleBitmap((Widget) ag);
  
  ag->arrowbutton.insensitive_GC = XtAllocateGC((Widget) mw, 0, valueMask, 
						&values, GCClipMask, 
						unusedMask);
}

/************************************************************************
 *
 *  Redisplay
 *     General redisplay function called on exposure events.
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
Redisplay(
        Widget w,
        XEvent *event,
        Region region)
{
  XmArrowButtonGadget aw = (XmArrowButtonGadget) w;
  int iwidth, iheight;
  int background_x_offset, background_y_offset, background_width,
  background_height;
  
  iwidth = (int) aw->rectangle.width - 2 * aw->gadget.highlight_thickness;
  iheight = (int) aw->rectangle.height - 2 * aw->gadget.highlight_thickness;
  
  background_x_offset = (aw->rectangle.x +
			 aw->gadget.highlight_thickness +
			 aw->gadget.shadow_thickness);
  
  background_y_offset = (aw->rectangle.y +
			 aw->gadget.highlight_thickness +
			 aw->gadget.shadow_thickness);
  
  background_height = iheight - 2 * aw->gadget.shadow_thickness;
  background_width = iwidth - 2 * aw->gadget.shadow_thickness;
  
  if (aw->arrowbutton.fill_bg_box)
    XFillRectangle(XtDisplay(aw),
		   XtWindow((Widget) aw),
		   aw->arrowbutton.background_GC,
		   background_x_offset,
		   background_y_offset,
		   background_width,
		   background_height);
  
  /*  Draw the arrow  */
  if ((iwidth > 0) && (iheight > 0))
    {
      if (aw->gadget.shadow_thickness > 0)
	XmeDrawShadows (XtDisplay (aw), XtWindow (aw),
			aw->arrowbutton.top_shadow_GC,
			aw->arrowbutton.bottom_shadow_GC,
			aw->rectangle.x + aw->gadget.highlight_thickness,
			aw->rectangle.y + aw->gadget.highlight_thickness,
			aw->rectangle.width - 2 *
			aw->gadget.highlight_thickness,
			aw->rectangle.height-2 *
			aw->gadget.highlight_thickness,
			aw->gadget.shadow_thickness, XmSHADOW_OUT);
      
      if (aw->arrowbutton.selected && XtIsSensitive(w))
	DrawArrowG(aw, aw->arrowbutton.bottom_shadow_GC,
		   aw->arrowbutton.top_shadow_GC, aw->arrowbutton.arrow_GC);
      else
	DrawArrowG(aw, aw->arrowbutton.top_shadow_GC,
		   aw->arrowbutton.bottom_shadow_GC,
		   (XtIsSensitive(w) ? 
		    aw->arrowbutton.arrow_GC : aw->arrowbutton.insensitive_GC));
    }

  if (aw->gadget.highlighted)
    {   
      (*(xmArrowButtonGadgetClassRec.gadget_class.border_highlight)) (w);
    } 
}

 /*
  *
  * DealWithColors
  *
  * Deal with compatibility.  
  *  If any resource is set initialize like a widget otherwise get
  * everything from the parent.
  * 
  *
  */
static void
DealWithColors(
        XmArrowButtonGadget ag)
{
  XmManagerWidget mw = (XmManagerWidget) XtParent(ag);
  
  /*
   * If the gadget color is set to the tag value or it is the
   * same as the manager color; bc mode is enabled otherwise
   * initialize like a widget.
   */
  if ((ag->arrowbutton.background == INVALID_PIXEL ||
       ag->arrowbutton.background == mw->core.background_pixel) &&
      (ag->arrowbutton.foreground == INVALID_PIXEL ||
       ag->arrowbutton.foreground == mw->manager.foreground) &&
      (ag->arrowbutton.top_shadow_color == INVALID_PIXEL ||
       ag->arrowbutton.top_shadow_color == mw->manager.top_shadow_color) &&
      (ag->arrowbutton.bottom_shadow_color == INVALID_PIXEL ||
       ag->arrowbutton.bottom_shadow_color == mw->manager.bottom_shadow_color) &&
      (ag->arrowbutton.highlight_color == INVALID_PIXEL ||
       ag->arrowbutton.highlight_color == mw->manager.highlight_color))
    {
      ag->arrowbutton.background = mw->core.background_pixel;
      ag->arrowbutton.foreground = mw->manager.foreground;
      ag->arrowbutton.top_shadow_color = mw->manager.top_shadow_color;
      ag->arrowbutton.bottom_shadow_color = mw->manager.bottom_shadow_color;
      ag->arrowbutton.highlight_color = mw->manager.highlight_color;
    }
  else
    {
      InitNewColorBehavior(ag);
    }
}
 
static void
InitNewColorBehavior(
        XmArrowButtonGadget ag)
{
  XrmValue value;
  
  value.size = sizeof(Pixel);
  
  if (ag->arrowbutton.background == INVALID_PIXEL)
    {
      _XmBackgroundColorDefault ((Widget)ag,
				 XtOffsetOf(struct _XmArrowButtonGadgetRec, 
					    arrowbutton.background),
				 &value);
      memcpy((char*) &ag->arrowbutton.background, value.addr, value.size);
    }
  
  if (ag->arrowbutton.foreground == INVALID_PIXEL)
    {
      _XmForegroundColorDefault ((Widget)ag,
				 XtOffsetOf(struct _XmArrowButtonGadgetRec, 
					    arrowbutton.foreground),
				 &value);
      memcpy((char*) &ag->arrowbutton.foreground, value.addr, value.size);
    }
  
  if (ag->arrowbutton.top_shadow_color == INVALID_PIXEL)
    {
      _XmTopShadowColorDefault ((Widget)ag,
				XtOffsetOf(struct _XmArrowButtonGadgetRec, 
					   arrowbutton.top_shadow_color),
				&value);
      memcpy((char*)&ag->arrowbutton.top_shadow_color, value.addr,value.size);
    }
  
  if (ag->arrowbutton.bottom_shadow_color == INVALID_PIXEL)
    {
      _XmBottomShadowColorDefault((Widget)ag,
				  XtOffsetOf(struct _XmArrowButtonGadgetRec,
					     arrowbutton.bottom_shadow_color),
				  &value);
      memcpy((char*)&ag->arrowbutton.bottom_shadow_color, value.addr, value.size);
    }
  
  if (ag->arrowbutton.highlight_color == INVALID_PIXEL)
    {
      _XmHighlightColorDefault((Widget)ag,
			       XtOffsetOf(struct _XmArrowButtonGadgetRec,
					  arrowbutton.highlight_color),
			       &value);
      memcpy((char*) &ag->arrowbutton.highlight_color, value.addr,value.size);
    }
}

 /*
  *
  * DealWithPixmaps
  *
  * Deal with compatibility.  
  *  If any resource is set initialize like a widget otherwise get
  * everything from the parent.
  * 
  */

static void
DealWithPixmaps(
        XmArrowButtonGadget ag)
{
  XmManagerWidget mw = (XmManagerWidget) XtParent(ag);
  
  if ((ag->arrowbutton.top_shadow_pixmap == INVALID_PIXMAP ||
       ag->arrowbutton.top_shadow_pixmap == mw->manager.top_shadow_pixmap) && 
      (ag->arrowbutton.highlight_pixmap == INVALID_PIXMAP  ||
       ag->arrowbutton.highlight_pixmap == mw->manager.highlight_pixmap))
    {
      ag->arrowbutton.top_shadow_pixmap = mw->manager.top_shadow_pixmap;
      ag->arrowbutton.highlight_pixmap = mw->manager.highlight_pixmap;
    }
  else
    {
      InitNewPixmapBehavior(ag);
    }
}
    
/*
 * InitNewPixmapBehavior
 *
 * Initialize colors like a widget.
 */
 
static void
InitNewPixmapBehavior(
        XmArrowButtonGadget ag)
{
  if (ag->arrowbutton.top_shadow_pixmap == INVALID_PIXMAP)
    {
      ag->arrowbutton.top_shadow_pixmap = GetTopShadowPixmapDefault(ag);
    }

  if (ag->arrowbutton.highlight_pixmap == INVALID_PIXMAP)
    {
      ag->arrowbutton.highlight_pixmap = GetHighlightPixmapDefault(ag);
    }
}

/************************************************************************
 *
 *  Destroy
 *	Clean up allocated resources when the widget is destroyed.
 *
 ************************************************************************/

static void 
Destroy(
        Widget w)
{
  XmArrowButtonGadget aw = (XmArrowButtonGadget) w;
  XmManagerWidget mw = (XmManagerWidget) XtParent(aw);
  
  if (aw->arrowbutton.timer)
    XtRemoveTimeOut (aw->arrowbutton.timer);
  
  XtReleaseGC ((Widget) mw, aw->arrowbutton.arrow_GC);
  XtReleaseGC ((Widget) mw, aw->arrowbutton.insensitive_GC);
  if (aw->arrowbutton.fill_bg_box)
    XtReleaseGC ((Widget) mw, aw->arrowbutton.background_GC);
  XtReleaseGC ((Widget) mw, aw->arrowbutton.top_shadow_GC);
  XtReleaseGC ((Widget) mw, aw->arrowbutton.bottom_shadow_GC);
  XtReleaseGC ((Widget) mw, aw->arrowbutton.highlight_GC);
}

/************************************************************************
 *
 *  SetValues
 *
 ************************************************************************/

/*ARGSUSED*/
static Boolean 
SetValues(
        Widget cw,
        Widget rw,		/* unused */
        Widget nw,
        ArgList args,		/* unused */
        Cardinal *num_args)	/* unused */
{
  XmArrowButtonGadget current = (XmArrowButtonGadget) cw;
  XmArrowButtonGadget new_w = (XmArrowButtonGadget) nw;
  
  Boolean returnFlag = FALSE;
  
  
  /*  Check the data put into the new widget.  */
  
  if (!XmRepTypeValidValue(XmRID_ARROW_DIRECTION, 
			   new_w->arrowbutton.direction, (Widget) new_w))
    {
      new_w->arrowbutton.direction = current->arrowbutton.direction;
    }
  
  
  /*  ReInitialize the interesting input types.  */
  
  new_w->gadget.event_mask |=  XmARM_EVENT | XmACTIVATE_EVENT | XmHELP_EVENT |
    XmFOCUS_IN_EVENT | XmFOCUS_OUT_EVENT | XmENTER_EVENT | XmLEAVE_EVENT
      | XmMULTI_ARM_EVENT | XmMULTI_ACTIVATE_EVENT;
  
  if (new_w->arrowbutton.direction != current->arrowbutton.direction ||
      XtIsSensitive(nw) != XtIsSensitive(cw) ||
      new_w->gadget.highlight_thickness !=
      current->gadget.highlight_thickness ||
      new_w->gadget.shadow_thickness != current->gadget.shadow_thickness)
    {
      returnFlag = TRUE;
    }
  
  if (new_w->arrowbutton.foreground != current->arrowbutton.foreground ||
      new_w->arrowbutton.background != current->arrowbutton.background)
    {
      XtReleaseGC (XtParent(current), new_w->arrowbutton.arrow_GC);
      XtReleaseGC (XtParent(current), new_w->arrowbutton.insensitive_GC);
      if (new_w->arrowbutton.fill_bg_box)
	XtReleaseGC (XtParent(current), new_w->arrowbutton.background_GC);
      GetArrowGC (new_w);
      GetBackgroundGC (new_w);
      return (True);
    }
  
  if (current->arrowbutton.top_shadow_color != 
      new_w->arrowbutton.top_shadow_color ||
      current->arrowbutton.top_shadow_pixmap != 
      new_w->arrowbutton.top_shadow_pixmap)
    {
      XtReleaseGC ((Widget) new_w, new_w->arrowbutton.top_shadow_GC);
      new_w->arrowbutton.top_shadow_GC =
	_XmGetPixmapBasedGC (XtParent(nw), 
			     new_w->arrowbutton.top_shadow_color,
			     new_w->arrowbutton.background,
			     new_w->arrowbutton.top_shadow_pixmap);
      returnFlag = True;
    }
  
  
  if (current->arrowbutton.bottom_shadow_color != 
      new_w->arrowbutton.bottom_shadow_color ||
      current->arrowbutton.bottom_shadow_pixmap != 
      new_w->arrowbutton.bottom_shadow_pixmap)
    {
      XtReleaseGC ((Widget) new_w, new_w->arrowbutton.bottom_shadow_GC);
      new_w->arrowbutton.bottom_shadow_GC =
	_XmGetPixmapBasedGC (XtParent(nw), 
			     new_w->arrowbutton.bottom_shadow_color,
			     new_w->arrowbutton.background,
			     new_w->arrowbutton.bottom_shadow_pixmap);
      returnFlag = True;
    }
  
  if (current->arrowbutton.highlight_color !=
      new_w->arrowbutton.highlight_color ||
      current->arrowbutton.highlight_pixmap !=
      new_w->arrowbutton.highlight_pixmap)
    {
      XtReleaseGC ((Widget) new_w, new_w->arrowbutton.highlight_GC);
      new_w->arrowbutton.highlight_GC =
	_XmGetPixmapBasedGC (XtParent(nw), 
			     new_w->arrowbutton.highlight_color,
			     new_w->arrowbutton.background,
			     new_w->arrowbutton.highlight_pixmap);
      
      returnFlag = True;
    }
  
  
  return (returnFlag);
}

static void 
HighlightBorder(
        Widget w)
{   
  XmArrowButtonGadget ag = (XmArrowButtonGadget) w;

  if (ag->rectangle.width == 0 || 
      ag->rectangle.height == 0 ||
      ag->gadget.highlight_thickness == 0)
    {   
      return;
    } 

  ag->gadget.highlighted = True;
  ag->gadget.highlight_drawn = True;

  /* CR 7330: Use XmeDrawHighlight, not _XmDrawHighlight. */
  XmeDrawHighlight(XtDisplay((Widget) ag), XtWindow((Widget) ag), 
		   ag->arrowbutton.highlight_GC,
		   ag->rectangle.x, ag->rectangle.y, 
		   ag->rectangle.width, ag->rectangle.height,
		   ag->gadget.highlight_thickness);
}

static Boolean 
HandleRedraw (
	Widget kid, 	       
	Widget cur_parent,
	Widget new_parent,
	Mask visual_flag)
{
  XmArrowButtonGadget ag = (XmArrowButtonGadget) kid;
  XmManagerWidget mw = (XmManagerWidget) new_parent;
  XmManagerWidget curmw = (XmManagerWidget) cur_parent;
  Boolean redraw, do_bg, do_arrow, do_highlight, do_top, do_bot;
  
  redraw = do_bg = do_arrow = do_highlight = do_top = do_bot = False;
  
  if ((visual_flag & VisualBackgroundPixel) &&
      (ag->arrowbutton.background == curmw->core.background_pixel))
    
    {
      redraw = do_bg = do_arrow = do_highlight = do_top = do_bot = True;
      ag->arrowbutton.background = mw->core.background_pixel;
    }
  
  if ((visual_flag & VisualForeground) &&
      (ag->arrowbutton.foreground == curmw->manager.foreground))
    {
      redraw = do_arrow = True;
      ag->arrowbutton.foreground = mw->manager.foreground;
    }
  
  if (visual_flag & VisualBackgroundPixmap)	
    {
      redraw = do_bg = True;
    }
  
  if (visual_flag & (VisualTopShadowColor | VisualTopShadowPixmap))
    {
      redraw = do_top = True;
      
      if (ag->arrowbutton.top_shadow_color == curmw->manager.top_shadow_color)
	ag->arrowbutton.top_shadow_color = mw->manager.top_shadow_color;
      
      if ((ag->arrowbutton.top_shadow_pixmap == 
	   curmw->manager.top_shadow_pixmap) &&
	  (ag->arrowbutton.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP || 
	   ag->arrowbutton.top_shadow_color == curmw->manager.top_shadow_color))
	ag->arrowbutton.top_shadow_pixmap = mw->manager.top_shadow_pixmap;
    }
  
  if (visual_flag & (VisualBottomShadowColor | VisualBottomShadowPixmap))
    {
      redraw = do_bot = True;
      
      if (ag->arrowbutton.bottom_shadow_color ==
	  curmw->manager.bottom_shadow_color)
	ag->arrowbutton.bottom_shadow_color = mw->manager.bottom_shadow_color;
      
      if ((ag->arrowbutton.bottom_shadow_pixmap == 
	   curmw->manager.bottom_shadow_pixmap) && 
	  (ag->arrowbutton.bottom_shadow_pixmap != XmUNSPECIFIED_PIXMAP ||
	   ag->arrowbutton.bottom_shadow_color == curmw->manager.bottom_shadow_color))
	ag->arrowbutton.bottom_shadow_pixmap = mw->manager.bottom_shadow_pixmap;
    }
  
  if (visual_flag & (VisualHighlightColor | VisualHighlightPixmap))
    {
      redraw = do_highlight = True;
      
      if (ag->arrowbutton.highlight_color == curmw->manager.highlight_color)
	ag->arrowbutton.highlight_color = mw->manager.highlight_color;
      
      if (ag->arrowbutton.highlight_pixmap == curmw->manager.highlight_pixmap &&
	  (ag->arrowbutton.highlight_pixmap != XmUNSPECIFIED_PIXMAP ||
	   ag->arrowbutton.highlight_color != curmw->manager.highlight_color))
	ag->arrowbutton.highlight_pixmap = mw->manager.highlight_pixmap;
      
      ag->arrowbutton.highlight_GC =
	_XmGetPixmapBasedGC (XtParent(ag), 
			     ag->arrowbutton.highlight_color,
			     ag->arrowbutton.background,
			     ag->arrowbutton.highlight_pixmap);
    }
  
  if (do_bg)
    {
      if (ag->arrowbutton.fill_bg_box)
	XtReleaseGC ((Widget)mw, ag->arrowbutton.background_GC);
      GetBackgroundGC (ag);
    }
  
  if (do_arrow)
    {
      XtReleaseGC ((Widget)mw, ag->arrowbutton.arrow_GC);
      XtReleaseGC ((Widget)mw, ag->arrowbutton.insensitive_GC);
      GetArrowGC (ag);
    }
  
  if (do_highlight)
    {
      XtReleaseGC ((Widget)mw, ag->arrowbutton.highlight_GC);
      ag->arrowbutton.highlight_GC =
	_XmGetPixmapBasedGC (XtParent(ag), 
			     ag->arrowbutton.highlight_color,
			     ag->arrowbutton.background,
			     ag->arrowbutton.highlight_pixmap);
    }
  
  if (do_top)
    {
      XtReleaseGC ((Widget)mw, ag->arrowbutton.top_shadow_GC);
      ag->arrowbutton.top_shadow_GC =
	_XmGetPixmapBasedGC (XtParent(ag), 
			     ag->arrowbutton.top_shadow_color,
			     ag->arrowbutton.background,
			     ag->arrowbutton.top_shadow_pixmap);
    }
  
  if (do_bot)
    {
      XtReleaseGC ((Widget)mw, ag->arrowbutton.bottom_shadow_GC);
      ag->arrowbutton.bottom_shadow_GC =
	_XmGetPixmapBasedGC (XtParent(ag), 
			     ag->arrowbutton.bottom_shadow_color,
			     ag->arrowbutton.background,
			     ag->arrowbutton.bottom_shadow_pixmap);
    }
  
  return redraw;
}

/************************************************************************
 *
 *  InputDispatch
 *     This function catches input sent by a manager and dispatches it
 *     to the individual routines.
 *
 ************************************************************************/

static void 
InputDispatch(
        Widget wid,
        XEvent *event,
        Mask event_mask)
{
  XmArrowButtonGadget ag = (XmArrowButtonGadget) wid;
  
  if ((event_mask & XmARM_EVENT) || 
      ((ag->arrowbutton.multiClick == XmMULTICLICK_KEEP) &&
       (event_mask & XmMULTI_ARM_EVENT)))
    Arm (ag, event);

  else if (event_mask & XmACTIVATE_EVENT)
    { 
      ag->arrowbutton.click_count = 1;  
      ActivateCommonG (ag, event, event_mask);
    }

  else if (event_mask & XmMULTI_ACTIVATE_EVENT)
    { 
      /* if XmNMultiClick resource is set to DISCARD - do nothing
       * else call ActivateCommon() and increment clickCount;
       */
      if (ag->arrowbutton.multiClick == XmMULTICLICK_KEEP)
	{  
	  ag->arrowbutton.click_count++;
	  ActivateCommonG (ag, event, event_mask);
	}
    }
  
  else if (event_mask & XmHELP_EVENT) 
    Help (ag, event);

  else if (event_mask & XmENTER_EVENT)
    Enter (ag, event);

  else if (event_mask & XmLEAVE_EVENT)
    Leave (ag, event);

  else if (event_mask & XmFOCUS_IN_EVENT) 
    _XmFocusInGadget ((Widget) ag, event, NULL, NULL);

  else if (event_mask & XmFOCUS_OUT_EVENT) 
    _XmFocusOutGadget ((Widget)ag, event, NULL, NULL);
}

/************************************************************************
 *
 *  Arm
 *     This function processes button 1 down occuring on the arrowbutton.
 *
 ************************************************************************/
static void 
Arm(
        XmArrowButtonGadget aw,
        XEvent *event)
{
  XmArrowButtonCallbackStruct call_value;
  
  aw->arrowbutton.selected = True;
  
  DrawArrowG(aw, aw->arrowbutton.bottom_shadow_GC,
	     aw->arrowbutton.top_shadow_GC, NULL);
  
  if (aw->arrowbutton.arm_callback)
    {
      XFlush(XtDisplay(aw));
      
      call_value.reason = XmCR_ARM;
      call_value.event = event;
      XtCallCallbackList ((Widget) aw, aw->arrowbutton.arm_callback,
			  &call_value);
    }
}

/************************************************************************
 *
 *  Activate
 *     This function processes button 1 up occuring on the arrowbutton.
 *     If the button 1 up occurred inside the button the activate
 *     callbacks are called.
 *
 ************************************************************************/
/*ARGSUSED*/

static void 
Activate(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params)	/* unused */
{
  XmArrowButtonGadget aw = (XmArrowButtonGadget) wid;
  XButtonPressedEvent *buttonEvent = (XButtonPressedEvent *) event;
  
  XmPushButtonCallbackStruct call_value;
  
  aw->arrowbutton.selected = False;
  
  DrawArrowG(aw, aw->arrowbutton.top_shadow_GC, 
	     aw->arrowbutton.bottom_shadow_GC, NULL);
  
  /* CR 9181: Consider clipping when testing visibility. */
  if ((buttonEvent->type == ButtonPress || 
       buttonEvent->type == ButtonRelease) &&
      _XmGetPointVisibility(wid, buttonEvent->x_root, buttonEvent->y_root) &&
      (aw->arrowbutton.activate_callback))
    {
      XFlush(XtDisplay(aw));
      
      call_value.reason = XmCR_ACTIVATE;
      call_value.event = (XEvent *) buttonEvent;
      call_value.click_count = aw->arrowbutton.click_count;
      XtCallCallbackList ((Widget) aw, 
			  aw->arrowbutton.activate_callback, &call_value);
    }
}

/************************************************************************
 *
 *     ArmAndActivate
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
ArmAndActivate(
        Widget w,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params)	/* unused */
{
  XmArrowButtonGadget ab = (XmArrowButtonGadget) w;
  XmPushButtonCallbackStruct call_value;
  XtExposeProc expose;
  
  ab->arrowbutton.selected = TRUE;
  ab->arrowbutton.click_count = 1;
  _XmProcessLock();
  expose = ab->object.widget_class->core_class.expose;
  _XmProcessUnlock();
  (*(expose)) 
    ((Widget) ab, event, FALSE);
  
  XFlush (XtDisplay (ab));
  
  if (ab->arrowbutton.arm_callback)
    {
      call_value.reason = XmCR_ARM;
      call_value.event = event;
      call_value.click_count = ab->arrowbutton.click_count;
      XtCallCallbackList ((Widget) ab, ab->arrowbutton.arm_callback,
			  &call_value);
    }
  
  call_value.reason = XmCR_ACTIVATE;
  call_value.event = event;
  call_value.click_count = 1;          /* always 1 in kselect */
  
  if (ab->arrowbutton.activate_callback)
    {
      XFlush (XtDisplay (ab));
      XtCallCallbackList ((Widget) ab, ab->arrowbutton.activate_callback,
			  &call_value);
    }
  
  ab->arrowbutton.selected = FALSE;
  
  if (ab->arrowbutton.disarm_callback)
    {
      XFlush (XtDisplay (ab));
      call_value.reason = XmCR_DISARM;
      XtCallCallbackList ((Widget) ab, ab->arrowbutton.disarm_callback,
			  &call_value);
    }
  
  /* If the button is still around, show it released, after a short delay */
  
  if (ab->object.being_destroyed == False)
    {
      ab->arrowbutton.timer = 
	XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) ab),
			(unsigned long) DELAY_DEFAULT,
			ArmTimeout, (XtPointer)ab);
    }
}

/*ARGSUSED*/
static void 
ArmTimeout(
        XtPointer data,
        XtIntervalId *id)
{
  XmArrowButtonGadget ab = (XmArrowButtonGadget) data;
  
  ab->arrowbutton.timer = 0;

  if (XtIsRealized((Widget)ab) && XtIsManaged((Widget)ab)) 
    {
      Redisplay ((Widget) ab, NULL, FALSE);
      XFlush (XtDisplay (ab));
    }
}

/************************************************************************
 *
 *  Disarm
 *     This function processes button 1 up occuring on the arrowbutton.
 *
 ************************************************************************/
static void 
Disarm(
        XmArrowButtonGadget aw,
        XEvent *event)
{
  XmArrowButtonCallbackStruct call_value;
  
  call_value.reason = XmCR_DISARM;
  call_value.event = event;
  XtCallCallbackList ((Widget) aw, aw->arrowbutton.disarm_callback,
		      &call_value);
}

/************************************************************************
 *
 *  Enter
 *
 ************************************************************************/

static void 
Enter(
        XmArrowButtonGadget aw,
        XEvent *event)
{
  _XmEnterGadget ((Widget) aw, event, NULL, NULL);
  
  if (aw->arrowbutton.selected && XtIsSensitive((Widget) aw))
    DrawArrowG(aw, aw->arrowbutton.bottom_shadow_GC,
	       aw->arrowbutton.top_shadow_GC, NULL);
}

/************************************************************************
 *
 *  Leave
 *
 ************************************************************************/

static void 
Leave(
        XmArrowButtonGadget aw,
        XEvent *event)
{
  _XmLeaveGadget ((Widget) aw, event, NULL, NULL);

  if (aw->arrowbutton.selected && XtIsSensitive((Widget) aw))
    DrawArrowG(aw, aw->arrowbutton.top_shadow_GC,
	       aw->arrowbutton.bottom_shadow_GC, NULL);
}

/************************************************************************
 *
 *  Help
 *     This function processes Function Key 1 press occuring on 
 *     the arrowbutton.
 *
 ************************************************************************/

static void 
Help(
        XmArrowButtonGadget aw,
        XEvent *event)
{
   _XmSocorro((Widget) aw, event, NULL, NULL);
}

/************************************************************************
 *
 *  ChangeCB
 *	add or remove the activate callback list.
 *      
 ************************************************************************/

static void 
ChangeCB(
	 Widget w, 
	 XtCallbackProc activCB,
	 XtPointer closure,
	 Boolean setunset)
{
  if (setunset)
    XtAddCallback (w, XmNactivateCallback, activCB, closure);
  else
    XtRemoveCallback (w, XmNactivateCallback, activCB, closure);
}

static void
GetColors(Widget w, 
	  XmAccessColorData color_data)
{
  color_data->valueMask = AccessForeground | AccessBackgroundPixel |
    AccessHighlightColor | AccessTopShadowColor | AccessBottomShadowColor;
  color_data->background = ArrowBG_Background(w);
  color_data->foreground = ArrowBG_Foreground(w);
  color_data->highlight_color = ArrowBG_HighlightColor(w);
  color_data->top_shadow_color = ArrowBG_TopShadowColor(w);
  color_data->bottom_shadow_color = ArrowBG_BottomShadowColor(w);
}

/************************************************************************
 *
 *  XmCreateArrowButtonGadget
 *	Create an instance of an arrowbutton and return the widget id.
 *
 ************************************************************************/

Widget 
XmCreateArrowButtonGadget(
        Widget parent,
        char *name,
        ArgList arglist,
        Cardinal argcount)
{
  return XtCreateWidget(name, xmArrowButtonGadgetClass, parent, 
			arglist, argcount);
}

/* ARGSUSED */
static void 
ActivateCommonG(
        XmArrowButtonGadget ag,
        XEvent *event,
        Mask event_mask)
{
  if (event->type == ButtonRelease)
    {
      Activate((Widget) ag, event, NULL, NULL);
      Disarm (ag, event);
    }

  else  /* assume KeyPress or KeyRelease */
    (* (((XmArrowButtonGadgetClassRec *)(ag->object.widget_class))->
	gadget_class.arm_and_activate))
      ((Widget) ag, event, NULL, NULL);
}

/* Wrapper around XmeDrawArrow to calculate sizes. */
static void
DrawArrowG(XmArrowButtonGadget ag,
	   GC		       top_gc,
	   GC		       bottom_gc,
	   GC		       center_gc)
{
  Position x, y;
  Dimension width, height;
  Dimension margin = 
    ag->gadget.highlight_thickness + ag->gadget.shadow_thickness;

  /* Don't let large margins cause confusion. */
  if (margin <= (ag->rectangle.width / 2))
    {
      x = ag->rectangle.x + margin;
      width = ag->rectangle.width - (margin * 2);
    }
  else
    {
      x = ag->rectangle.x + ag->rectangle.width / 2;
      width = 0;
    }

  if (margin <= (ag->rectangle.height / 2))
    {
      y = ag->rectangle.y + margin;
      height = ag->rectangle.height - (margin * 2);
    }
  else
    {
      y = ag->rectangle.y + ag->rectangle.height / 2;
      height = 0;
    }

  /* The way we currently handle 1 shadowThickness in XmeDrawArrow 
     is by drawing the center a little bit bigger, so the center_gc has
     to be present. Kinda hacky... */
  if (!center_gc && 
      ag->arrowbutton.detail_shadow_thickness == 1) 
      center_gc = ag->arrowbutton.arrow_GC ;
  if (center_gc)
    XSetClipMask(XtDisplay((Widget) ag), center_gc, None);

  XmeDrawArrow (XtDisplay ((Widget) ag), XtWindow ((Widget) ag),
		top_gc, bottom_gc, center_gc,
		x, y, width, height, 
		ag->arrowbutton.detail_shadow_thickness, 
		ag->arrowbutton.direction);
}
