/* 
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: PushB.c /main/29 1999/01/27 16:08:33 mgreess $"
#endif
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif


/* (c) Copyright 1989, 1990 DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */
/* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */
/* (c) Copyright 1988 MASSACHUSETTS INSTITUTE OF TECHNOLOGY  */
/* (c) Copyright 1988 MICROSOFT CORPORATION */

#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/ShellP.h>
#include <Xm/ActivatableT.h>
#include <Xm/BaseClassP.h>
#include <Xm/CareVisualT.h>
#include <Xm/DisplayP.h>
#include <Xm/DrawP.h>
#include <Xm/ManagerP.h>
#include <Xm/MenuT.h>
#include <Xm/PushBP.h>
#include <Xm/TakesDefT.h>
#include <Xm/TearOffBP.h>
#include <Xm/TraitP.h>
#include <Xm/TransltnsP.h>
#include <Xm/VaSimpleP.h>
#include "ColorI.h"
#include "LabelI.h"
#include "MenuProcI.h"
#include "MenuStateI.h"
#include "MenuUtilI.h"
#include "PrimitiveI.h"
#include "TravActI.h"
#include "TraversalI.h"
#include "UniqueEvnI.h"
#include "XmI.h"
#include "VaSimpleI.h"
#include "ExtP.h"

#define XmINVALID_MULTICLICK	255
#define DELAY_DEFAULT		100 

#define FIX_1516

/********    Static Function Declarations    ********/

static void Arm( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void MultiArm( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void Activate( 
                        Widget wid,
                        XEvent *buttonEvent,
                        String *params,
                        Cardinal *num_params) ;
static void MultiActivate( 
                        Widget wid,
                        XEvent *buttonEvent,
                        String *params,
                        Cardinal *num_params) ;
static void ActivateCommon( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void ArmAndActivate( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void ArmTimeout( 
                        XtPointer data,
                        XtIntervalId *id) ;
static void Disarm( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void BtnDown( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void BtnUp( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void Enter( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void Leave( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void BorderHighlight( 
                        Widget wid) ;
static void DrawBorderHighlight( 
                        Widget wid) ;
static void BorderUnhighlight( 
                        Widget wid) ;
static void KeySelect( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void ClassInitialize( void ) ;
static void ClassPartInitialize( 
                        WidgetClass wc) ;
static void InitializePrehook( 
                        Widget req,
                        Widget new_w,
                        ArgList args,
                        Cardinal *num_args) ;
static void InitializePosthook( 
                        Widget req,
                        Widget new_w,
                        ArgList args,
                        Cardinal *num_args) ;
static void Initialize( 
                        Widget rw,
                        Widget nw,
                        ArgList args,
                        Cardinal *num_args) ;
static void GetFillGC( 
                        XmPushButtonWidget pb) ;
static void GetBackgroundGC( 
                        XmPushButtonWidget pb) ;
static Boolean SetValuesPrehook( 
			Widget cw,
                        Widget rw,
                        Widget nw,
                        ArgList args,
                        Cardinal *num_args) ;
static Boolean SetValues( 
                        Widget cw,
                        Widget rw,
                        Widget nw,
                        ArgList args,
                        Cardinal *num_args) ;
static void Help( 
                        Widget wid,
                        XEvent *event,
                        String *params,
                        Cardinal *num_params) ;
static void Destroy( 
                        Widget w) ;
static void Resize(
                        Widget w) ;
static void EraseDefaultButtonShadow( 
                        XmPushButtonWidget pb) ;
static void Redisplay( 
                        Widget wid,
                        XEvent *event,
                        Region region) ;
static void DrawPushButtonBackground( 
                        XmPushButtonWidget pb) ;
static void DrawPushButtonLabel( 
                        XmPushButtonWidget pb,
                        XEvent *event,
                        Region region) ;
static void DrawPushButtonShadows( 
                        XmPushButtonWidget pb) ;
static void ComputePBLabelArea( 
                        XmPushButtonWidget pb,
                        XRectangle *box) ;
static void DrawPBPrimitiveShadows( 
                        XmPushButtonWidget pb) ;
static void DrawDefaultButtonShadows( 
                        XmPushButtonWidget pb) ;
static XmImportOperator ShowAsDef_ToHorizPix( 
                        Widget widget,
                        int offset,
                        XtArgVal *value) ;
static int AdjustHighLightThickness( 
                        XmPushButtonWidget new_w,
                        XmPushButtonWidget current) ;
static void ExportHighlightThickness( 
                        Widget widget,
                        int offset,
                        XtArgVal *value) ;
static void FillBorderWithParentColor( 
                        XmPushButtonWidget pb,
                        int borderwidth,
                        int dx,
                        int dy,
                        int rectwidth,
                        int rectheight) ;
static void SetPushButtonSize(
                        XmPushButtonWidget newtb) ;
static void ChangeCB(Widget w, 
		     XtCallbackProc activCB,
		     XtPointer closure,
		     Boolean setunset) ;
static void ShowAsDefault(Widget w,
			  XtEnum state) ;
static Boolean ParentVisualChanged(Widget kid, 
				   Widget cur_parent,
				   Widget new_parent,
				   Mask visual_flag);
static void PB_FixTearoff(XmPushButtonWidget pb);

/********    End Static Function Declarations    ********/

/*************************************<->*************************************
 *
 *
 *   Description:   translation tables for class: PushButton
 *   -----------
 *
 *   Matches events with string descriptors for internal routines.
 *
 *************************************<->***********************************/

static XtTranslations default_parsed;

#define defaultTranslations	_XmPushB_defaultTranslations

static XtTranslations menu_parsed;

#define menuTranslations	_XmPushB_menuTranslations


/*************************************<->*************************************
 *
 *
 *   Description:  action list for class: PushButton
 *   -----------
 *
 *   Matches string descriptors with internal routines.
 *   Note that Primitive will register additional event handlers
 *   for traversal.
 *
 *************************************<->***********************************/

static XtActionsRec actionsList[] =
{
  { "Arm", 			Arm			 },
  { "MultiArm", 		MultiArm		 },
  { "Activate", 		Activate		 },
  { "MultiActivate",		MultiActivate		 },
  { "ArmAndActivate", 		ArmAndActivate		 },
  { "Disarm", 			Disarm			 },
  { "BtnDown", 			BtnDown			 },
  { "BtnUp", 			BtnUp			 },
  { "Enter", 			Enter			 },
  { "Leave",			Leave			 },
  { "ButtonTakeFocus",       	_XmButtonTakeFocus	 },
  { "MenuButtonTakeFocus",   	_XmMenuButtonTakeFocus	 },
  { "MenuButtonTakeFocusUp", 	_XmMenuButtonTakeFocusUp },
  { "KeySelect",		KeySelect		 },
  { "Help",			Help			 },
};



/* The resource list for Push Button. */

static XtResource resources[] = 
{     
   {
     XmNmultiClick, XmCMultiClick, 
     XmRMultiClick, sizeof (unsigned char),
     XtOffsetOf(XmPushButtonRec, pushbutton.multiClick),
     XmRImmediate, (XtPointer) XmINVALID_MULTICLICK
   },

   {
     XmNfillOnArm, XmCFillOnArm, 
     XmRBoolean, sizeof (Boolean),
     XtOffsetOf(XmPushButtonRec, pushbutton.fill_on_arm),
     XmRImmediate, (XtPointer) True
   },

   {
     XmNarmColor, XmCArmColor,
     XmRPixel, sizeof (Pixel),
     XtOffsetOf(XmPushButtonRec, pushbutton.arm_color),
     XmRCallProc, (XtPointer) _XmSelectColorDefault
   },

   {
     XmNarmPixmap, XmCArmPixmap,
     XmRDynamicPixmap, sizeof (Pixmap),
     XtOffsetOf(XmPushButtonRec, pushbutton.arm_pixmap),
     XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
   },

   {
     XmNshowAsDefault, XmCShowAsDefault,
     XmRBooleanDimension, sizeof (Dimension),
     XtOffsetOf(XmPushButtonRec, pushbutton.show_as_default),
     XmRImmediate, (XtPointer) 0
   },

   {
     XmNactivateCallback, XmCCallback,
     XmRCallback, sizeof(XtCallbackList),
     XtOffsetOf(XmPushButtonRec, pushbutton.activate_callback),
     XmRPointer, (XtPointer) NULL
   },

   {
     XmNarmCallback, XmCCallback,
     XmRCallback, sizeof(XtCallbackList),
     XtOffsetOf(XmPushButtonRec, pushbutton.arm_callback),
     XmRPointer, (XtPointer) NULL
   },

   {
     XmNdisarmCallback, XmCCallback,
     XmRCallback, sizeof(XtCallbackList),
     XtOffsetOf(XmPushButtonRec, pushbutton.disarm_callback),
     XmRPointer, (XtPointer) NULL
   },
   
   {
     XmNshadowThickness, XmCShadowThickness,
     XmRHorizontalDimension, sizeof(Dimension),
     XtOffsetOf(XmPushButtonRec, primitive.shadow_thickness),
     XmRCallProc, (XtPointer) _XmSetThickness
   },

   {
     XmNdefaultButtonShadowThickness, XmCDefaultButtonShadowThickness, 
     XmRHorizontalDimension, sizeof (Dimension),
     XtOffsetOf(XmPushButtonRec, pushbutton.default_button_shadow_thickness),
     XmRImmediate, (XtPointer) 0
   },

   {
     XmNtraversalOn, XmCTraversalOn,
     XmRBoolean, sizeof(Boolean),
     XtOffsetOf(XmPrimitiveRec, primitive.traversal_on),
     XmRImmediate, (XtPointer) True
   },

   {
     XmNhighlightThickness, XmCHighlightThickness,
     XmRHorizontalDimension, sizeof (Dimension),
     XtOffsetOf(XmPrimitiveRec, primitive.highlight_thickness),
     XmRCallProc, (XtPointer) _XmSetThickness
   },
};

/* Synthetic resources list */

static XmSyntheticResource syn_resources[] =
{
  {
     XmNshowAsDefault, sizeof (Dimension),
     XtOffsetOf(XmPushButtonRec, pushbutton.show_as_default),
     XmeFromHorizontalPixels,
     ShowAsDef_ToHorizPix
  },

  {
     XmNdefaultButtonShadowThickness, sizeof (Dimension),
     XtOffsetOf(XmPushButtonRec, pushbutton.default_button_shadow_thickness),
     XmeFromHorizontalPixels,  
     XmeToHorizontalPixels
  },

   {
     XmNhighlightThickness, sizeof (Dimension),
     XtOffsetOf(XmPrimitiveRec, primitive.highlight_thickness),
     ExportHighlightThickness,
     XmeToHorizontalPixels
   },
};


/*************************************<->*************************************
 *
 *
 *   Description:  global class record for instances of class: PushButton
 *   -----------
 *
 *   Defines default field settings for this class record.
 *
 *************************************<->***********************************/

static XmBaseClassExtRec       pushBBaseClassExtRec = {
    NULL,                                     /* Next extension       */
    NULLQUARK,                                /* record type XmQmotif */
    XmBaseClassExtVersion,                    /* version              */
    sizeof(XmBaseClassExtRec),                /* size                 */
    InitializePrehook,                        /* initialize prehook   */
    SetValuesPrehook,                         /* set_values prehook   */
    InitializePosthook,                       /* initialize posthook  */
    XmInheritSetValuesPosthook,               /* set_values posthook  */
    XmInheritClass,                           /* secondary class      */
    XmInheritSecObjectCreate,                 /* creation proc        */
    XmInheritGetSecResData,                   /* getSecResData        */
    {0},                                      /* fast subclass        */
    XmInheritGetValuesPrehook,                /* get_values prehook   */
    XmInheritGetValuesPosthook,               /* get_values posthook  */
    (XtWidgetClassProc)NULL,                  /* classPartInitPrehook */
    (XtWidgetClassProc)NULL,                  /* classPartInitPosthook*/
    NULL,                                     /* ext_resources        */
    NULL,                                     /* compiled_ext_resources*/
    0,                                        /* num_ext_resources    */
    FALSE,                                    /* use_sub_resources    */
    XmInheritWidgetNavigable,                 /* widgetNavigable      */
    XmInheritFocusChange,                     /* focusChange          */
};

externaldef(xmpushbuttonclassrec) XmPushButtonClassRec xmPushButtonClassRec = 
{
  { /* core_class record */	
    /* superclass	  */	(WidgetClass) &xmLabelClassRec,
    /* class_name	  */	"XmPushButton",
    /* widget_size	  */	sizeof(XmPushButtonRec),
    /* class_initialize   */    ClassInitialize,
    /* class_part_init    */    ClassPartInitialize,
    /* class_inited       */	FALSE,
    /* initialize	  */	Initialize,
    /* initialize_hook    */    (XtArgsProc)NULL,
    /* realize		  */	XtInheritRealize,
    /* actions		  */	actionsList,
    /* num_actions	  */	XtNumber(actionsList),
    /* resources	  */	resources,
    /* num_resources	  */	XtNumber(resources),
    /* xrm_class	  */	NULLQUARK,
    /* compress_motion	  */	TRUE,
    /* compress_exposure  */	XtExposeCompressMaximal,
    /* compress_enterlv   */    TRUE,
    /* visible_interest	  */	FALSE,
    /* destroy		  */	Destroy,
    /* resize		  */	Resize,
    /* expose		  */	Redisplay,
    /* set_values	  */	SetValues,
    /* set_values_hook    */    (XtArgsFunc)NULL,
    /* set_values_almost  */    XtInheritSetValuesAlmost,
    /* get_values_hook    */	(XtArgsProc)NULL,
    /* accept_focus	  */	(XtAcceptFocusProc)NULL,
    /* version            */	XtVersion,
    /* callback_private   */    NULL,
    /* tm_table           */    NULL,
    /* query_geometry     */	XtInheritQueryGeometry, 
    /* display_accelerator*/    (XtStringProc)NULL,
    /* extension record   */    (XtPointer)&pushBBaseClassExtRec,
  },

  { /* primitive_class record       */
    /* Primitive border_highlight   */	BorderHighlight,
    /* Primitive border_unhighlight */	BorderUnhighlight,
    /* translations		    */  XtInheritTranslations,
    /* arm_and_activate		    */  ArmAndActivate,
    /* get resources		    */  syn_resources,
    /* num get_resources	    */  XtNumber(syn_resources),
    /* extension		    */  NULL,
  },

  { /* label_class record */
    /* setOverrideCallback*/	XmInheritWidgetProc,
    /* menu procedures    */	XmInheritMenuProc,
    /* menu traversal xlation */ XtInheritTranslations,
    /* extension	  */	(XtPointer) NULL,
  },

  { /* pushbutton_class record */
    /* extension	  */	(XtPointer) NULL,
  }
};


externaldef(xmpushbuttonwidgetclass)
   WidgetClass xmPushButtonWidgetClass = (WidgetClass)&xmPushButtonClassRec;



/* Activatable Trait record for pushButton */
static XmConst XmActivatableTraitRec pushButtonAT = 
{
  0,		/* version */
  ChangeCB,
};

/* Care visual Trait record for pushButton */
static XmConst XmCareVisualTraitRec pushButtonCVT = {
  0,		/* version */
  ParentVisualChanged,
};

/* TakesDefault Trait record for pushButton */
static XmConst XmTakesDefaultTraitRec pushButtonTDT = 
{
  0,		/* version */
  ShowAsDefault,
};

/* Menu Savvy trait record */
static XmMenuSavvyTraitRec MenuSavvyRecord = {
    /* version: */
    -1,
    NULL,
    NULL,
    NULL,
    _XmCBNameActivate,
};


/*************************************<->*************************************
 *
 *  Synthetic hooks
 *
 *************************************<->***********************************/

static XmImportOperator 
ShowAsDef_ToHorizPix(
        Widget widget,
        int offset,
        XtArgVal *value )
{
  XtArgVal        oldValue ;
  XmImportOperator returnVal ;
  
  oldValue = *value ;
  returnVal = XmeToHorizontalPixels (widget, offset, value) ;
  
  if (oldValue  &&  !*value)
    *value = (XtArgVal) 1;

  return (returnVal) ;
} 

static void 
ExportHighlightThickness(
        Widget widget,
        int offset,
        XtArgVal *value )
{
  XmPushButtonWidget pbw = (XmPushButtonWidget) widget;
  if (pbw->pushbutton.show_as_default ||
      pbw->pushbutton.default_button_shadow_thickness)
    {
      if ((int)*value >= Xm3D_ENHANCE_PIXEL)
	*value -= Xm3D_ENHANCE_PIXEL;
    }
  
  XmeFromHorizontalPixels (widget, offset, value);
}

/*************************************<->*************************************
 *
 *  ClassInitialize 
 *
 *************************************<->***********************************/

static void 
ClassInitialize( void )
{
  /* parse the various translation tables */
  menu_parsed    = XtParseTranslationTable(menuTranslations);
  default_parsed = XtParseTranslationTable(defaultTranslations);
  
  /* set up base class extension quark */
  pushBBaseClassExtRec.record_type = XmQmotif;
}



/************************************************************************
 *
 *  ClassPartInitialize
 *     Set up the fast subclassing for the widget
 *
 ************************************************************************/
static void 
ClassPartInitialize(
        WidgetClass wc )
{
  _XmFastSubclassInit (wc, XmPUSH_BUTTON_BIT);
  
  /* Install the menu savvy trait record,  copying fields from XmLabel */
  _XmLabelCloneMenuSavvy (wc, &MenuSavvyRecord);

  /* Install the activatable trait for all subclasses */
  XmeTraitSet((XtPointer) wc, XmQTactivatable, (XtPointer) &pushButtonAT);
  
  /* Install the takesDefault trait for all subclasses */
  XmeTraitSet((XtPointer) wc, XmQTtakesDefault, (XtPointer) &pushButtonTDT);

  /* Override primitive's careParentVisual trait for all subclasses. */
  XmeTraitSet((XtPointer) wc, XmQTcareParentVisual, (XtPointer)&pushButtonCVT);
}

/************************************************************
 *
 * InitializePrehook
 *
 * Put the proper translations in core_class tm_table so that
 * the data is massaged correctly
 *
 ************************************************************/

/*ARGSUSED*/
static void
InitializePrehook(
        Widget req,		/* unused */
        Widget new_w,
        ArgList args,		/* unused */
        Cardinal *num_args )	/* unused */
{
  XmPushButtonWidget bw = (XmPushButtonWidget) new_w;
  unsigned char type;
  XmMenuSystemTrait menuSTrait;
  
  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass(XtParent(new_w)), XmQTmenuSystem);
  
  _XmSaveCoreClassTranslations (new_w);
  
  if (menuSTrait != NULL)
    type = menuSTrait->type(XtParent(new_w));
  else 
    type = XmWORK_AREA;
  
  _XmProcessLock();
  if (type == XmMENU_PULLDOWN ||
      type == XmMENU_POPUP)
    new_w->core.widget_class->core_class.tm_table = (String) menu_parsed;
  else 
    new_w->core.widget_class->core_class.tm_table = (String) default_parsed;
  
  /* CR 2990: Use XmNbuttonFontList as the default font. */
  if (bw->label.font == NULL)
    bw->label.font = XmeGetDefaultRenderTable (new_w, XmBUTTON_FONTLIST);
  _XmProcessUnlock();
}

/************************************************************
 *
 * InitializePosthook
 *
 * restore core class translations
 *
 ************************************************************/

/*ARGSUSED*/
static void
InitializePosthook(
        Widget req,		/* unused */
        Widget new_w,
        ArgList args,		/* unused */
        Cardinal *num_args )	/* unused */
{
  _XmRestoreCoreClassTranslations (new_w);
}

/************************************************************************
 *
 *  GetFillGC
 *     Get the graphics context used for filling in background of button.
 *
 ************************************************************************/

static void 
GetFillGC(
        XmPushButtonWidget pb )
{
  XGCValues values;
  XtGCMask  valueMask;
  
  valueMask = GCForeground | GCBackground | GCFillStyle;
  
  values.foreground = pb->pushbutton.arm_color;
  values.background = pb->core.background_pixel;
  values.fill_style = FillSolid;
  
  pb->pushbutton.fill_gc = XtGetGC ((Widget) pb, valueMask, &values);
}

/************************************************************************
 *
 *  GetBackgroundGC
 *     Get the graphics context used for filling in background of 
 *     the pushbutton when not armed.
 *
 ************************************************************************/
static void 
GetBackgroundGC(
        XmPushButtonWidget pb )
{
  XGCValues       values;
  XtGCMask        valueMask;
  XFontStruct     *fs;
  
  valueMask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
  
  values.foreground = pb->core.background_pixel;
  values.background = pb->primitive.foreground;
  values.graphics_exposures = False;
  
  if (XmeRenderTableGetDefaultFont(pb->label.font, &fs))
    values.font = fs->fid;
  else
    valueMask &= ~GCFont;
  
  /* add background_pixmap to GC */
  if (pb->core.background_pixmap != XmUNSPECIFIED_PIXMAP)
    {
      values.tile = pb->core.background_pixmap;
      values.fill_style = FillTiled;
      valueMask |= (GCTile | GCFillStyle);
    }
  
  pb->pushbutton.background_gc = XtGetGC ((Widget) pb,valueMask,&values);
}

/*************************************<->*************************************
 *
 *  Initialize 
 *
 *************************************<->***********************************/

/*ARGSUSED*/
static void 
Initialize(
        Widget rw,
        Widget nw,
        ArgList args,		/* unused */
        Cardinal *num_args )	/* unused */
{
  XmPushButtonWidget request = (XmPushButtonWidget) rw ;
  XmPushButtonWidget new_w = (XmPushButtonWidget) nw ;
  int		     increase;	
  int		     adjustment = 0;  
  XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(new_w));
  Boolean etched_in = dpy->display.enable_etched_in_menu;
  
  if (new_w->pushbutton.multiClick == XmINVALID_MULTICLICK)
    {
      if (Lab_IsMenupane(new_w))
	new_w->pushbutton.multiClick = XmMULTICLICK_DISCARD;
      else
	new_w->pushbutton.multiClick = XmMULTICLICK_KEEP;
    }
  
  /* if menuProcs is not set up yet, try again */
  _XmProcessLock();
  if (xmLabelClassRec.label_class.menuProcs == NULL)
    xmLabelClassRec.label_class.menuProcs =
      (XmMenuProc) _XmGetMenuProcContext();
  _XmProcessUnlock();
  
  /*
   * Fix to introduce Resource XmNdefaultBorderWidth and compatibility
   *  variable.
   *  if defaultBorderWidth > 0, the program knows about this resource
   *  and is therefore a Motif 1.1 program; otherwise it is a Motif 1.0
   *      program and old semantics of XmNshowAsDefault prevails.
   */
  if (new_w->pushbutton.default_button_shadow_thickness > 0)
    new_w->pushbutton.compatible = False;
  else 
    new_w->pushbutton.compatible = True;
  
  /*
   * showAsDefault as boolean if compatibility is false (Motif 1.1) else
   *  treat it to indicate the thickness of defaultButtonShadow.
   */
  if (new_w->pushbutton.compatible)
    new_w->pushbutton.default_button_shadow_thickness =
      new_w->pushbutton.show_as_default;
  
#ifdef DEFAULT_GLYPH_PIXMAP
  if (_XmGetDefaultGlyphPixmap(XtScreen(nw), NULL, NULL) != 
      XmUNSPECIFIED_PIXMAP) 
    {
      new_w->pushbutton.compatible = False;
      new_w->pushbutton.default_button_shadow_thickness = 0 ;
    }
#endif
  
  new_w->pushbutton.armed = FALSE;
  new_w->pushbutton.timer = 0;
  
  /* No unarm_pixmap but do have an arm_pixmap, use that. */
  if ((new_w->label.pixmap == XmUNSPECIFIED_PIXMAP) &&
      (new_w->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP))
    {
      XtWidgetProc resize;
      new_w->label.pixmap = new_w->pushbutton.arm_pixmap;
      if (request->core.width == 0)
	new_w->core.width = 0;
      if (request->core.height == 0)
	new_w->core.height = 0;
      
      _XmCalcLabelDimensions(nw);
      _XmProcessLock();
      resize = xmLabelClassRec.core_class.resize;
      _XmProcessUnlock();
      (* resize) ((Widget) new_w);
    }
  
    if ((new_w->label.label_type == XmPIXMAP ||
       new_w->label.label_type == XmPIXMAP_AND_STRING) &&
       (new_w->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP))
    {
      if (request->core.width == 0)
	new_w->core.width = 0;
      if (request->core.height == 0)
	new_w->core.height = 0;
      SetPushButtonSize(new_w);
    }
  
  new_w->pushbutton.unarm_pixmap = new_w->label.pixmap;
  
  if (new_w->pushbutton.default_button_shadow_thickness)
    {
      /*
       * Special hack for 3d enhancement of location cursor highlight.
       *  - Make the box bigger. During drawing of location cursor
       *    make it smaller.  See in Primitive.c
       *  Maybe we should use the macro: G_HighLightThickness(pbgadget);
       */
      new_w->primitive.highlight_thickness += Xm3D_ENHANCE_PIXEL;
      adjustment = Xm3D_ENHANCE_PIXEL;
      increase =  (2 * new_w->pushbutton.default_button_shadow_thickness +
		   new_w->primitive.shadow_thickness + adjustment);
      
      /* Add the increase to the core to compensate for extra space */
      if (increase != 0)
	{
	  Lab_MarginLeft(new_w) += increase;
	  Lab_MarginRight(new_w) += increase;
	  Lab_TextRect_x(new_w) += increase ;
	  new_w->core.width += (increase << 1);
	  
	  Lab_MarginTop(new_w) += increase;
	  Lab_MarginBottom(new_w) += increase;
	  Lab_TextRect_y(new_w) += increase ;
	  new_w->core.height += (increase << 1);
	}
    }
  
  if (Lab_IsMenupane(new_w))
    {
      new_w->primitive.traversal_on = TRUE;
    }  

  if (etched_in || !Lab_IsMenupane(new_w)) {
      /* Initialize GCs for fill and background */
      GetFillGC (new_w);
      GetBackgroundGC (new_w);
  }
  
}

#ifdef DEFAULT_GLYPH_PIXMAP

/*
 * DrawDefaultGlyphPixmap (pb)
 */

static void 
DrawDefaultGlyphPixmap(
        XmPushButtonWidget pb )
{ 
  int dx, dy, width, height ;
  Pixmap def_pixmap ;
  unsigned int def_pixmap_width, def_pixmap_height ;
  
  def_pixmap = _XmGetDefaultGlyphPixmap(XtScreen((Widget)(pb)), 
					&def_pixmap_width, 
					&def_pixmap_height) ;
  
  /* we draw in the margin right area here */
  dx = pb->core.width -
    (Lab_MarginRight(pb) + Lab_MarginWidth(pb) +
     pb->primitive.highlight_thickness + pb->primitive.shadow_thickness) ;
  dy = pb->primitive.highlight_thickness +
    pb->primitive.shadow_thickness + Lab_MarginTop(pb) + Lab_MarginHeight(pb) + 
      (MAX(Lab_TextRect_height(pb),
	   pb->label.acc_TextRect.height) - def_pixmap_height)/2;
  width = MIN(def_pixmap_width, Lab_MarginRight(pb));
  height = MIN(def_pixmap_height, 
	       MAX(Lab_TextRect_height(pb), pb->label.acc_TextRect.height));
  XCopyPlane (XtDisplay (pb), def_pixmap, XtWindow (pb),
	      pb->label.normal_GC, 0, 0, width, height, dx, dy, 1);
}
#endif /* DEFAULT_GLYPH_PIXMAP */

#ifdef DEFAULT_GLYPH_PIXMAP

/*
 * EraseDefaultGlyphPixmap (pb)
 */

static void 
EraseDefaultGlyphPixmap(
        XmPushButtonWidget pb )
{ 
  int dx, dy, width, height ;
  
  /* we clear the margin right area here */
  dx = pb->core.width -
    (Lab_MarginRight(pb) + Lab_MarginWidth(pb) +
     pb->primitive.highlight_thickness + pb->primitive.shadow_thickness) ;
  dy = pb->primitive.highlight_thickness +
    pb->primitive.shadow_thickness + Lab_MarginTop(pb) + Lab_MarginHeight(pb) ;

  width = Lab_MarginRight(pb) ;
  height = MAX(Lab_TextRect_height(pb), pb->label.acc_TextRect.height) ;

  XClearArea (XtDisplay (pb), XtWindow (pb),
	      dx, dy, width, height, False);
}
#endif /* DEFAULT_GLYPH_PIXMAP */

/*
 * EraseDefaultButtonShadow (pb)
 *  - Called from SetValues() - effort to optimize shadow drawing.
 */

static void 
EraseDefaultButtonShadow(
        XmPushButtonWidget pb )
{  
  int size, x, y, width, height, delta;
  XtEnum default_button_emphasis;
  
#ifdef DEFAULT_GLYPH_PIXMAP
  if (_XmGetDefaultGlyphPixmap(XtScreen((Widget)(pb)), NULL, NULL) != 
      XmUNSPECIFIED_PIXMAP) 
    {
      EraseDefaultGlyphPixmap( pb) ;
      return ;
    } 
#endif

  size = pb->pushbutton.default_button_shadow_thickness;

  if (size > 0) 
    { 
      XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));

      default_button_emphasis = xm_dpy->display.default_button_emphasis;

      switch (default_button_emphasis)
	{
	case XmEXTERNAL_HIGHLIGHT:
	  delta = pb->primitive.highlight_thickness;
	  break;

	case XmINTERNAL_HIGHLIGHT:
	  delta = Xm3D_ENHANCE_PIXEL;
	  break;

	default:
	  assert(FALSE);
	  return;
	}

      size += Xm3D_ENHANCE_PIXEL;
      x = y = delta;
      width = pb->core.width - (2 * delta);
      height = pb->core.height - (2 * delta);

      FillBorderWithParentColor(pb, size, x, y, width, height);
    }
}

/************************************************************************
 *
 *  SetValuesPrehook
 *
 ************************************************************************/

/*ARGSUSED*/
static Boolean 
SetValuesPrehook(
        Widget cw,		/* unused */
        Widget rw,		/* unused */
        Widget nw,
        ArgList args,		/* unused */
        Cardinal *num_args )	/* unused */
{
  XmPushButtonWidget new_w = (XmPushButtonWidget) nw ;
  
  /* CR 2990: Use XmNbuttonFontList as the default font. */
  if (new_w->label.font == NULL)
    new_w->label.font = XmeGetDefaultRenderTable (nw, XmBUTTON_FONTLIST);
  
  return False;
}

/*************************************<->*************************************
 *
 *  SetValues(current, request, new_w)
 *
 *************************************<->***********************************/

/*ARGSUSED*/
static Boolean 
SetValues(
        Widget cw,
        Widget rw,
        Widget nw,
        ArgList args,		/* unused */
        Cardinal *num_args )	/* unused */
{
  XmPushButtonWidget current = (XmPushButtonWidget) cw ;
  XmPushButtonWidget request = (XmPushButtonWidget) rw ;
  XmPushButtonWidget new_w = (XmPushButtonWidget) nw ;
  int increase;
  Boolean  flag = FALSE;    /* our return value */
  int adjustment;
  XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(new_w));
  Boolean etched_in = dpy->display.enable_etched_in_menu;
  
  /*
   * Fix to introduce Resource XmNdefaultBorderWidth and compatibility
   *      variable.
   *  if the XmNdefaultBorderWidth resource in the current differ from the
   *  one in "new_w", then the programmer is setting this resource - so this
   *  is known to the programmer and hence it is a Motif1.1 program.
   *  If they are same then either it is a Motif 1.0 program or there has been
   *  no change in the resource (Motif 1.1 program). If it is a Motif 1.0 
   *  program, then we should copy the value of XmNshowAsDefault to the 
   *  XmNdefaultBorderWidth. If it is  Motif 1.1 program  (Compatible
   *  flag is false) - then we should not do the copy.
   *  This logic will maintain the semantics of the  XmNshowAsDefault of Motif
   *  1.0. For a full explanation see the Design architecture document.
   */
  
  if ((current->pushbutton.default_button_shadow_thickness) !=
      (new_w->pushbutton.default_button_shadow_thickness))
    new_w->pushbutton.compatible = False;
  
  if (new_w->pushbutton.compatible)
    new_w->pushbutton.default_button_shadow_thickness =
      new_w->pushbutton.show_as_default;
  
  adjustment = AdjustHighLightThickness (new_w, current);
  
  /*
   * Compute size change.
   */
  if (new_w->pushbutton.default_button_shadow_thickness != 
      current->pushbutton.default_button_shadow_thickness)
    {
      if (new_w->pushbutton.default_button_shadow_thickness > 
	  current->pushbutton.default_button_shadow_thickness)
	{
	  increase = (2 * new_w->pushbutton.default_button_shadow_thickness +
		      new_w->primitive.shadow_thickness);
	  if (current->pushbutton.default_button_shadow_thickness > 0)
            increase -=
	      (2 * current->pushbutton.default_button_shadow_thickness +
	       current->primitive.shadow_thickness);
	}
      else
	{
	  increase = -(2 * current->pushbutton.default_button_shadow_thickness +
		       current->primitive.shadow_thickness);
	  if (new_w->pushbutton.default_button_shadow_thickness > 0)
	    increase += (2 * new_w->pushbutton.default_button_shadow_thickness +
			 new_w->primitive.shadow_thickness);
	}
      
      increase += adjustment ;
      
      if (new_w->label.recompute_size || request->core.width == 0)
	{
	  Lab_MarginLeft(new_w) += increase;
	  Lab_MarginRight(new_w) += increase;
	  new_w->core.width += (increase << 1);
	  flag = TRUE;
	}
      else if (increase != 0)
	{ 
	  /* Add the change due to default button to the core */
	  Lab_MarginLeft(new_w) += increase;
	  Lab_MarginRight(new_w) += increase;
	  new_w->core.width += (increase << 1);
	  flag = TRUE;
	}
      
      if (new_w->label.recompute_size || request->core.height == 0)
	{
	  Lab_MarginTop(new_w) += increase;
	  Lab_MarginBottom(new_w) += increase;
	  new_w->core.height += (increase << 1);
	  flag = TRUE;
	}
      else if (increase != 0)
	{ 
	  /* Add the change due to default button to the core */
	  Lab_MarginTop(new_w) += increase;
	  Lab_MarginBottom(new_w) += increase;
	  new_w->core.height += (increase << 1);
	  flag = TRUE;
	}
    }
  
  if ((new_w->pushbutton.arm_pixmap != current->pushbutton.arm_pixmap) &&
      (new_w->label.label_type == XmPIXMAP) && (new_w->pushbutton.armed)) 
    flag = TRUE;
  
  /* No unarm_pixmap but do have an arm_pixmap, use that. */
  if ((new_w->label.pixmap == XmUNSPECIFIED_PIXMAP) &&
      (new_w->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP))
    {
      XtWidgetProc resize;
      new_w->label.pixmap = new_w->pushbutton.arm_pixmap;
      if (new_w->label.recompute_size &&
          request->core.width == current->core.width)
	new_w->core.width = 0;
      if (new_w->label.recompute_size &&
          request->core.height == current->core.height)
	new_w->core.width = 0;
      
      _XmCalcLabelDimensions(nw);
      _XmProcessLock();
      resize = xmLabelClassRec.core_class.resize;
      _XmProcessUnlock();
      (* resize) ((Widget) new_w);
    }
  
  if (new_w->label.pixmap != current->label.pixmap)
    {
      new_w->pushbutton.unarm_pixmap = new_w->label.pixmap;
      if ((new_w->label.label_type == XmPIXMAP) && (!new_w->pushbutton.armed))
	flag = TRUE;
    }
  
  if ((new_w->label.label_type == XmPIXMAP ||
      new_w->label.label_type == XmPIXMAP_AND_STRING) &&
      (new_w->pushbutton.arm_pixmap != current->pushbutton.arm_pixmap))
    {
      if ((new_w->label.recompute_size))
	{
          if (request->core.width == current->core.width)
	    new_w->core.width = 0;
          if (request->core.height == current->core.height)
	    new_w->core.height = 0;
	}
      SetPushButtonSize(new_w);
      flag = TRUE;
    }
  
  if ((new_w->pushbutton.fill_on_arm != current->pushbutton.fill_on_arm) &&
      (new_w->pushbutton.armed == TRUE))
    flag = TRUE;
  

  if (! Lab_IsMenupane(new_w) || etched_in) {
      /*  See if the GC need to be regenerated and widget redrawn.  */
      if (new_w->pushbutton.arm_color != current->pushbutton.arm_color)
	{
	    if (new_w->pushbutton.armed) flag = TRUE;  /* see PIR 5091 */
	    XtReleaseGC ((Widget) new_w, new_w->pushbutton.fill_gc);
	    GetFillGC (new_w);
	}
      
      if (new_w->core.background_pixel != current->core.background_pixel ||
	  (new_w->core.background_pixmap != XmUNSPECIFIED_PIXMAP &&
	   new_w->core.background_pixmap != current->core.background_pixmap))
	{
	    flag = TRUE;  /* label will cause redisplay anyway */
	    XtReleaseGC ((Widget) new_w, new_w->pushbutton.background_gc);
	    GetBackgroundGC (new_w);
	}
  }
  
  /* OSF Fix pir 3469 */
  if (flag == False && XtIsRealized((Widget)new_w))
    {
      /* Size is unchanged - optimize the shadow drawing  */
      if ((current->pushbutton.show_as_default != 0) &&
	  (new_w->pushbutton.show_as_default == 0))
	EraseDefaultButtonShadow (new_w);
      
      if ((current->pushbutton.show_as_default == 0) &&
	  (new_w->pushbutton.show_as_default != 0))
	DrawDefaultButtonShadows (new_w);
    }
  
  return flag;
}

/**************************************************************************
 *
 * Resize(w)
 *
 **************************************************************************/

static void 
Resize(
        Widget w )
{
  register XmPushButtonWidget tb = (XmPushButtonWidget) w;

  if (Lab_IsPixmap(w) || Lab_IsPixmapAndText(w)) 
    SetPushButtonSize((XmPushButtonWidget) tb);
  else {
    XtWidgetProc    resize;
    _XmProcessLock();
    resize = xmLabelClassRec.core_class.resize;
    _XmProcessUnlock();
    (* resize)((Widget) tb);
  }
}

/************************************************************************
 *
 *  Destroy
 *	Clean up allocated resources when the widget is destroyed.
 *
 ************************************************************************/

static void 
Destroy(
        Widget w )
{
  XmPushButtonWidget pb = (XmPushButtonWidget) w ;
  XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
  Boolean etched_in = dpy->display.enable_etched_in_menu;

  if (pb->pushbutton.timer)
    XtRemoveTimeOut (pb->pushbutton.timer);
  
  if (!Lab_IsMenupane(pb) || etched_in) {
    XtReleaseGC ((Widget) pb, pb->pushbutton.fill_gc);
    XtReleaseGC ((Widget) pb, pb->pushbutton.background_gc);
  }
}

/*************************************<->*************************************
 *
 *  Redisplay (pb, event, region)
 *   Completely rewritten to accommodate defaultButtonShadowThickness
 *   Description:
 *   -----------
 *     Cause the widget, identified by pb, to be redisplayed.
 *     If XmNfillOnArm is True and the pushbutton is not in a menu,
 *     the background will be filled with XmNarmColor.
 *     If XmNinvertOnArm is True and XmNLabelType is XmPIXMAP,
 *     XmNarmPixmap will be used in the label.
 *
 *************************************<->***********************************/

/*ARGSUSED*/
static void 
Redisplay(
        Widget wid,
        XEvent *event,
        Region region )
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  
  if (XtIsRealized((Widget)pb))
    { 
      if (Lab_IsMenupane(pb))
	{
	  DrawPushButtonLabel (pb, event, region);	
	  
	  /* CR 5991:  Refresh border highlight too. */
	  if (pb->pushbutton.armed)
	    (*(((XmPushButtonWidgetClass) XtClass (pb))
	       ->primitive_class.border_highlight)) ((Widget) pb) ;
	}
      else
	{ 
	  DrawPushButtonBackground (pb);
	  DrawPushButtonLabel (pb, event, region);
	  DrawPushButtonShadows (pb);
	}
    }
}

/*
 * DrawPushButtonBackground ()
 *  - Compute the area allocated to the pushbutton and fill it with
 *    the background or the fill gc;
 */ 

static void 
DrawPushButtonBackground(
        XmPushButtonWidget pb )
{
  XRectangle box;
  GC  tmp_gc;

  ComputePBLabelArea (pb, &box);
  
  if ((pb->pushbutton.armed) && (pb->pushbutton.fill_on_arm))
    tmp_gc = pb->pushbutton.fill_gc;
  else
    tmp_gc = pb->pushbutton.background_gc;
  /* really need to fill with background if not armed ? */

  if (tmp_gc)
    XFillRectangle (XtDisplay(pb), XtWindow(pb), tmp_gc,
		    box.x, box.y, box.width, box.height);
}

/*
 * DrawPushButtonLabel (pb, event, region)
 * Draw the label contained in the pushbutton.
 */

static void 
DrawPushButtonLabel(
        XmPushButtonWidget pb,
        XEvent *event,
        Region region )
{  
  GC tmp_gc = NULL;
  Boolean replaceGC = False;
  Boolean replaceBg = False;
  Boolean deadjusted = False;
  XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));
  Boolean etched_in = dpy->display.enable_etched_in_menu;

  if (pb->pushbutton.armed &&
      ((! Lab_IsMenupane(pb) && pb->pushbutton.fill_on_arm) ||
       (Lab_IsMenupane(pb) && etched_in)))
    {
      XSetWindowBackground(XtDisplay(pb), XtWindow(pb), pb->pushbutton.arm_color);
      replaceBg = True;
      if ((pb->label.label_type == XmSTRING ||
           pb->label.label_type == XmPIXMAP_AND_STRING) && 
	  (pb->pushbutton.arm_color == pb->primitive.foreground))
	{
	  tmp_gc = pb->label.normal_GC;
	  pb->label.normal_GC = pb->pushbutton.background_gc;
	  replaceGC = True;
	}
    }
  
  if (pb->label.label_type == XmPIXMAP ||
     pb->label.label_type == XmPIXMAP_AND_STRING)
    {
	if (pb->pushbutton.armed)
	  {
	      if (pb->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP)
		  pb->label.pixmap = pb->pushbutton.arm_pixmap;
	      else
		  pb->label.pixmap = pb->pushbutton.unarm_pixmap;
	  }
	else   /* pushbutton is unarmed */
	    pb->label.pixmap = pb->pushbutton.unarm_pixmap;
    }
  
  /*
   * Temporarily remove the Xm3D_ENHANCE_PIXEL hack ("adjustment")
   *           from the margin values, so we don't confuse Label.
   */
  if (pb->pushbutton.default_button_shadow_thickness > 0)
    { 
	deadjusted = True;
	Lab_MarginLeft(pb) -= Xm3D_ENHANCE_PIXEL;
	Lab_MarginRight(pb) -= Xm3D_ENHANCE_PIXEL;
	Lab_MarginTop(pb) -= Xm3D_ENHANCE_PIXEL;
	Lab_MarginBottom(pb) -= Xm3D_ENHANCE_PIXEL;
    }
  
    {
	XtExposeProc expose;
	_XmProcessLock();
	expose = xmLabelClassRec.core_class.expose;
	_XmProcessUnlock();
	(* expose) ((Widget) pb, event, region) ;
    }

  if (deadjusted)
    {
	Lab_MarginLeft(pb) += Xm3D_ENHANCE_PIXEL;
	Lab_MarginRight(pb) += Xm3D_ENHANCE_PIXEL;
	Lab_MarginTop(pb) += Xm3D_ENHANCE_PIXEL;
	Lab_MarginBottom(pb) += Xm3D_ENHANCE_PIXEL;
    }
  
  if (replaceGC)
      pb->label.normal_GC = tmp_gc;    
  if (replaceBg) {
      XSetWindowBackground(XtDisplay(pb), XtWindow(pb), XtBackground(pb));
      if (pb->core.background_pixmap != XmUNSPECIFIED_PIXMAP) {
          XSetWindowBackgroundPixmap(XtDisplay(pb), XtWindow(pb),
	      pb->core.background_pixmap);
      }
  }
}



/*
 * DrawPushButtonShadows()
 *  Note: PushButton has two types of shadows: primitive-shadow and
 *	default-button-shadow.
 *  If pushbutton is in a menu only primitive shadows are drawn.
 */

static void 
DrawPushButtonShadows(
        XmPushButtonWidget pb )
{
  XRectangle box;
  XtEnum default_button_emphasis;
  int adjust;
  XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));

  default_button_emphasis = xm_dpy->display.default_button_emphasis;

  switch (default_button_emphasis)
    {
    case XmEXTERNAL_HIGHLIGHT:
      adjust = (pb->primitive.highlight_thickness -
		(pb->pushbutton.default_button_shadow_thickness ? 
		 Xm3D_ENHANCE_PIXEL : 0));
      break;

    case XmINTERNAL_HIGHLIGHT:
      adjust = 0;
      break;

    default:
      assert(FALSE);
      return;
    }

  /* Clear the area not occupied by label with parents background color. */
  /* Label will invoke BorderUnhighlight() on the highlight_thickness	 */
  /* area, which is redundant when XmEXTERNAL_HIGHLIGHT default button	 */
  /* shadow emphasis is used.						 */

  ComputePBLabelArea (pb, &box);
  if (box.x > adjust)
    {
      FillBorderWithParentColor(pb, 
				box.x - adjust, 
				adjust, 
				adjust,
				pb->core.width - 2 * adjust,
				pb->core.height - 2 * adjust);

      switch (default_button_emphasis)
	{
	case XmINTERNAL_HIGHLIGHT:
	  /* The call above erases the border highlighting. */
	  if (pb->primitive.highlight_drawn)
	    (*(((XmPushButtonWidgetClass) XtClass (pb))
	       ->primitive_class.border_highlight)) ((Widget) pb) ;
	  break;

	default:
	  break;
	}
    }


  if (pb->pushbutton.default_button_shadow_thickness
#ifdef DEFAULT_GLYPH_PIXMAP
      || (_XmGetDefaultGlyphPixmap(XtScreen((Widget)pb), NULL, NULL) != 
	  XmUNSPECIFIED_PIXMAP) 
#endif
      ) 
    { 
      if (pb->pushbutton.show_as_default)
	DrawDefaultButtonShadows (pb);
    }
  
  if (pb->primitive.shadow_thickness)
    DrawPBPrimitiveShadows (pb);
}

/*ARGSUSED*/
static Boolean 
ParentVisualChanged(Widget kid, 	       
		    Widget cur_parent,	/* unused */
		    Widget new_parent,	/* unused */
		    Mask visual_flag)
{
  XmPushButtonWidget pb = (XmPushButtonWidget) kid ;

  /* CR 9333: The primitive Redraw procedure only redraws the */
  /*	highighlight area, but push buttons needs to redraw the */
  /*	default button shadow emphasis area too. */  

  if (visual_flag & (VisualBackgroundPixel|VisualBackgroundPixmap)) 
    {
      XmPrimitiveClassRec* kid_class = (XmPrimitiveClassRec*) XtClass(kid);

      if (! XtIsRealized(kid)) return True;

      if (!pb->primitive.highlighted &&
	  kid_class->primitive_class.border_unhighlight)
	kid_class->primitive_class.border_unhighlight(kid);

      DrawPushButtonShadows(pb);
    }

  return False;
}

/*
 * ComputePBLabelArea()
 *	Compute the area allocated to the label of the pushbutton; 
 * fill in the dimensions in the box.
 */

static void
ComputePBLabelArea(
        XmPushButtonWidget pb,
        XRectangle *box )
{   
  int dx, adjust;
  short fill = 0;
  
  if ((pb->pushbutton.arm_color == pb->primitive.top_shadow_color) ||
      (pb->pushbutton.arm_color == pb->primitive.bottom_shadow_color))
    fill = 1;
  
  if (pb->pushbutton.compatible)
    adjust = pb->pushbutton.show_as_default; 
  else
    adjust = pb->pushbutton.default_button_shadow_thickness; 

  if (adjust > 0) 
    { 
      adjust = adjust + pb->primitive.shadow_thickness;
      adjust = (adjust << 1);
      dx = pb->primitive.highlight_thickness + adjust + fill;
    }
  else
    dx = (pb->primitive.highlight_thickness + 
	  pb->primitive.shadow_thickness + fill);
  
  box->x = dx;
  box->y = dx;
  adjust = (dx << 1);
  box->width  = pb->core.width - adjust;
  box->height = pb->core.height - adjust;
}
	
/*
 * DrawPBPrimitiveShadow (pb)
 *   - Should be called only if PrimitiveShadowThickness > 0 
 */

static void 
DrawPBPrimitiveShadows(
        XmPushButtonWidget pb )
{
  GC top_gc, bottom_gc;
  int dx, adjust, shadow_thickness;

  if (pb->pushbutton.armed)
    {
      bottom_gc = pb->primitive.top_shadow_GC;
      top_gc = pb->primitive.bottom_shadow_GC;
    }
  else 
    { 
      bottom_gc = pb->primitive.bottom_shadow_GC;
      top_gc = pb->primitive.top_shadow_GC;
    }
  
  
  shadow_thickness = pb->primitive.shadow_thickness;
  /*
   * This might have to be modified.
   *  - this is where dependency on compatibility with 1.0
   *    and defaultButtonShadowThickness etc. will showup.
   *  NOTE: defaultButtonShadowThickness is not supported in 
   *   RowColumn children.
   *  1. Compute (x,y,width,height) for the rectangle within which
   *	  the shadow is to be drawn.
   */
  
  if ((shadow_thickness > 0) && (top_gc) && (bottom_gc))
    { 
      if (pb->pushbutton.compatible)
	adjust = pb->pushbutton.show_as_default;
      else
	adjust = pb->pushbutton.default_button_shadow_thickness;

      if (adjust > 0)
	{ 
	  adjust = (adjust << 1);
	  dx = (pb->primitive.highlight_thickness + 
		adjust + pb->primitive.shadow_thickness);
	}
      else
	dx = pb->primitive.highlight_thickness ;

      /* CR 7115: Deal with degenerate cases. */
      if ((pb->core.width > 2 * dx) &&
	  (pb->core.height > 2 * dx))
	XmeDrawShadows (XtDisplay (pb), XtWindow (pb), top_gc, bottom_gc, 
			dx, dx, 
			pb->core.width - 2 * dx, 
			pb->core.height - 2 * dx, 
			shadow_thickness, XmSHADOW_OUT);
    }
}

/*
 * DrawDefaultButtonShadows()
 *  - get the topShadowColor and bottomShadowColor from the parent;
 *    use those colors to construct top and bottom gc; use these
 *	  GCs to draw the shadows of the button.
 *  - Should not be called if pushbutton is in a row column or in a menu.
 *  - Should be called only if a defaultbuttonshadow is to be drawn.
 */      

static void 
DrawDefaultButtonShadows(
        XmPushButtonWidget pb )
{
  GC	 top_gc, bottom_gc;
  int	 default_button_shadow_thickness;
  int	 x, y, width, height, delta;
  Widget parent;
  XtEnum default_button_emphasis;
  XmDisplay xm_dpy;
  
  if (pb->pushbutton.compatible && 
      (pb->pushbutton.show_as_default == 0))
    return;
  
#ifdef DEFAULT_GLYPH_PIXMAP
  if (_XmGetDefaultGlyphPixmap(XtScreen((Widget)(pb)), NULL, NULL) != 
      XmUNSPECIFIED_PIXMAP) 
    {
      DrawDefaultGlyphPixmap( pb) ;
      return ;
    } 
#endif
  
  if (!pb->pushbutton.compatible &&
      (pb->pushbutton.default_button_shadow_thickness == 0))
    return ;
  
  /*
   * May need more complex computation for getting the GCs.
   */
  parent = XtParent(pb);
  if (XmIsManager(parent)) 
    {  
      /* CR 5894:  Use the parent's GC so monochrome works. */
      bottom_gc = XmParentTopShadowGC(pb);
      top_gc = XmParentBottomShadowGC(pb);
    }
  else
    { 
      /* Use your own pixel for drawing. */
      bottom_gc = pb->primitive.top_shadow_GC;
      top_gc = pb->primitive.bottom_shadow_GC;
    }
  
  if ((bottom_gc == None) || (top_gc == None)) 
    return;
  
  
  if (pb->pushbutton.compatible)
    default_button_shadow_thickness = pb->pushbutton.show_as_default;
  else    
    default_button_shadow_thickness = 
      pb->pushbutton.default_button_shadow_thickness;
  
  
  /*
   * Compute location of bounding box to contain the defaultButtonShadow.
   */
  xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));
  default_button_emphasis = xm_dpy->display.default_button_emphasis;

  switch (default_button_emphasis)
    {
    case XmEXTERNAL_HIGHLIGHT:
      delta = pb->primitive.highlight_thickness;
      break;

    case XmINTERNAL_HIGHLIGHT:
      delta = Xm3D_ENHANCE_PIXEL;
      break;

    default:
      assert(FALSE);
      return;
    }

  x = y = delta;
  width = pb->core.width - 2 * delta;
  height = pb->core.height - 2 * delta;

  if ((width > 0) && (height > 0))
    XmeDrawShadows(XtDisplay(pb), XtWindow(pb), 
		   top_gc, bottom_gc, x, y, width, height,
		   default_button_shadow_thickness, XmSHADOW_OUT); 
}

/*************************************<->*************************************
 *
 *  BorderHighlight 
 *
 *************************************<->***********************************/

static void 
BorderHighlight(
        Widget wid )
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;
  XEvent * event = NULL;
  
  if (Lab_IsMenupane(pb))
    {
       XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid));
       Boolean etched_in = dpy->display.enable_etched_in_menu;
       Boolean already_armed = pb->pushbutton.armed;

       pb->pushbutton.armed = TRUE;

       if (etched_in && !XmIsTearOffButton(pb) ) 
	 {
	     XFillRectangle (XtDisplay(pb), XtWindow(pb),
			     pb->pushbutton.fill_gc,
			     0, 0, pb->core.width, pb->core.height);

	     DrawPushButtonLabel (pb, event, NULL);	
	 }
      
       if ((pb->core.width > 2 * pb->primitive.highlight_thickness) &&
	   (pb->core.height > 2 * pb->primitive.highlight_thickness))
	   XmeDrawShadows(XtDisplay (pb), XtWindow (pb),
		       pb->primitive.top_shadow_GC,
		       pb->primitive.bottom_shadow_GC,
		       pb->primitive.highlight_thickness,
		       pb->primitive.highlight_thickness,
		       pb->core.width - 2 * pb->primitive.highlight_thickness,
		       pb->core.height - 2 * pb->primitive.highlight_thickness,
		       pb->primitive.shadow_thickness, 
		       etched_in ? XmSHADOW_IN : XmSHADOW_OUT);
      
       if (!already_armed && pb->pushbutton.arm_callback) 
	 {
	     XFlush (XtDisplay (pb));
	  
	     call_value.reason = XmCR_ARM;
	     call_value.event = event;
	     XtCallCallbackList ((Widget) pb, pb->pushbutton.arm_callback, 
				 &call_value);
	 }
   }
  else 
    {
      DrawBorderHighlight ((Widget) pb) ;
    } 
}

static void
DrawBorderHighlight(
        Widget wid)
{   
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  int x, y, width, height, delta;
  Dimension highlight_width ;
  XtEnum default_button_emphasis;
  
  if (!XtWidth (pb) || !XtHeight (pb))
    return;

  pb->primitive.highlighted = True;
  pb->primitive.highlight_drawn = True;
  
  if (pb->pushbutton.default_button_shadow_thickness)
    highlight_width = pb->primitive.highlight_thickness - Xm3D_ENHANCE_PIXEL;
  else
    highlight_width = pb->primitive.highlight_thickness;
  
  if (highlight_width > 0)
    {
      XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));

      default_button_emphasis = xm_dpy->display.default_button_emphasis;

      switch (default_button_emphasis)
	{
	case XmEXTERNAL_HIGHLIGHT:
	  delta = 0;
	  break;

	case XmINTERNAL_HIGHLIGHT:
	  if (pb->pushbutton.default_button_shadow_thickness)
	    delta = Xm3D_ENHANCE_PIXEL +
	      2 * (pb->pushbutton.compatible ?
		   pb->pushbutton.show_as_default :
		   pb->pushbutton.default_button_shadow_thickness);
	  else
	    delta = 0;
	  break;

	default:
	  assert(FALSE);
	  return;
	}

      x = y = delta;
      width = pb->core.width - 2 * delta;
      height = pb->core.height - 2 * delta;

      XmeDrawHighlight(XtDisplay(pb), XtWindow(pb), pb->primitive.highlight_GC,
		       x, y, width, height, highlight_width);
    }
} 

/*************************************<->*************************************
 *
 *  BorderUnhighlight
 *
 *************************************<->***********************************/

static void 
BorderUnhighlight(
        Widget wid )
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;
  XEvent * event = NULL;

  if (Lab_IsMenupane(pb))
    {
     XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid));
     Boolean etched_in = dpy->display.enable_etched_in_menu;
     Boolean already_armed = pb->pushbutton.armed;

     pb->pushbutton.armed = FALSE;

     if (etched_in && !XmIsTearOffButton(pb) ) {
	  XFillRectangle (XtDisplay(pb), XtWindow(pb),
			  pb->pushbutton.background_gc,
			  0, 0, pb->core.width, pb->core.height);
	  DrawPushButtonLabel (pb, event, NULL);
     }
      else
	  XmeClearBorder (
		  XtDisplay (pb), XtWindow (pb),
		  pb->primitive.highlight_thickness,
		  pb->primitive.highlight_thickness,
		  pb->core.width - 2 * pb->primitive.highlight_thickness,
		  pb->core.height - 2 * pb->primitive.highlight_thickness,
		  pb->primitive.shadow_thickness);
      
      
      if (already_armed && pb->pushbutton.disarm_callback)
	{
	  XFlush (XtDisplay (pb));
	  
	  call_value.reason = XmCR_DISARM;
	  call_value.event = event;
	  XtCallCallbackList ((Widget) pb, pb->pushbutton.disarm_callback, 
			      &call_value);
	}
    }
  else 
    {
      /* PushButton is not in a menu - parent may be a shell or manager */
      int border = pb->primitive.highlight_thickness - Xm3D_ENHANCE_PIXEL;
      XtEnum default_button_emphasis;
      XmDisplay xm_dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));

      default_button_emphasis = xm_dpy->display.default_button_emphasis;

      switch (default_button_emphasis)
	{
	case XmINTERNAL_HIGHLIGHT:
	  if (pb->pushbutton.default_button_shadow_thickness && (border > 0))
	    {
	      int x, y, width, height, delta;

	      pb->primitive.highlighted = False;
	      pb->primitive.highlight_drawn = False;

	      delta = Xm3D_ENHANCE_PIXEL + 
		2 * (pb->pushbutton.compatible ?
		     pb->pushbutton.show_as_default :
		     pb->pushbutton.default_button_shadow_thickness);
	    
	      x = y = delta;
	      width = pb->core.width - 2 * delta;
	      height = pb->core.height - 2 * delta;

	      FillBorderWithParentColor(pb, border, x, y, width, height);
	      break;
	    }
	  /* else fall through to XmEXTERNAL_HIGHLIGHT. */

	case XmEXTERNAL_HIGHLIGHT:
	  (*(xmLabelClassRec.primitive_class.border_unhighlight)) (wid) ;
	  break;

	default:
	  assert(FALSE);
	  return;
	}
    }
}

/*
 * AdjustHighLightThickness ()
 *  HighlightThickness has a dependency on default_button-shadow-thickness;
 *  This routine (called from SetValues) adjust for that dependency.
 *  Applications should be aware that
 *  if a pushbutton gadget has  with (default_button-shadow-thickness == 0)
 * - then if through a XtSetValue it sets (default_button-shadow-thickness > 0)
 *  the application-specified highlight-thickness is internally increased by
 *  Xm3D_ENHANCE_PIXEL to enhance the 3D-appearance of the defaultButton
 *  Shadow. Similarly if a pushbutton gadget has  (default_button-shadow_
 *  thickness > 0), and it resets the (default_button-shadow-thickness = 0)
 *  through a XtSetValue , then the existing highlight-thickness is decreased
 *  by Xm3D_ENHANCE_PIXEL.
 *  The border-highlight when drawn is however is always of the same
 *  thickness as specified by the application since compensation is done
 *  in the drawing routine (see BorderHighlight).
 */

static int 
AdjustHighLightThickness(
        XmPushButtonWidget new_w,
        XmPushButtonWidget current )
{
  int adjustment = 0; 
  
  
  if (new_w->pushbutton.default_button_shadow_thickness > 0)
    {
      if (current->pushbutton.default_button_shadow_thickness == 0)
	{
	  new_w->primitive.highlight_thickness += Xm3D_ENHANCE_PIXEL;
	  adjustment = Xm3D_ENHANCE_PIXEL;
	}
      else if (new_w->primitive.highlight_thickness !=
	       current->primitive.highlight_thickness)
	{
	  new_w->primitive.highlight_thickness += Xm3D_ENHANCE_PIXEL;
	  adjustment = Xm3D_ENHANCE_PIXEL;
	}
    }
  else
    { 
      if (current->pushbutton.default_button_shadow_thickness > 0)
        /* default_button_shadow_thickness was > 0 and is now being set to 0,
         * so take away the adjustment for enhancement.
         */
	{
	  if (new_w->primitive.highlight_thickness ==
	      current->primitive.highlight_thickness)
	    {
	      new_w->primitive.highlight_thickness -= Xm3D_ENHANCE_PIXEL;
	      adjustment -= Xm3D_ENHANCE_PIXEL;
	    }
	  /*
	   * This will appear to be a bug if in a XtSetValues the application
	   * removes the default_button_shadow_thickness and also
	   * sets the high-light-thickness to a value of
	   * (old-high-light-thickness (from previous XtSetValue) +
	   *  Xm3D_ENHANCE_PIXEL) at the same time.
	   * This will be documented.
	   */
	}
    }

  return (adjustment);
}

static void 
FillBorderWithParentColor(
        XmPushButtonWidget pb,
        int borderwidth,
        int dx,
        int dy,
        int rectwidth,
        int rectheight )
{
  if (XmIsManager(XtParent(pb)))
    {
      /* CR 5551: Use the manager gc rather than creating a new one. */
      XmeDrawHighlight(XtDisplay(pb), XtWindow(pb), XmParentBackgroundGC(pb),
		       dx, dy, rectwidth, rectheight, borderwidth);
    }
  else 
    {
      /* CR 6038: This is wrong, but is the way Label (by calling
       *	Primitive.c:UnhighlightBorder) clears borders in shells.
       */
      XmeClearBorder(XtDisplay(pb), XtWindow(pb),
		     dx, dy, rectwidth, rectheight, borderwidth);
    }
}

/*************************************************************************
 *
 * SetPushButtonSize(newpb)
 *  Picks the larger dimension when the armPixmap is a
 *  different size than the label pixmap(i.e the unarm pixmap).
 *
 ************************************************************************/

static void
SetPushButtonSize(
     XmPushButtonWidget newpb)
{
  XmLabelPart *lp = &(newpb->label);
  unsigned int onW = 0, onH = 0, onW2 = 0, onH2 = 0;
  XtWidgetProc resize;
  
  if (newpb->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP)
    {
#ifdef FIX_1516
      if (newpb->label.pixmap != XmUNSPECIFIED_PIXMAP)
#endif
      XmeGetPixmapData(XtScreen(newpb), newpb->label.pixmap,
		     NULL, NULL, NULL, NULL, NULL, NULL,
		     &onW, &onH);
      XmeGetPixmapData(XtScreen(newpb), newpb->pushbutton.arm_pixmap,
		     NULL, NULL, NULL, NULL, NULL, NULL,
		     &onW2, &onH2);
      newpb->label.PixmapRect.width = MAX(onW2, onW);
      newpb->label.PixmapRect.height = MAX(onH2, onH);
      _XmLabelCalcTextRect((Widget)newpb);
    }
  
  
  /* Let Label do the rest. */
  _XmProcessLock();
  resize = xmLabelClassRec.core_class.resize;
  _XmProcessUnlock();
  (* resize) ((Widget) newpb);
}

/************************************************************************
 *
 *    Actions -----------
 *
 ************************************************************************/

/************************************************************************
 *
 *     Arm
 *
 *     This function processes button 1 down occuring on the pushbutton.
 *     Mark the pushbutton as armed (i.e. active).
 *     The callbacks for XmNarmCallback are called.
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
Arm(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;
  XtExposeProc expose;

  (void) XmProcessTraversal ((Widget) pb, XmTRAVERSE_CURRENT);
  
  pb->pushbutton.armed = TRUE;
  
  if (event != NULL &&
      (event->xany.type == ButtonPress || event->xany.type == ButtonRelease))
    pb->pushbutton.armTimeStamp = event->xbutton.time;
  else
    pb->pushbutton.armTimeStamp = 0;
  
  _XmProcessLock();
  expose = XtClass(pb)->core_class.expose;
  _XmProcessUnlock();
  (* expose)(wid, event, (Region) NULL);
  
  if (pb->pushbutton.arm_callback)
    {
      XFlush(XtDisplay (pb));
      
      call_value.reason = XmCR_ARM;
      call_value.event = event;
      XtCallCallbackList((Widget) pb, pb->pushbutton.arm_callback, &call_value);
    }
}

/*ARGSUSED*/
static void 
MultiArm(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  
  if (pb->pushbutton.multiClick == XmMULTICLICK_KEEP)
    Arm ((Widget) pb, event, NULL, NULL);
}

/************************************************************************
 *
 *     Activate
 *
 *     Mark the pushbutton as unarmed (i.e. inactive).
 *     If the button release occurs inside of the PushButton, the 
 *     callbacks for XmNactivateCallback are called.
 *
 ************************************************************************/
static void 
Activate(
        Widget wid,
        XEvent *buttonEvent,
        String *params,
        Cardinal *num_params )
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;

  if (pb->pushbutton.armed == FALSE)
    return;
  
  pb->pushbutton.click_count = 1;
  ActivateCommon ((Widget) pb, buttonEvent, params, num_params);
}

static void 
MultiActivate(
        Widget wid,
        XEvent *buttonEvent,
        String *params,
        Cardinal *num_params )
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;

  /* When a multi click sequence occurs and the user Button Presses and
   * holds for a length of time, the final release should look like a
   * new_w/separate activate.
   */
  if (pb->pushbutton.multiClick == XmMULTICLICK_KEEP)
    {
      if ((buttonEvent->xbutton.time - pb->pushbutton.armTimeStamp) >
	  XtGetMultiClickTime(XtDisplay(pb)))
	pb->pushbutton.click_count = 1;
      else
        pb->pushbutton.click_count++;

      ActivateCommon ((Widget) pb, buttonEvent, params, num_params);
      Disarm ((Widget) pb, buttonEvent, params, num_params);
    }
}

/*ARGSUSED*/
static void 
ActivateCommon(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;
  XmMenuSystemTrait menuSTrait;
  XtExposeProc expose;
  
  pb->pushbutton.armed = FALSE;
  
  _XmProcessLock();
  expose = ((WidgetClass)XtClass(pb))->core_class.expose;
  _XmProcessUnlock();

  (* expose)(wid, event, (Region) NULL);
  
  /* CR 9181: Consider clipping when testing visibility. */
  if ((event->xany.type == ButtonPress || event->xany.type == ButtonRelease) &&
      _XmGetPointVisibility(wid, event->xbutton.x_root, event->xbutton.y_root))
    {
      call_value.reason = XmCR_ACTIVATE;
      call_value.event = event;
      call_value.click_count = pb->pushbutton.click_count;
      
      if ((pb->pushbutton.multiClick == XmMULTICLICK_DISCARD) &&	
	  (call_value.click_count > 1))
	return;
      
      menuSTrait = (XmMenuSystemTrait) 
	XmeTraitGet((XtPointer) XtClass(XtParent(pb)), XmQTmenuSystem);
      
      /* if the parent is menu system able, notify it about the select */
      if (menuSTrait != NULL)
	menuSTrait->entryCallback(XtParent(pb), (Widget) pb, &call_value);
      
      if ((! pb->label.skipCallback) &&
	  (pb->pushbutton.activate_callback))
	{
	  XFlush (XtDisplay (pb));
	  XtCallCallbackList ((Widget) pb, pb->pushbutton.activate_callback,
			      &call_value);
	}
    }
}



static void 
PB_FixTearoff( XmPushButtonWidget pb)	
{
	 if  (XmMENU_PULLDOWN == pb->label.menu_type) 
	 {							
		Widget mwid = XmGetPostedFromWidget(XtParent(pb));	
		if (mwid && XmIsRowColumn(mwid)
			&& (XmMENU_OPTION == RC_Type(mwid)) 
			&& _XmIsActiveTearOff(XtParent(pb))) 
			XmProcessTraversal((Widget) pb, XmTRAVERSE_CURRENT);
	 }							
}
/************************************************************************
 *
 *     ArmAndActivate
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
ArmAndActivate(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{  
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  Boolean already_armed = pb->pushbutton.armed;
  XmPushButtonCallbackStruct call_value;
  Boolean is_menupane = Lab_IsMenupane(pb);
  Boolean torn_has_focus = FALSE;	/* must be torn! */
  XmMenuSystemTrait menuSTrait;
  
  if (is_menupane && !XmIsMenuShell(XtParent(XtParent(pb))))
    {
      /* Because the pane is torn and the parent is a transient shell,
       * the shell's focal point from _XmGetFocusData should be valid
       * (as opposed to getting it from a MenuShell).
       */
      if (XmeFocusIsInShell((Widget)pb))
	{
	  /* In case allowAcceleratedInsensitiveUnmanagedMenuItems is True */
	  if (!XtIsSensitive((Widget)pb) || (!XtIsManaged((Widget)pb)))
            return;
	  torn_has_focus = TRUE;
	}
    }
  
  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass((Widget)XtParent(pb)), XmQTmenuSystem);
  if (is_menupane && menuSTrait != NULL)
    {
      pb->pushbutton.armed = FALSE;
      
      /* CR 7799: Torn off menus shouldn't be shared, so don't reparent. */
      if (torn_has_focus)
	menuSTrait->popdown(XtParent(pb), event);
      else
	menuSTrait->buttonPopdown(XtParent(pb), event);
      
      /* if its in a torn off menu pane, show depressed button briefly */
      if (torn_has_focus)
	{
	  XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));
	  Boolean etched_in = dpy->display.enable_etched_in_menu;
	  
	  /* Set the focus here. */
	  XmProcessTraversal((Widget) pb, XmTRAVERSE_CURRENT);
	  
	  if ((pb->core.width > 2 * pb->primitive.highlight_thickness) &&
	      (pb->core.height > 2 * pb->primitive.highlight_thickness))
	    XmeDrawShadows
	      (XtDisplay (pb), XtWindow (pb),
	       pb->primitive.bottom_shadow_GC, pb->primitive.top_shadow_GC,
	       pb->primitive.highlight_thickness,
	       pb->primitive.highlight_thickness,
	       pb->core.width - 2 * pb->primitive.highlight_thickness,
	       pb->core.height - 2 * pb->primitive.highlight_thickness,
	       pb->primitive.shadow_thickness, 
	       etched_in ? XmSHADOW_IN : XmSHADOW_OUT);
	}
    }
  else 
    {
      XtExposeProc expose;
      pb->pushbutton.armed = TRUE;
      _XmProcessLock();
      expose = XtClass(pb)->core_class.expose;
      _XmProcessUnlock();
      (* expose)(wid, event, (Region) NULL);
    }
  
  XFlush (XtDisplay (pb));
  
  /* If the parent is menu system able, set the lastSelectToplevel before
   * the arm. It's ok if this is recalled later.
   */
  if (menuSTrait != NULL)
    menuSTrait->getLastSelectToplevel(XtParent(pb));
  
  if (pb->pushbutton.arm_callback && !already_armed)
    {
      call_value.reason = XmCR_ARM;
      call_value.event = event;
      XtCallCallbackList((Widget)pb, pb->pushbutton.arm_callback, &call_value);
    }
  
  call_value.reason = XmCR_ACTIVATE;
  call_value.event = event;
  call_value.click_count = 1;	           /* always 1 in kselect */
  
  /* if the parent is menu system able, notify it about the select */
  if (menuSTrait != NULL)
    menuSTrait->entryCallback(XtParent(pb), (Widget)pb, &call_value);
#ifdef FIX_1375
	pb->label.pixmap = pb->pushbutton.unarm_pixmap;
#endif 
  if ((! pb->label.skipCallback) && (pb->pushbutton.activate_callback))
    {
      XFlush (XtDisplay (pb));
      XtCallCallbackList ((Widget) pb, pb->pushbutton.activate_callback,
			  &call_value);
    }
  
  pb->pushbutton.armed = FALSE;
  
  if (pb->pushbutton.disarm_callback)
    {
      XFlush (XtDisplay (pb));
      call_value.reason = XmCR_DISARM;
      XtCallCallbackList ((Widget) pb, pb->pushbutton.disarm_callback,
			  &call_value);
    }
  
  if (is_menupane && menuSTrait != NULL)
    {
      if (torn_has_focus && XtIsSensitive(wid))
	{
	  /* Leave the focus widget in an armed state */
	  pb->pushbutton.armed = TRUE;
	  
	  if (pb->pushbutton.arm_callback)
	    {
	      XFlush (XtDisplay (pb));
	      call_value.reason = XmCR_ARM;
	      XtCallCallbackList ((Widget) pb, pb->pushbutton.arm_callback,
				  &call_value);
	    }
	}
      else
	{
	  menuSTrait->reparentToTearOffShell(XtParent(pb), event);
	  PB_FixTearoff(pb);
	}
    }
  
  /*
   * If the button is still around, show it released, after a short delay.
   * This is done if the button is outside of a menus, or if in a torn
   * off menupane.
   */
  
  if (!is_menupane || torn_has_focus)
    {
      if ((pb->core.being_destroyed == False) && (!pb->pushbutton.timer))
        pb->pushbutton.timer = 
	  XtAppAddTimeOut (XtWidgetToApplicationContext((Widget)pb),
			   (unsigned long) DELAY_DEFAULT,
			   ArmTimeout,
			   (XtPointer)(pb));
    }
}

/*ARGSUSED*/
static void 
ArmTimeout(
        XtPointer data,
        XtIntervalId *id )
{ 
  XmPushButtonWidget pb = (XmPushButtonWidget) data;
  
  pb->pushbutton.timer = 0;
  if (XtIsRealized ((Widget)pb) && XtIsManaged ((Widget)pb))
    {
      if (Lab_IsMenupane(pb))
	{
	  /* When rapidly clicking, the focus may have moved away from this
	   * widget, so check before changing the shadow.
	   */
	  if (XmeFocusIsInShell((Widget)pb) &&
	      (XmGetFocusWidget((Widget)pb) == (Widget)pb))
	    {
	      XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));
	      Boolean etched_in = dpy->display.enable_etched_in_menu;

	      /* in a torn off menu, redraw shadows */
	      if ((pb->core.width > 2 * pb->primitive.highlight_thickness) &&
		  (pb->core.height > 2 * pb->primitive.highlight_thickness))
		XmeDrawShadows
		  (XtDisplay (pb), XtWindow (pb),
		   pb->primitive.top_shadow_GC,
		   pb->primitive.bottom_shadow_GC,
		   pb->primitive.highlight_thickness,
		   pb->primitive.highlight_thickness,
		   pb->core.width - 2 * pb->primitive.highlight_thickness,
		   pb->core.height - 2 * pb->primitive.highlight_thickness,
		   pb->primitive.shadow_thickness, 
		   etched_in ? XmSHADOW_IN : XmSHADOW_OUT);
	    }
	}
      else
	{
	  XtExposeProc expose;
	  _XmProcessLock();
	  expose = XtClass(pb)->core_class.expose;
	  _XmProcessUnlock();
	  (* expose) ((Widget) pb, NULL, (Region) NULL);
	}
      
      XFlush (XtDisplay (pb));
    }
}

/************************************************************************
 *
 *    Disarm
 *
 *     Mark the pushbutton as unarmed (i.e. active).
 *     The callbacks for XmNdisarmCallback are called..
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
Disarm(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;
  XtExposeProc expose;
  
  /* BEGIN OSF Fix pir 2826 */
  if (pb->pushbutton.armed == TRUE)
    {
      pb->pushbutton.armed = FALSE;
      Redisplay((Widget) pb, event, (Region)NULL);
      _XmProcessLock();
      expose = XtClass(pb)->core_class.expose;
      _XmProcessUnlock();
      if (expose)
        (* expose)((Widget)(pb), event, (Region)NULL);
      
    }
  /* END OSF Fix pir 2826 */
  
  if (pb->pushbutton.disarm_callback)
    {
      call_value.reason = XmCR_DISARM;
      call_value.event = event;
      XtCallCallbackList ((Widget) pb, pb->pushbutton.disarm_callback, 
			  &call_value);
    }
}

/************************************************************************
 *
 *     BtnDown
 *
 *     This function processes a button down occuring on the pushbutton
 *     when it is in a popup, pulldown, or option menu.
 *     Popdown the posted menu.
 *     Turn parent's traversal off.
 *     Mark the pushbutton as armed (i.e. active).
 *     The callbacks for XmNarmCallback are called.
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
BtnDown(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;
  Boolean validButton = False;
  Boolean already_armed;
  ShellWidget popup;
  XmMenuSystemTrait menuSTrait;
  
  /* Support menu replay, free server input queue until next button event */
  XAllowEvents(XtDisplay(pb), SyncPointer, CurrentTime);
  
  /* If no menu system trait then parent isn't a menu as it should be. */
  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass(XtParent(pb)), XmQTmenuSystem);
  if (menuSTrait == NULL) 
    return;
  
  if (event && (event->type == ButtonPress))
    validButton = menuSTrait->verifyButton(XtParent(pb), event);
  
  if (!validButton)
    return;
  
  _XmSetInDragMode((Widget)pb, True);
  
  /* Popdown other popus that may be up */
  if (!(popup = (ShellWidget)_XmGetRC_PopupPosted(XtParent(pb))))
    {
      if (!XmIsMenuShell(XtParent(XtParent(pb))))
	{
	  /* In case tear off not armed and no grabs in place, do it now.
	   * Ok if already armed and grabbed - nothing done.
	   */
	  menuSTrait->tearOffArm(XtParent(pb));
	}
    }
  
  if (popup)
    {
      if (popup->shell.popped_up)
	menuSTrait->popdownEveryone((Widget) popup, event);
    } 
  
  /* Set focus to this pushbutton.  This must follow the possible
   * unhighlighting of the CascadeButton else it'll screw up active_child.
   */
  (void)XmProcessTraversal ((Widget) pb, XmTRAVERSE_CURRENT);
  /* get the location cursor - get consistent with Gadgets */
  
  already_armed = pb->pushbutton.armed;
  pb->pushbutton.armed = TRUE;
  
  if (pb->pushbutton.arm_callback && !already_armed)
    {
      XFlush (XtDisplay (pb));
      
      call_value.reason = XmCR_ARM;
      call_value.event = event;
      XtCallCallbackList((Widget) pb, pb->pushbutton.arm_callback, &call_value);
    }
  _XmRecordEvent (event);
}

/************************************************************************
 *
 *     BtnUp
 *
 *     This function processes a button up occuring on the pushbutton
 *     when it is in a popup, pulldown, or option menu.
 *     Mark the pushbutton as unarmed (i.e. inactive).
 *     The callbacks for XmNactivateCallback are called.
 *     The callbacks for XmNdisarmCallback are called.
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
BtnUp(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  Widget parent =  XtParent(pb);
  XmPushButtonCallbackStruct call_value;
  Boolean flushDone = False;
  Boolean validButton = False;
  Boolean popped_up;
  Boolean is_menupane = Lab_IsMenupane(pb);
  Widget shell = XtParent(XtParent(pb));
  XmMenuSystemTrait menuSTrait;
  
  /* If no menu system trait then parent isn't a menu as it should be. */
  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass(XtParent(pb)), XmQTmenuSystem);
  if (menuSTrait == NULL) 
    return;
  
  if (event && (event->type == ButtonRelease))
    validButton = menuSTrait->verifyButton(parent, event);
  
  if (!validButton || (pb->pushbutton.armed == FALSE))
    return;
  
  pb->pushbutton.armed = FALSE;
  
  if (is_menupane && !XmIsMenuShell(shell))
    popped_up = menuSTrait->popdown((Widget) pb, event);
  else
    popped_up = menuSTrait->buttonPopdown((Widget) pb, event);
  
  _XmRecordEvent(event);
  
  /* XmMENU_POPDOWN left the menu posted on button click - don't activate! */
  if (popped_up)
    return;
  
  call_value.reason = XmCR_ACTIVATE;
  call_value.event = event;
  call_value.click_count = 1;  

  /* if the parent is menu system able, notify it about the select */
  if (menuSTrait != NULL)
    {
      menuSTrait->entryCallback(parent, (Widget) pb, &call_value);
      flushDone = True;
    }
  
  if ((! pb->label.skipCallback) &&
      (pb->pushbutton.activate_callback))
    {
      XFlush (XtDisplay (pb));
      flushDone = True;
      XtCallCallbackList ((Widget) pb, pb->pushbutton.activate_callback,
			  &call_value);
    }
  if (pb->pushbutton.disarm_callback)
    {
      if (!flushDone)
	XFlush (XtDisplay (pb));
      call_value.reason = XmCR_DISARM;
      call_value.event = event;
      XtCallCallbackList ((Widget) pb, pb->pushbutton.disarm_callback,
			  &call_value);
    }
  
  /* If the original shell does not indicate an active menu, but rather a
   * tear off pane, leave the button in an armed state.  Also, briefly
   * display the button as depressed to give the user some feedback of
   * the selection.
   */
  
  if (is_menupane) /* necessary check? */
    {
      if (!XmIsMenuShell(shell))
	{
	  if (XtIsSensitive((Widget)pb))
	    {
	      XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(pb));
	      Boolean etched_in = dpy->display.enable_etched_in_menu;
	      
	      if ((pb->core.width > 2 * pb->primitive.highlight_thickness) &&
		  (pb->core.height > 2 * pb->primitive.highlight_thickness))
		XmeDrawShadows
		  (XtDisplay (pb), XtWindow (pb),
		   pb->primitive.bottom_shadow_GC,
		   pb->primitive.top_shadow_GC,
		   pb->primitive.highlight_thickness,
		   pb->primitive.highlight_thickness,
		   pb->core.width - 2 * pb->primitive.highlight_thickness,
		   pb->core.height - 2 * pb->primitive.highlight_thickness,
		   pb->primitive.shadow_thickness, 
		   etched_in ? XmSHADOW_IN : XmSHADOW_OUT);
	      
	      XFlush (XtDisplay (pb));
	      flushDone = True;

	      if (pb->core.being_destroyed == False)
		{
		  if (!pb->pushbutton.timer)
		    pb->pushbutton.timer =
		      XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)pb),
				      (unsigned long) DELAY_DEFAULT,
				      ArmTimeout,
				      (XtPointer)(pb));
		}
	      
	      pb->pushbutton.armed = TRUE;
	      if (pb->pushbutton.arm_callback)
		{
		  if (!flushDone)
		    XFlush (XtDisplay (pb));
		  call_value.reason = XmCR_ARM;
		  call_value.event = event;
		  XtCallCallbackList ((Widget) pb, pb->pushbutton.arm_callback,
				      &call_value);
		}
	    }
	}
      else
	menuSTrait->reparentToTearOffShell(XtParent(pb), event);
    }
  
  _XmSetInDragMode((Widget)pb, False);
  
  /* For the benefit of tear off menus, we must set the focus item
   * to this button.  In normal menus, this would not be a problem
   * because the focus is cleared when the menu is unposted.
   */
  if (!XmIsMenuShell(shell))
    XmProcessTraversal((Widget) pb, XmTRAVERSE_CURRENT);
  PB_FixTearoff(pb);
}

/************************************************************************
 *
 *  Enter
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
Enter(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;

  if (Lab_IsMenupane(pb))
    {
      if ((((ShellWidget) XtParent(XtParent(pb)))->shell.popped_up) &&
          _XmGetInDragMode((Widget)pb))
	{
	  XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid));
	  Boolean etched_in = dpy->display.enable_etched_in_menu;

	  if (pb->pushbutton.armed)
	    return;
	  
	  /* So KHelp event is delivered correctly */
	  _XmSetFocusFlag (XtParent(XtParent(pb)), XmFOCUS_IGNORE, TRUE);
	  XtSetKeyboardFocus(XtParent(XtParent(pb)), (Widget)pb);
	  _XmSetFocusFlag (XtParent(XtParent(pb)), XmFOCUS_IGNORE, FALSE);

	  pb -> pushbutton.armed = TRUE;

	  ((XmManagerWidget) XtParent(wid))->manager.active_child = wid;

	  /* etched in menu button */
	  if (etched_in && !XmIsTearOffButton(pb) ) {

	      XFillRectangle (XtDisplay(pb), XtWindow(pb),
			      pb->pushbutton.fill_gc,
			      0, 0, pb->core.width, pb->core.height);
	      DrawPushButtonLabel( pb, event, NULL );
	  }

	  if ((pb->core.width > 2 * pb->primitive.highlight_thickness) &&
	      (pb->core.height > 2 * pb->primitive.highlight_thickness))
	    XmeDrawShadows
	      (XtDisplay (pb), XtWindow (pb),
	       pb->primitive.top_shadow_GC,
	       pb->primitive.bottom_shadow_GC,
	       pb->primitive.highlight_thickness,
	       pb->primitive.highlight_thickness,
	       pb->core.width - 2 * pb->primitive.highlight_thickness,
	       pb->core.height - 2 * pb->primitive.highlight_thickness,
	       pb->primitive.shadow_thickness, 
	       etched_in ? XmSHADOW_IN : XmSHADOW_OUT);

	  if (pb->pushbutton.arm_callback)
	    {
	      XFlush (XtDisplay (pb));
	      
	      call_value.reason = XmCR_ARM;
	      call_value.event = event;
	      XtCallCallbackList ((Widget) pb,
				  pb->pushbutton.arm_callback, &call_value);
	    }
	}
    }  
  else 
    {	
      XtExposeProc expose;
      _XmPrimitiveEnter ((Widget) pb, event, NULL, NULL);
      if (pb->pushbutton.armed == TRUE) {
	_XmProcessLock();
	expose = XtClass(pb)->core_class.expose;
	_XmProcessUnlock();
	(* expose)(wid, event, (Region) NULL);
      }
    }
}

/************************************************************************
 *
 *  Leave
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
Leave(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;

  if (Lab_IsMenupane(pb))
    {
      XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid));
      Boolean etched_in = dpy->display.enable_etched_in_menu;

      if (_XmGetInDragMode((Widget)pb) && pb->pushbutton.armed &&
          (/* !ActiveTearOff || */ event->xcrossing.mode == NotifyNormal))
	{
	  pb->pushbutton.armed = FALSE;
  
	  ((XmManagerWidget) XtParent(wid))->manager.active_child = NULL;

	  if (etched_in && !XmIsTearOffButton(pb) ) {
	      XFillRectangle (XtDisplay(pb), XtWindow(pb),
			      pb->pushbutton.background_gc,
			      0, 0, pb->core.width, pb->core.height);
	      DrawPushButtonLabel (pb, event, NULL);
	  }
	  else 
	     XmeClearBorder
		 (XtDisplay (pb), XtWindow (pb),
		  pb->primitive.highlight_thickness,
		  pb->primitive.highlight_thickness,
		  pb->core.width - 2 * pb->primitive.highlight_thickness,
		  pb->core.height - 2 * pb->primitive.highlight_thickness,
		  pb->primitive.shadow_thickness);

	  if (pb->pushbutton.disarm_callback)
	    {
	      XFlush (XtDisplay (pb));
	      
	      call_value.reason = XmCR_DISARM;
	      call_value.event = event;
	      XtCallCallbackList ((Widget) pb, 
				  pb->pushbutton.disarm_callback, &call_value);
	    }
	}
    }
  else 
    {
      _XmPrimitiveLeave ((Widget) pb, event, NULL, NULL);
      
      if (pb->pushbutton.armed == TRUE)
	{  
	  XtExposeProc expose;
	  pb->pushbutton.armed = FALSE;
	  _XmProcessLock();
	  expose = XtClass(pb)->core_class.expose;
	  _XmProcessUnlock();
	  (* expose)(wid, event, (Region) NULL);
	  pb->pushbutton.armed = TRUE;
	}
    }
}

/*************************************<->*************************************
 *
 *  KeySelect
 *
 *  If the menu system traversal is enabled, do an activate and disarm
 *
 *************************************<->***********************************/

/*ARGSUSED*/
static void 
KeySelect(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  XmPushButtonCallbackStruct call_value;
  XmMenuSystemTrait menuSTrait;
  
  if (!_XmIsEventUnique(event))
    return;
  
  if (!_XmGetInDragMode((Widget)pb))
    {
      menuSTrait = (XmMenuSystemTrait) 
	XmeTraitGet((XtPointer) XtClass(XtParent(pb)), XmQTmenuSystem);
      pb->pushbutton.armed = FALSE;
      
      if (menuSTrait != NULL)
	menuSTrait->buttonPopdown(XtParent(pb), event);
      
      _XmRecordEvent(event);
      
      call_value.reason = XmCR_ACTIVATE;
      call_value.event = event;
      
      /* if the parent is menu system able, notify it about the select */
      if (menuSTrait != NULL)
	menuSTrait->entryCallback(XtParent(pb), (Widget) pb, &call_value);
      
      if ((! pb->label.skipCallback) &&
	  (pb->pushbutton.activate_callback))
	{
	  XFlush (XtDisplay (pb));
	  XtCallCallbackList ((Widget) pb, pb->pushbutton.activate_callback,
			      &call_value);
	}
      
      if (menuSTrait != NULL)
	menuSTrait->reparentToTearOffShell(XtParent(pb), event);
    }
}

/************************************************************************
 *
 *  Help
 *     This function processes Function Key 1 press occuring on the PushButton.
 *
 ************************************************************************/

/*ARGSUSED*/
static void 
Help(
        Widget wid,
        XEvent *event,
        String *params,		/* unused */
        Cardinal *num_params )	/* unused */
{
  XmPushButtonWidget pb = (XmPushButtonWidget) wid ;
  Boolean is_menupane = Lab_IsMenupane(pb);
  XmMenuSystemTrait menuSTrait;
  
  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass(XtParent(wid)), XmQTmenuSystem);
  
  if (is_menupane && menuSTrait != NULL)
    menuSTrait->buttonPopdown(XtParent(pb), event);
  
  _XmPrimitiveHelp ((Widget) pb, event, NULL, NULL);
  
  /***
   * call_value.reason = XmCR_HELP;
   * call_value.event = event;
   * XtCallCallbackList ((Widget) pb, pb->primitive.help_callback, &call_value);
   ***/
  
  if (is_menupane && menuSTrait != NULL)
    menuSTrait->reparentToTearOffShell(XtParent(pb), event);
}

/************************************************************************
 *
 *  Trait methods --------
 *      
 ************************************************************************/

/************************************************************************
 *
 *  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);
}

/************************************************************************
 *
 *  ShowAsDefault
 *	set up the default visual
 *      
 ************************************************************************/

static void 
ShowAsDefault(Widget w, 
	      XtEnum state)
{
  XmPushButtonWidget pb = (XmPushButtonWidget) w ;
  Dimension dbShadowTh ;
  
  switch (state) 
    {
    case XmDEFAULT_READY:
      {
	/* We have pixels, but the button unit type might not be 
	 * pixel, so save it and restore it after the setvalues */
	unsigned char saved_unit_type =
	  ((XmPrimitiveWidget)w)->primitive.unit_type ;

#ifdef DEFAULT_GLYPH_PIXMAP
	unsigned int def_pixmap_width ;
	if (_XmGetDefaultGlyphPixmap(XtScreen((Widget)(pb)), 
				     &def_pixmap_width, NULL) != 
	    XmUNSPECIFIED_PIXMAP) 
	  {
	    /* We will use the margin right area, so increase it */
	    pb->pushbutton.compatible = False;
	    ((XmPrimitiveWidget)w)->primitive.unit_type = XmPIXELS;
	    XtVaSetValues(w, XmNmarginRight, def_pixmap_width, NULL);
	    ((XmPrimitiveWidget)w)->primitive.unit_type = saved_unit_type;
	  } 
	else
#endif
	  if (!pb->pushbutton.default_button_shadow_thickness)
	    {   
	      if (pb->primitive.shadow_thickness > 1) 
		dbShadowTh = pb->primitive.shadow_thickness >> 1 ;
	      else
		dbShadowTh = pb->primitive.shadow_thickness ;
		
	      /* CR 7474: Disable pushbutton compatibility mode. */
	      pb->pushbutton.compatible = False;
	      ((XmPrimitiveWidget)w)->primitive.unit_type = XmPIXELS;
	      XtVaSetValues(w, XmNdefaultButtonShadowThickness,
			    dbShadowTh, NULL);
	      ((XmPrimitiveWidget)w)->primitive.unit_type = saved_unit_type;
	    } 
      }
      break ;

    case XmDEFAULT_ON :
      /* CR 7474: Disable pushbutton compatibility mode. */
      pb->pushbutton.compatible = False;
      XtVaSetValues(w, XmNshowAsDefault, True, NULL);
      break ;

    case XmDEFAULT_OFF :
      XtVaSetValues(w, XmNshowAsDefault, False, NULL);
      break ;

    case XmDEFAULT_FORGET :
    default:
#ifdef DEFAULT_GLYPH_PIXMAP
      if (_XmGetDefaultGlyphPixmap(XtScreen((Widget)(pb)), NULL, NULL) != 
	  XmUNSPECIFIED_PIXMAP)
	XtVaSetValues(w, XmNmarginRight, 0, NULL);
      else 
#endif
    	if (!pb->pushbutton.default_button_shadow_thickness)
	  XtVaSetValues(w, XmNdefaultButtonShadowThickness, 0, NULL);
    }
}

/************************************************************************
 *
 *		Application Accessible External Functions
 *
 ************************************************************************/


/************************************************************************
 *
 *  XmCreatePushButton
 *	Create an instance of a pushbutton and return the widget id.
 *
 ************************************************************************/

Widget 
XmCreatePushButton(
        Widget parent,
        char *name,
        ArgList arglist,
        Cardinal argcount )
{
  return XtCreateWidget(name, xmPushButtonWidgetClass, parent, 
			arglist, argcount);
}

Widget 
XmVaCreatePushButton(
        Widget parent,
        char *name,
        ...)
{
    register Widget w;
    va_list var;
    int count;
    
    Va_start(var,name);
    count = XmeCountVaListSimple(var);
    va_end(var);

    
    Va_start(var, name);
    w = XmeVLCreateWidget(name, 
                         xmPushButtonWidgetClass, 
                         parent, False, 
                         var, count);
    va_end(var);   
    return w;
    
}
Widget 
XmVaCreateManagedPushButton(
        Widget parent,
        char *name,
        ...)
{
    Widget w = NULL;
    va_list var;
    int count;
    
    Va_start(var, name);
    count = XmeCountVaListSimple(var);
    va_end(var);
    
    Va_start(var, name);
    w = XmeVLCreateWidget(name, 
                         xmPushButtonWidgetClass, 
                         parent, True, 
                         var, count);
    va_end(var);   
    return w;
    
}
