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

#include <ctype.h>
#include <X11/IntrinsicP.h>
#include <X11/ShellP.h>
#include <X11/Xatom.h>
#include <X11/Xlocale.h>
#include <X11/keysymdef.h>
#include <Xm/AccTextT.h>
#include <Xm/AtomMgr.h>
#include <Xm/BaseClassP.h>
#include <Xm/CascadeBP.h>
#include <Xm/DisplayP.h>
#include <Xm/DragC.h>
#include <Xm/DragIcon.h>
#include <Xm/DragIconP.h>
#include <Xm/DrawP.h>
#include <Xm/MenuT.h>
#include <Xm/RowColumnP.h>
#include <Xm/TraitP.h>
#include <Xm/TransferT.h>
#include <Xm/TransltnsP.h>
#include "GadgetUtiI.h"
#include "GMUtilsI.h"
#include "LabelGI.h"
#include "LabelI.h"
#include "MessagesI.h"
#include "MenuProcI.h"
#include "PrimitiveI.h"
#include "RepTypeI.h"
#include "ScreenI.h"
#include "TransferI.h"
#include "TravActI.h"
#include "XmI.h"
#include "XmosI.h"
#include "XmStringI.h"

#define Pix(w)			((w)->label.pixmap)
#define Pix_insen(w)		((w)->label.pixmap_insen)

/* Warning Messages */

#define CS_STRING_MESSAGE	_XmMMsgLabel_0003
#define ACC_MESSAGE		_XmMMsgLabel_0004

/********    Static Function Declarations    ********/

static void ClassInitialize(void);
static void ClassPartInitialize(WidgetClass c);
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 SetNormalGC(XmLabelWidget lw);
static void Resize(Widget wid);
static void Initialize(Widget req, Widget new_w,
		       ArgList args, Cardinal *num_args);
static XtGeometryResult QueryGeometry(Widget wid,
				      XtWidgetGeometry *intended,
				      XtWidgetGeometry *reply);
static void Destroy(Widget w);
static void Redisplay(Widget wid, XEvent *event, Region region);
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 Boolean SetValues(Widget cw, Widget rw, Widget nw,
			 ArgList args, Cardinal *num_args);
static void SetOverrideCallback(Widget wid);
static void Help(Widget w, XEvent *event, String *params, Cardinal *num_params);
static void GetLabelString(Widget wid, int resource, XtArgVal *value);
static void GetAccelerator(Widget wid, int resource, XtArgVal *value);
static void GetAcceleratorText(Widget wid, int resource, XtArgVal *value);
static XmStringCharSet _XmStringCharSetCreate(XmStringCharSet stringcharset);
static void GetMnemonicCharSet(Widget wid, int resource, XtArgVal *value);
static void SetValuesAlmost(Widget cw, Widget nw,
			    XtWidgetGeometry *request, XtWidgetGeometry *reply);
static Boolean XmLabelGetDisplayRect(Widget w, XRectangle *displayrect);
static Boolean XmLabelGetBaselines(Widget wid,
				   Dimension **baselines,
				   int *line_count);
static void XmLabelMarginsProc(Widget w,
			       XmBaselineMargins *margins_rec);
static Widget GetPixmapDragIcon(Widget w);
static void ProcessDrag(Widget w, XEvent *event,
                        String *params, Cardinal *num_params);
static void SetActivateCallbackState(Widget w, XmActivateState state);
static void CheckSetRenderTable(Widget wid, int offset, XrmValue *value); 
static XtPointer LabelGetValue(Widget, int);
static void LabelSetValue(Widget, XtPointer, int);
static int LabelPreferredValue(Widget);
static char* GetLabelAccelerator(Widget);
static KeySym GetLabelMnemonic(Widget);
static XtPointer ConvertToEncoding(Widget, char*, Atom, unsigned long *, 
				 Boolean *);
/********    End Static Function Declarations    ********/


void _XmLabelConvert(Widget w, XtPointer ignore, XmConvertCallbackStruct*);

/* Transfer trait record */
static XmConst XmTransferTraitRec LabelTransfer = {
  0, 						/* version		  */
  (XmConvertCallbackProc) _XmLabelConvert,	/* convertProc		  */
  NULL,						/* destinationProc	  */
  NULL						/* destinationPreHookProc */
};

/* Menu Savvy trait record */
static XmConst XmMenuSavvyTraitRec MenuSavvyRecord = {
  0,						     /* version		  */
  (XmMenuSavvyDisableProc) SetActivateCallbackState, /* disableCallback	  */
  GetLabelAccelerator,				     /* getAccelerator	  */
  GetLabelMnemonic,				     /* getMnemonic	  */
  (XmMenuSavvyGetActivateCBNameProc) NULL,	     /* getActivateCBName */
};

/* Access Textual trait record */
XmAccessTextualTraitRec _XmLabel_AccessTextualRecord = {
  0,				/* version         */
  LabelGetValue,		/* getValueMethod  */
  LabelSetValue,		/* setValuesMethod */
  LabelPreferredValue,		/* preferredFormat */
};


/* Default translations and action recs */

static XtTranslations default_parsed;

#define defaultTranslations	_XmLabel_defaultTranslations

static XtTranslations menu_parsed;

#define menuTranslations	_XmLabel_menuTranslations


static XtActionsRec ActionsList[] = {
  { "Enter",		Enter		},
  { "Leave",		Leave		},
  { "Help",		Help		},
  { "ProcessDrag",	ProcessDrag	}
};


/* Here are the translations used by the subclasses for menu traversal */
/* The matching actions are defined in RowColumn.c                     */

#define menu_traversal_events	_XmLabel_menu_traversal_events

static XtResource resources[] = 
{
  {
    XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
    sizeof(Dimension), XtOffsetOf(XmLabelRec, primitive.shadow_thickness),
    XmRImmediate, (XtPointer) 0
  },

  {
    XmNalignment, XmCAlignment, XmRAlignment,
    sizeof(unsigned char), XtOffsetOf(XmLabelRec, label.alignment),
    XmRImmediate, (XtPointer) XmALIGNMENT_CENTER
  },

  {
    XmNlabelType, XmCLabelType, XmRLabelType,
    sizeof(unsigned char), XtOffsetOf(XmLabelRec, label.label_type),
    XmRImmediate, (XtPointer) XmSTRING
  },

  {
    XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, 
    sizeof(Dimension), XtOffsetOf(XmLabelRec, label.margin_width), 
    XmRImmediate, (XtPointer) 2
  },

  {
    XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension, 
    sizeof(Dimension), XtOffsetOf(XmLabelRec, label.margin_height),
    XmRImmediate, (XtPointer) 2
  },

  {
    XmNmarginLeft, XmCMarginLeft, XmRHorizontalDimension, 
    sizeof(Dimension), XtOffsetOf(XmLabelRec, label.margin_left), 
    XmRImmediate, (XtPointer) 0
  },

  {
    XmNmarginRight, XmCMarginRight, XmRHorizontalDimension, 
    sizeof(Dimension), XtOffsetOf(XmLabelRec, label.margin_right), 
    XmRImmediate, (XtPointer) 0
  },

  {
    XmNmarginTop, XmCMarginTop, XmRVerticalDimension, 
    sizeof(Dimension), XtOffsetOf(XmLabelRec, label.margin_top), 
    XmRImmediate, (XtPointer) 0
  },

  {
    XmNmarginBottom, XmCMarginBottom, XmRVerticalDimension, 
    sizeof(Dimension), XtOffsetOf(XmLabelRec, label.margin_bottom), 
    XmRImmediate, (XtPointer) 0
  },

  {
      "pri.vate","Pri.vate",XmRBoolean,
      sizeof(Boolean), XtOffsetOf(XmLabelRec, label.check_set_render_table),
      XmRImmediate, (XtPointer) False
  },

  {
    XmNfontList, XmCFontList, XmRFontList,
    sizeof(XmFontList), XtOffsetOf(XmLabelRec, label.font),
    XmRCallProc, (XtPointer)CheckSetRenderTable
  },

  {
    XmNrenderTable, XmCRenderTable, XmRRenderTable,
    sizeof(XmRenderTable), XtOffsetOf(XmLabelRec, label.font),
    XmRCallProc, (XtPointer)CheckSetRenderTable
  },

  {
    XmNlabelPixmap, XmCLabelPixmap, XmRDynamicPixmap,
    sizeof(Pixmap), XtOffsetOf(XmLabelRec, label.pixmap),
    XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
  },

  {
    XmNlabelInsensitivePixmap, XmCLabelInsensitivePixmap, XmRDynamicPixmap,
    sizeof(Pixmap), XtOffsetOf(XmLabelRec, label.pixmap_insen),
    XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP 
  },

  {    
    XmNlabelString, XmCXmString, XmRXmString,
    sizeof(XmString), XtOffsetOf(XmLabelRec, label._label),
    XmRImmediate, (XtPointer) NULL
  },

  {
    XmNmnemonic, XmCMnemonic, XmRKeySym,
    sizeof(KeySym), XtOffsetOf(XmLabelRec, label.mnemonic),
    XmRImmediate, (XtPointer) XK_VoidSymbol
  },

   {
     XmNmnemonicCharSet, XmCMnemonicCharSet, XmRString,
     sizeof(XmStringCharSet), XtOffsetOf(XmLabelRec, label.mnemonicCharset),
     XmRImmediate, (XtPointer) XmFONTLIST_DEFAULT_TAG    
   },

  {
    XmNaccelerator, XmCAccelerator, XmRString,
    sizeof(char *), XtOffsetOf(XmLabelRec, label.accelerator),
    XmRImmediate, (XtPointer) NULL
  },

  {
    XmNacceleratorText, XmCAcceleratorText, XmRXmString,
    sizeof(XmString), XtOffsetOf(XmLabelRec, label._acc_text),
    XmRImmediate, (XtPointer) NULL
  },

 { 
   XmNrecomputeSize, XmCRecomputeSize, XmRBoolean,
   sizeof(Boolean), XtOffsetOf(XmLabelRec, label.recompute_size),
   XmRImmediate, (XtPointer) True
 },

 { 
   XmNstringDirection, XmCStringDirection, XmRStringDirection,
   sizeof(unsigned char), XtOffsetOf(XmLabelRec, label.string_direction),
   XmRImmediate, (XtPointer) XmDEFAULT_DIRECTION
 },

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

  {
    XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension,
    sizeof(Dimension), XtOffsetOf(XmPrimitiveRec, primitive.highlight_thickness),
    XmRImmediate, (XtPointer) 0
  },
#ifndef XM_PART_BC
  {
    XmNlayoutDirection, XmCLayoutDirection, XmRDirection,
    sizeof(XmDirection), XtOffsetOf(XmPrimitiveRec, primitive.layout_direction),
    XmRImmediate, (XtPointer) XmDEFAULT_DIRECTION
  }
#endif
};

/* Definition for resources that need special processing in get values. */

static XmSyntheticResource syn_resources[] =
{
  { 
    XmNmarginWidth, sizeof(Dimension),
    XtOffsetOf(XmLabelRec, label.margin_width), 
    XmeFromHorizontalPixels, XmeToHorizontalPixels 
  },

  { 
    XmNmarginHeight, sizeof(Dimension),
    XtOffsetOf(XmLabelRec, label.margin_height),
    XmeFromVerticalPixels, XmeToVerticalPixels 
  },

  { 
    XmNmarginLeft, sizeof(Dimension),
    XtOffsetOf(XmLabelRec, label.margin_left), 
    XmeFromHorizontalPixels, XmeToHorizontalPixels 
  },

  { 
    XmNmarginRight, sizeof(Dimension),
    XtOffsetOf(XmLabelRec, label.margin_right), 
    XmeFromHorizontalPixels, XmeToHorizontalPixels
  },

  { 
    XmNmarginTop, sizeof(Dimension),
    XtOffsetOf(XmLabelRec, label.margin_top), 
    XmeFromVerticalPixels, XmeToVerticalPixels
  },

  { 
    XmNmarginBottom, sizeof(Dimension),
    XtOffsetOf(XmLabelRec, label.margin_bottom),
    XmeFromVerticalPixels, XmeToVerticalPixels
  },

  {
    XmNlabelString, sizeof(XmString),
    XtOffsetOf(XmLabelRec, label._label),
    GetLabelString, NULL
  },

  {
    XmNmnemonicCharSet, sizeof(XmStringCharSet),
    XtOffsetOf(XmLabelRec, label.mnemonicCharset),
    GetMnemonicCharSet, NULL
  },

  {
    XmNaccelerator, sizeof(String),
    XtOffsetOf(XmLabelRec, label.accelerator),
    GetAccelerator, NULL
  },

  {
    XmNacceleratorText, sizeof(XmString),
    XtOffsetOf(XmLabelRec, label._acc_text),
    GetAcceleratorText, NULL
  }
};

static XmBaseClassExtRec labelBaseClassExtRec = {
  NULL,				/* Next extension         */
  NULLQUARK,			/* record type XmQmotif   */
  XmBaseClassExtVersion,	/* version                */
  sizeof(XmBaseClassExtRec),	/* size                   */
  InitializePrehook,		/* initialize prehook     */
  XmInheritSetValuesPrehook,	/* 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    */
  NULL,				/* classPartInitPrehook   */
  NULL,				/* classPartInitPosthook  */
  NULL,				/* ext_resources          */
  NULL,				/* compiled_ext_resources */
  0,				/* num_ext_resources      */
  FALSE,			/* use_sub_resources      */
  XmInheritWidgetNavigable,	/* widgetNavigable        */
  XmInheritFocusChange		/* focusChange            */
};

static XmPrimitiveClassExtRec _XmLabelPrimClassExtRec = {
  NULL,					/* next_extension      */
  NULLQUARK,				/* record_type         */
  XmPrimitiveClassExtVersion,		/* version             */
  sizeof(XmPrimitiveClassExtRec),	/* record_size         */
  XmLabelGetBaselines,			/* widget_baseline     */
  XmLabelGetDisplayRect,		/* widget_display_rect */
  XmLabelMarginsProc,			/* widget_margins      */
};

externaldef (xmlabelclassrec) XmLabelClassRec xmLabelClassRec = {
  {
    (WidgetClass) &xmPrimitiveClassRec,	/* superclass	       */
    "XmLabel",				/* class_name	       */
    sizeof(XmLabelRec),			/* widget_size	       */
    ClassInitialize,			/* class_initialize    */
    ClassPartInitialize,		/* chained class init  */
    FALSE,				/* class_inited	       */
    Initialize,				/* initialize	       */
    NULL,				/* initialize hook     */
    XtInheritRealize,			/* realize	       */
    ActionsList,			/* actions	       */
    XtNumber(ActionsList),		/* num_actions	       */
    resources,				/* resources	       */
    XtNumber(resources),		/* num_resources       */
    NULLQUARK,				/* xrm_class	       */
    TRUE,				/* compress_motion     */
    XtExposeCompressMaximal,		/* compress_exposure   */
    TRUE,				/* compress enter/exit */
    FALSE,				/* visible_interest    */
    Destroy,				/* destroy	       */
    Resize,				/* resize	       */
    Redisplay,				/* expose	       */
    SetValues,				/* set_values	       */
    NULL,				/* set values hook     */
    SetValuesAlmost,			/* set values almost   */
    NULL,				/* get values hook     */
    NULL,				/* accept_focus	       */
    XtVersion,				/* version	       */
    NULL,				/* callback offsetlst  */
    NULL,				/* default trans       */
    QueryGeometry,			/* query geo proc      */
    NULL,				/* display accelerator */
    (XtPointer)&labelBaseClassExtRec	/* extension record    */
  },

  { /* XmPrimitiveClassPart */
    XmInheritBorderHighlight,		 /* border_highlight   */
    XmInheritBorderUnhighlight,		 /* border_unhighlight */
    XtInheritTranslations,		 /* translations       */
    NULL,				 /* arm_and_activate   */
    syn_resources,			 /* syn resources      */
    XtNumber(syn_resources),		 /* num syn_resources  */
    (XtPointer)&_XmLabelPrimClassExtRec, /* extension          */
  },

  { /* XmLabelClassPart */
    SetOverrideCallback,	/* override_callback             */
    NULL,			/* menu procedure interface      */
    NULL,			/* translations                  */
    NULL			/* extension record              */
  }
};

externaldef(xmlabelwidgetclass) WidgetClass xmLabelWidgetClass =  
				(WidgetClass) &xmLabelClassRec;

/*********************************************************************
 *
 * ClassInitialize
 *       This is the class initialization routine.  It is called only
 *       the first time a widget of this class is initialized.
 *
 ********************************************************************/         

/*ARGSUSED*/
static void 
ClassInitialize(void)
{
  /* Parse the various translation tables */
  menu_parsed	 = XtParseTranslationTable(menuTranslations);
  default_parsed = XtParseTranslationTable(defaultTranslations);
  
  /* Set up base class extension quark */
  labelBaseClassExtRec.record_type = XmQmotif;
  
  xmLabelClassRec.label_class.translations =
    (String) (XtParseTranslationTable(menu_traversal_events));
  
  /* Install menu savvy on just this class */
  XmeTraitSet((XtPointer) &xmLabelClassRec,
	      XmQTmenuSavvy, (XtPointer) &MenuSavvyRecord);
}

void
_XmLabelCloneMenuSavvy(WidgetClass wc, 
		       XmMenuSavvyTrait mst)
{
  /* Modify and reinstall menu savvy trait */
  if (mst->version == -1) 
    {
      mst->version = MenuSavvyRecord.version;
      mst->disableCallback = MenuSavvyRecord.disableCallback;
      mst->getAccelerator = MenuSavvyRecord.getAccelerator;
      mst->getMnemonic = MenuSavvyRecord.getMnemonic;
    }

  /* Install the new record */
  XmeTraitSet((XtPointer) wc, XmQTmenuSavvy, (XtPointer) mst);
}

char* _XmCBNameActivate()
{
  return XmNactivateCallback;
}

char* _XmCBNameValueChanged()
{
  return XmNvalueChangedCallback;
}

/************************************************************
 *
 * 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);
}

/*********************************************************************
 *
 *  ClassPartInitialize
 *      Processes the class fields which need to be inherited.
 *
 ************************************************************************/
static void 
ClassPartInitialize(WidgetClass c)
{
  register XmLabelWidgetClass wc = (XmLabelWidgetClass) c;
  XmLabelWidgetClass super = (XmLabelWidgetClass)wc->core_class.superclass;
  
  if (wc->label_class.setOverrideCallback == XmInheritSetOverrideCallback)
    wc->label_class.setOverrideCallback = 
      super->label_class.setOverrideCallback;
  
  if (wc->label_class.translations == XtInheritTranslations)
    wc->label_class.translations = super->label_class.translations;
  
  _XmFastSubclassInit (c, XmLABEL_BIT);
  
  
  /* Install traits */
  XmeTraitSet((XtPointer) c, XmQTtransfer, (XtPointer) &LabelTransfer);
  XmeTraitSet((XtPointer) c, XmQTaccessTextual, 
	      (XtPointer) &_XmLabel_AccessTextualRecord);
}

/************************************************************
 *
 * 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 */
{
  unsigned char type;
  XmMenuSystemTrait menuSTrait;

  _XmProcessLock();
  if (new_w->core.widget_class->core_class.tm_table != NULL) {
    _XmProcessUnlock();
    return;
  }

  _XmSaveCoreClassTranslations (new_w);

  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass((Widget) XtParent(new_w)), XmQTmenuSystem);

  if (menuSTrait != (XmMenuSystemTrait) NULL)
    type = menuSTrait->type(XtParent(new_w));
  else 
    type = XmWORK_AREA;

  if (type == XmWORK_AREA)
    new_w->core.widget_class->core_class.tm_table = (String) default_parsed;
  else 
    new_w->core.widget_class->core_class.tm_table = (String) menu_parsed;
  _XmProcessUnlock();
}

/************************************************************************
 *
 *  SetNormalGC
 *      Create the normal and insensitive GC's for the gadget.
 *
 ************************************************************************/

static void 
SetNormalGC(XmLabelWidget lw)
{
  XGCValues       values;
  XtGCMask        valueMask, dynamicMask;
  XFontStruct     *fs = (XFontStruct *) NULL;
  
  valueMask = GCForeground | GCBackground | GCGraphicsExposures;
  dynamicMask = GCClipMask | GCClipXOrigin | GCClipYOrigin;

  values.foreground = lw->primitive.foreground;
  values.background = lw->core.background_pixel;
  values.graphics_exposures = False;
  
  if (XmeRenderTableGetDefaultFont(lw->label.font, &fs))
    values.font = fs->fid, valueMask |= GCFont;
  
  lw->label.normal_GC = XtAllocateGC((Widget) lw, 0, valueMask, &values,
				     dynamicMask, 0);
  
  valueMask |= GCFillStyle | GCStipple;
  values.fill_style = FillOpaqueStippled;
  values.stipple = _XmGetInsensitiveStippleBitmap((Widget) lw);
  
  lw->label.insensitive_GC = XtAllocateGC((Widget) lw, 0, valueMask, &values,
					  dynamicMask, 0);
}

/************************************************************************
 *
 * _XmCalcLabelDimensions()
 *   Calculates the dimensions of the label text and pixmap, and updates
 *   the TextRect fields appropriately. Called at Initialize and SetValues.
 *   Also called by subclasses to recalculate label dimensions.
 *
 ************************************************************************/

void 
_XmCalcLabelDimensions(Widget wid)
{
  XmLabelWidget newlw = (XmLabelWidget) wid;
  XmLabelPart  *lp = &(newlw->label);
  unsigned int  w = 0, h = 0;
  

  /* Initialize TextRect width and height to 0, change later if needed */
  lp->TextRect.width = 0;
  lp->TextRect.height = 0;
  lp->acc_TextRect.width = 0;
  lp->acc_TextRect.height = 0;
  
  if (Lab_IsPixmap(newlw))
    {
      /* change NULL pixmap to refer to XmUNSPECIFIED_PIXMAP */
      if (Pix(newlw) == (Pixmap)None)
        Pix(newlw) = XmUNSPECIFIED_PIXMAP;
      if (Pix_insen(newlw) == (Pixmap)None)
        Pix_insen(newlw) = XmUNSPECIFIED_PIXMAP;

      /* Is a pixmap so find out how big it is. */
      if (XtIsSensitive(wid))
	{
	  if (Pix(newlw) != XmUNSPECIFIED_PIXMAP)
	    {
	      XmeGetPixmapData(XtScreen(newlw), Pix(newlw),
			       NULL, NULL, NULL, NULL, NULL, NULL,
			       &w, &h);         
	      
	      lp->TextRect.width = (unsigned short) w;
	      lp->TextRect.height = (unsigned short) h;
	    }
	}
      else
	{
	  Pixmap pix_use = Pix_insen (newlw) ;

	  if (pix_use == XmUNSPECIFIED_PIXMAP)
	      pix_use = Pix(newlw);

	  if (pix_use != XmUNSPECIFIED_PIXMAP)
	    {
	      XmeGetPixmapData(XtScreen(newlw), pix_use,
			       NULL, NULL, NULL, NULL, NULL, NULL,
			       &w, &h);         
	      
	      lp->TextRect.width = (unsigned short) w;
	      lp->TextRect.height = (unsigned short) h;
	    }
	}
      if (lp->_acc_text != NULL)
	{
	  Dimension w, h;
	  
	  /* If we have a string then size it. */
	  if (!XmStringEmpty (lp->_acc_text))
	    {
	      XmStringExtent(lp->font, lp->_acc_text, &w, &h);
	      lp->acc_TextRect.width = (unsigned short)w;
	      lp->acc_TextRect.height = (unsigned short)h;
	    }
	}
    }
  else if (Lab_IsText(newlw))
    {
      Dimension w, h;
      
      if (!XmStringEmpty (lp->_label))
	{
	  /* If we have a string then size it. */
	  XmStringExtent(lp->font, lp->_label, &w, &h);
	  lp->TextRect.width = (unsigned short)w;
	  lp->TextRect.height = (unsigned short)h;
	}
      
      if (lp->_acc_text != NULL)
	{
	  /* If we have a string then size it. */
	  if (!XmStringEmpty (lp->_acc_text))
	    {
	      XmStringExtent(lp->font, lp->_acc_text, &w, &h);
	      lp->acc_TextRect.width = (unsigned short)w;
	      lp->acc_TextRect.height = (unsigned short)h;
	    }
	}
    }
}       

/************************************************************************
 *
 *  Resize
 *      Sets new width, new height, and new label.TextRect
 *      appropriately. This routine is called by Initialize and
 *      SetValues.
 *
 ************************************************************************/

static void 
Resize(Widget wid)
{
  XmLabelWidget newlw = (XmLabelWidget) wid;
  XmLabelPart *lp = &(newlw->label);
  int leftx, rightx;
  
  /* Increase margin width if necessary to accomodate accelerator text. */
  if (lp->_acc_text != NULL)
    {
      if (LayoutIsRtoLP(newlw))
	{
          if (lp->margin_left < (Dimension) (lp->acc_TextRect.width + LABEL_ACC_PAD) )
	    {
	      int delta = 
		lp->acc_TextRect.width + LABEL_ACC_PAD - lp->margin_left;
	      lp->acc_left_delta += delta;
	      lp->margin_left += delta;
	    }
	}
      else
	{
	  if (lp->margin_right < (Dimension) (lp->acc_TextRect.width + LABEL_ACC_PAD) )
	    {
	      int delta = 
		lp->acc_TextRect.width + LABEL_ACC_PAD - lp->margin_right;
	      lp->acc_right_delta += delta;
	      lp->margin_right += delta;
	    }
	}
    }
  
  /* Has a width been specified?  */
  if (newlw->core.width == 0)
    newlw->core.width = (Dimension)
      lp->TextRect.width + 
	lp->margin_left + lp->margin_right +
	  (2 * (lp->margin_width 
		+ newlw->primitive.highlight_thickness
		+ newlw->primitive.shadow_thickness));
  
  leftx = (newlw->primitive.highlight_thickness +
	   newlw->primitive.shadow_thickness +
	   lp->margin_width + lp->margin_left);

  rightx = (newlw->core.width -
	    (newlw->primitive.highlight_thickness +
	     newlw->primitive.shadow_thickness +
	     lp->margin_width + lp->margin_right));

  switch (lp->alignment)
    {
    case XmALIGNMENT_BEGINNING:
      if (LayoutIsRtoLP(newlw))
	lp->TextRect.x = rightx - lp->TextRect.width;
      else
	lp->TextRect.x = leftx;
      break;
      
    case XmALIGNMENT_END:
      if (LayoutIsRtoLP(newlw))
	lp->TextRect.x = leftx;
      else
	lp->TextRect.x = rightx - lp->TextRect.width;
      break;
      
    default:
      /* CR 9737: Be careful about casting here, since rounding during */
      /*	division on Suns depends on the sign. */ 
      lp->TextRect.x = leftx + (rightx - leftx - (int)lp->TextRect.width) / 2;
      break;
    }
  
  /* Has a height been specified? */
  if (newlw->core.height == 0)
    newlw->core.height = (Dimension)
      MAX(lp->TextRect.height, lp->acc_TextRect.height) +
	lp->margin_top +
	  lp->margin_bottom
	    + (2 * (lp->margin_height
		    + newlw->primitive.highlight_thickness
		    + newlw->primitive.shadow_thickness));
  
  lp->TextRect.y =  (short) (newlw->primitive.highlight_thickness
			     + newlw->primitive.shadow_thickness
			     + lp->margin_height + lp->margin_top +
			     ((int) (newlw->core.height - lp->margin_top
			       - lp->margin_bottom
			       - (2 * (lp->margin_height
				       + newlw->primitive.highlight_thickness
				       + newlw->primitive.shadow_thickness))
			       - lp->TextRect.height) / 2));
  
  if (lp->_acc_text != NULL)
    {
      Dimension  base_label, base_accText, diff;
      
      if (LayoutIsRtoLP(newlw))
	lp->acc_TextRect.x = newlw->primitive.highlight_thickness +
	  newlw->primitive.shadow_thickness +
	    newlw->label.margin_width;
      else
	lp->acc_TextRect.x = (short) newlw->core.width - 
	  newlw->primitive.highlight_thickness -
	    newlw->primitive.shadow_thickness -
	      newlw->label.margin_width -
		newlw->label.margin_right + LABEL_ACC_PAD;
      
      lp->acc_TextRect.y =
	(short) (newlw->primitive.highlight_thickness
		 + newlw->primitive.shadow_thickness
		 + lp->margin_height + lp->margin_top +
		 ((int) (newlw->core.height - lp->margin_top
		   - lp->margin_bottom
		   - (2 * (lp->margin_height
			   + newlw->primitive.highlight_thickness
			   + newlw->primitive.shadow_thickness))
				       - lp->acc_TextRect.height) / 2));
      
      /* make sure the label and accelerator text line up */
      /* when the fonts are different */
      
      if (Lab_IsText(newlw))
	{
	  base_label = XmStringBaseline (lp->font, lp->_label);
	  base_accText = XmStringBaseline (lp->font, lp->_acc_text);
	  
	  if (base_label > base_accText)
	    {
	      diff = base_label - base_accText;
	      lp->acc_TextRect.y = (short) lp->TextRect.y + diff - 1;
	    }
	  else if (base_label < base_accText)
	    {
	      diff = base_accText - base_label;
	      lp->TextRect.y = (short) lp->acc_TextRect.y + diff - 1;
	    }
	}
    }
  
  if (newlw->core.width == 0)    /* set core width and height to a */
    newlw->core.width = 1;       /* default value so that it doesn't */
  if (newlw->core.height == 0)   /* generate a Toolkit Error */
    newlw->core.height = 1;
}

/************************************************************
 *
 * Initialize
 *    This is the widget's instance initialize routine.  It is 
 *    called once for each widget                              
 *
 ************************************************************/
/*ARGSUSED*/
static void 
Initialize(
        Widget req,
        Widget new_w,
        ArgList args,		/* unused */
        Cardinal *num_args)	/* unused */
{
  XmLabelWidget lw = (XmLabelWidget) new_w;
  XmMenuSystemTrait menuSTrait;
  XtTranslations	trans;
  
  lw->label.baselines = NULL;
  lw->label.computing_size = FALSE;
  
  /* if menuProcs is not set up yet, try again */
  if (xmLabelClassRec.label_class.menuProcs == NULL)
    xmLabelClassRec.label_class.menuProcs =
      (XmMenuProc) _XmGetMenuProcContext();
  
  /* Check for Invalid enumerated types */
  
  if (!XmRepTypeValidValue(XmRID_LABEL_TYPE, lw->label.label_type, (Widget) lw))
    {
      lw->label.label_type = XmSTRING;
    }
  
  if (!XmRepTypeValidValue(XmRID_ALIGNMENT, lw->label.alignment, (Widget) lw))
    {
      lw->label.alignment = XmALIGNMENT_CENTER;
    }
  
#ifndef NO_XM_1_2_BC
  /*
   * Some pre-Motif 2.0 XmManager subclasses may be bypassing the
   * synthetic resouce GetValues hook and passing us the manager's raw
   * string_direction field (which is now a layout_direction).  Fixup
   * the common/simple cases. 
   */
  switch (lw->label.string_direction)
    {
    case XmLEFT_TO_RIGHT:
    case XmRIGHT_TO_LEFT:
      /* These string directions are erroneous uses of layout directions. */
      lw->label.string_direction = 
	XmDirectionToStringDirection(lw->label.string_direction);
      break;
    default:
      /* Other unknown layout directions will still get a warning. */
      break;
    }
#endif

  /* If layout_direction is set, it overrides string_direction.
   * If string_direction is set, but not layout_direction, use
   *	string_direction value.
   * If neither is set, get from parent 
   */
  if (XmPrim_layout_direction(lw) != XmDEFAULT_DIRECTION) {
    if (lw->label.string_direction == XmDEFAULT_DIRECTION) 
      lw->label.string_direction = 
	XmDirectionToStringDirection(XmPrim_layout_direction(lw));
  } else if (lw->label.string_direction != XmDEFAULT_DIRECTION) {
    XmPrim_layout_direction(lw) = 
      XmStringDirectionToDirection(lw->label.string_direction);
  } else {
    XmPrim_layout_direction(lw) = _XmGetLayoutDirection(XtParent(new_w));
    lw->label.string_direction = 
      XmDirectionToStringDirection(XmPrim_layout_direction(lw));
  }
  
  if (!XmRepTypeValidValue(XmRID_STRING_DIRECTION,
			   lw->label.string_direction, (Widget) lw))
    {
      lw->label.string_direction = XmSTRING_DIRECTION_L_TO_R;
    }
  
  /* Make a local copy of the font list */
  if (lw->label.font == NULL)
    {
      /* CR 2990: Let subclasses choose their own default font. */
      lw->label.font = XmeGetDefaultRenderTable (new_w, XmLABEL_FONTLIST);
    }
  lw->label.font = XmFontListCopy(lw->label.font);
  
  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass(XtParent(new_w)), XmQTmenuSystem);
  
  /* get menu type and which button */
  if (menuSTrait != (XmMenuSystemTrait) NULL)
    lw->label.menu_type = menuSTrait->type(XtParent(new_w));
  else
    lw->label.menu_type = XmWORK_AREA;
  
  /*  Handle the label string :
   *   If label is the constant XmUNSPECIFIED, creates a empty XmString.
   *    (this is used by DrawnB instead of a default conversion that leads
   *     to a leak when someone provides a real label)
   *   If no label string is given accept widget's name as default.
   *     convert the widgets name to an XmString before storing;
   *   else
   *     save a copy of the given string.
   *     If the given string is not an XmString issue an warning.
   */
  if (lw->label._label == (XmString) XmUNSPECIFIED)
    {
      lw->label._label = XmeGetLocalizedString ((char *) NULL, /* reserved */
						(Widget) lw,
						XmNlabelString,
						"");
    }
  else if (lw->label._label == NULL)   
    {
      lw->label._label = XmeGetLocalizedString ((char *) NULL, /* reserved */
						(Widget) lw,
						XmNlabelString,
						lw->core.name);
    }
  else if (XmeStringIsValid(lw->label._label))
    {
      lw->label._label= XmStringCopy(lw->label._label);
    }
  else
    {
      XmeWarning((Widget) lw, CS_STRING_MESSAGE);
      lw->label._label = XmStringCreateLocalized(lw->core.name);
    }
  
  /*
   * Convert the given mnemonicCharset to the internal Xm-form.
   */
  if  (lw->label.mnemonicCharset != NULL)
    lw->label.mnemonicCharset =
      _XmStringCharSetCreate (lw->label.mnemonicCharset);
  else
    lw->label.mnemonicCharset =
      _XmStringCharSetCreate (XmFONTLIST_DEFAULT_TAG);
  
  /* Accelerators are currently only supported in menus */
  if ((lw->label._acc_text != NULL) && Lab_IsMenupane(lw))
    {
      if (XmeStringIsValid((XmString) lw->label._acc_text))
        {
	  /*
	   * Copy the input string into local space, if
	   * not a Cascade Button
	   */
	  if (XmIsCascadeButton(lw))
	    lw->label._acc_text = NULL;
	  else
	    lw->label._acc_text =
	      XmStringCopy((XmString) lw->label._acc_text);
        }
      else
        {
	  XmeWarning((Widget) lw, ACC_MESSAGE);
	  lw->label._acc_text = NULL;
        }
    }
  else
    lw->label._acc_text = NULL;
  
  
  if ((lw->label.accelerator != NULL) && Lab_IsMenupane(lw))
    {
      /* Copy the accelerator into local space */
      lw->label.accelerator = XtNewString(lw->label.accelerator);
    }
  else
    lw->label.accelerator = NULL;
  
  lw->label.skipCallback = FALSE;
  
  lw->label.acc_right_delta = 0;
  lw->label.acc_left_delta = 0;
  
  /*  If zero width and height was requested by the application,  */
  /*  reset new_w's width and height to zero to allow Resize()   */
  /*  to operate properly.                                        */
  
  if (req->core.width == 0)
    lw->core.width = 0;  
  
  if (req->core.height == 0)
    lw->core.height = 0;
  
  /* CR 6267:  Suppress highlight thickness before sizing also. */
  if ((lw->label.menu_type == XmMENU_POPUP) ||
      (lw->label.menu_type == XmMENU_PULLDOWN) ||
      (lw->label.menu_type == XmMENU_BAR))
    lw->primitive.highlight_thickness = 0;
  
  _XmCalcLabelDimensions(new_w);

  /* CR 7283: We can't use the resize method pointer, because */
  /*	subclasses haven't been initialized yet.	      */
  Resize((Widget) lw); 

  SetNormalGC(lw);
  
  /* Force the label traversal flag when in a menu. */
  
  if ((XtClass(lw) == xmLabelWidgetClass) &&
      ((lw->label.menu_type == XmMENU_POPUP) ||
       (lw->label.menu_type == XmMENU_PULLDOWN) ||
       (lw->label.menu_type == XmMENU_OPTION)))
    {
      lw->primitive.traversal_on = FALSE;
      lw->primitive.highlight_on_enter = FALSE;
    }
  
  /* if in menu, override with menu traversal translations */
  if ((lw->label.menu_type == XmMENU_POPUP) ||
      (lw->label.menu_type == XmMENU_PULLDOWN) ||
      (lw->label.menu_type == XmMENU_BAR) ||
      (lw->label.menu_type == XmMENU_OPTION))
    {

      _XmProcessLock();
      trans = (XtTranslations) 
	  ((XmLabelClassRec *)XtClass(lw))->label_class.translations;
      _XmProcessUnlock();
     
      XtOverrideTranslations((Widget) lw, trans);
    }
  else
    {
	
      _XmProcessLock();
      trans = (XtTranslations)
	  ((XmPrimitiveClassRec *) XtClass(lw))->primitive_class.translations;
      _XmProcessUnlock();
     
      /* Otherwise override with primitive traversal translations */
      XtOverrideTranslations((Widget) lw, trans);
    }
}

/************************************************************************
 *
 *  QueryGeometry
 *
 ************************************************************************/
static XtGeometryResult 
QueryGeometry(
        Widget widget,
        XtWidgetGeometry *intended,
        XtWidgetGeometry *desired)
{
  XmLabelWidget lw = (XmLabelWidget) widget;
  
  if (lw->label.recompute_size == FALSE) 
    {
      desired->width = XtWidth(widget);
      desired->height = XtHeight(widget);
    } 
  else
    {
      desired->width = (Dimension) lw->label.TextRect.width +
	(2 * (lw->label.margin_width +
	      lw->primitive.highlight_thickness +
	      lw->primitive.shadow_thickness)) +
		lw->label.margin_left +
		  lw->label.margin_right;
      if (desired->width == 0) 
	desired->width = 1;
      
      desired->height = (Dimension) MAX(lw->label.TextRect.height,
					lw->label.acc_TextRect.height)
	+ (2 * (lw->label.margin_height +
		lw->primitive.highlight_thickness +
		lw->primitive.shadow_thickness)) +
		  lw->label.margin_top +
		    lw->label.margin_bottom;
      if (desired->height == 0) 
	desired->height = 1;
    }
  
  return XmeReplyToQueryGeometry(widget, intended, desired);
}

/************************************************************************
 *
 *  Destroy
 *      Free up the label gadget allocated space.  This includes
 *      the label, and GC's.
 *
 ************************************************************************/
static void 
Destroy(
        Widget w)
{
  XmLabelWidget lw = (XmLabelWidget) w;
  
  if (lw->label._label != NULL) 
    XmStringFree (lw->label._label);

  if (lw->label._acc_text != NULL) 
    XmStringFree (lw->label._acc_text);

  if (lw->label.accelerator != NULL)
    XtFree (lw->label.accelerator);

  if (lw->label.font != NULL)
    XmFontListFree (lw->label.font);

  if (lw->label.mnemonicCharset != NULL)
    XtFree (lw->label.mnemonicCharset);

  if (lw->label.baselines != NULL)
    XtFree ((char*) lw->label.baselines);

  XtReleaseGC ((Widget) lw, lw->label.normal_GC);
  XtReleaseGC ((Widget) lw, lw->label.insensitive_GC);
}

/************************************************************************
 *
 *  Redisplay
 *

 ***********************************************************************/
static void 
Redisplay(
        Widget wid,
        XEvent *event,
        Region region)
{
  XmLabelWidget lw = (XmLabelWidget) wid;
  GC gc;
  GC clipgc = NULL;
  XRectangle clip_rect;
  XmLabelPart *lp;
  Dimension availW, availH, marginal_width, marginal_height, max_text_height;
  int depth;
  
  lp = &(lw->label);
  
  /*
   * Set a clipping area if the label will overwrite critical margins.
   * A critical margin is defined to be "margin_{left,right,
   * top,bottom} margin" because it used for other things
   * such as default_button_shadows and accelerators.   Note that
   * overwriting the "margin_{width,height}" margins is allowed.
   */
  availH = lw->core.height;
  availW = lw->core.width;
  
  /* Adjust definitions of temporary variables */
  marginal_width = lp->margin_left + lp->margin_right +
    (2 * (lw->primitive.highlight_thickness +
	  lw->primitive.shadow_thickness));
  
  marginal_height = lp->margin_top + lp->margin_bottom +
    (2 * (lw->primitive.highlight_thickness +
	  lw->primitive.shadow_thickness));
  
  max_text_height = MAX(lp->TextRect.height, lp->acc_TextRect.height);
  
  if (XtIsSensitive(wid))
    clipgc = lp->normal_GC;
  else
    clipgc = lp->insensitive_GC;
      
  if ((availH < (Dimension)(marginal_height + max_text_height)) ||
      (availW < (Dimension)(marginal_width + lp->TextRect.width)))
    {
      clip_rect.x = lw->primitive.highlight_thickness +
	lw->primitive.shadow_thickness + lp->margin_left;
      clip_rect.y = lw->primitive.highlight_thickness +
	lw->primitive.shadow_thickness + lp->margin_top;
      
      /* Don't allow negative dimensions. */
      if (availW > marginal_width)
	clip_rect.width = availW - marginal_width;
      else
	clip_rect.width = 0;
      
      if (availH > marginal_height)
	clip_rect.height = availH - marginal_height;
      else
	clip_rect.height = 0;
      
      XSetClipRectangles(XtDisplay(lw), clipgc, 0,0, &clip_rect, 1, Unsorted);
    } else
      XSetClipMask (XtDisplay (lw), clipgc, None);
  
  if (Lab_IsPixmap(lw))
    {
      if (XtIsSensitive(wid)) 
	{
	  if (Pix (lw) != XmUNSPECIFIED_PIXMAP)
	    {
	      gc = lp->normal_GC;
	      
	      XmeGetPixmapData(XtScreen(lw), Pix(lw), NULL, &depth,
			       NULL, NULL, NULL, NULL, NULL, NULL);   
	      
	      if (depth == lw->core.depth)
		XCopyArea (XtDisplay(lw), Pix(lw), XtWindow(lw), gc, 0, 0, 
			   lp->TextRect.width, lp->TextRect.height,
			   lp->TextRect.x, lp->TextRect.y); 
	      else if (depth == 1)
		XCopyPlane (XtDisplay(lw), Pix(lw), XtWindow(lw), 
			    gc, 0, 0, 
			    lp->TextRect.width, lp->TextRect.height,
			    lp->TextRect.x, lp->TextRect.y, 1); 
	    }
	}
      else 
	{
	  Pixmap pix_use = Pix_insen (lw) ;

	  if (pix_use == XmUNSPECIFIED_PIXMAP)
	      pix_use = Pix(lw);

	  if (pix_use != XmUNSPECIFIED_PIXMAP) 
	    {
	      gc = lp->insensitive_GC;
	      
	      XmeGetPixmapData(XtScreen(lw), pix_use, NULL, &depth,
			       NULL, NULL, NULL, NULL, NULL, NULL);   
	      
	      if (depth == lw->core.depth)
		XCopyArea (XtDisplay(lw), pix_use, XtWindow(lw), 
			   gc, 0, 0, 
			   lp->TextRect.width, lp->TextRect.height,
			   lp->TextRect.x, lp->TextRect.y); 
	      else if (depth == 1)
		XCopyPlane (XtDisplay(lw), pix_use, XtWindow(lw), 
			    gc, 0, 0, 
			    lp->TextRect.width, lp->TextRect.height,
			    lp->TextRect.x, lp->TextRect.y, 1); 

	      /* if no insensitive pixmap but a regular one, we need
 		 to do the stipple manually, since copyarea doesn't */
 	      if (pix_use == Pix(lw)) {
 		  /* need fill stipple, not opaque */
 		  XSetFillStyle(XtDisplay(lw), gc, FillStippled);
 		  XFillRectangle(XtDisplay(lw), XtWindow(lw), 
 				 gc, lp->TextRect.x, lp->TextRect.y, 
 				 lp->TextRect.width, lp->TextRect.height);
 		  XSetFillStyle(XtDisplay(lw), gc, FillOpaqueStippled);
 	      }
	    }
	}
    }
  
  else if ((Lab_IsText (lw)) && (lp->_label != NULL)) 
    {
      if (lp->mnemonic != XK_VoidSymbol)
	{ 
	  /* CR 5181: Convert the mnemonic keysym to a character string. */
	  char tmp[MB_LEN_MAX * 2];
	  XmString underline;
 
 	  tmp[_XmOSKeySymToCharacter(lp->mnemonic, NULL, tmp)] = '\0';
	  underline = XmStringCreate(tmp, lp->mnemonicCharset);
	  
	  XmStringDrawUnderline(XtDisplay(lw), XtWindow(lw),
				lp->font, lp->_label,
				(XtIsSensitive(wid) ? 
				 lp->normal_GC : lp->insensitive_GC),
				lp->TextRect.x, lp->TextRect.y,
				lp->TextRect.width, lp->alignment,
				XmPrim_layout_direction(lw), NULL,
				underline);
	  XmStringFree(underline);
	}
      else
	XmStringDraw (XtDisplay(lw), XtWindow(lw),
		       lp->font, lp->_label,
		       (XtIsSensitive(wid) ? 
			lp->normal_GC : lp->insensitive_GC),
		       lp->TextRect.x, lp->TextRect.y,
		       lp->TextRect.width, lp->alignment,
		       XmPrim_layout_direction(lw), NULL);
    }
  
  if (lp->_acc_text != NULL) 
    {
      /* Since accelerator text  is drawn by moving in from the right,
       * it is possible to overwrite label text when there is clipping,
       * Therefore draw accelerator text only if there is enough
       * room for everything
       */
      
      if (lw->core.width >= (Dimension)
	  (2 * (lw->primitive.highlight_thickness +
		lw->primitive.shadow_thickness +
		lp->margin_width) +
	   lp->margin_left + lp->TextRect.width + lp->margin_right))
	XmStringDraw (XtDisplay(lw), XtWindow(lw),
		       lp->font, lp->_acc_text,
		       (XtIsSensitive(wid) ? 
			lp->normal_GC : lp->insensitive_GC),
		       lp->acc_TextRect.x, lp->acc_TextRect.y,
		       lp->acc_TextRect.width, XmALIGNMENT_END,
		       XmPrim_layout_direction(lw), NULL);
    }
  
  /* Redraw the proper highlight  */
  if (! Lab_IsMenupane(lw) && Lab_MenuType(lw) != XmMENU_BAR)
    {
      XtExposeProc expose;

      _XmProcessLock();
      expose = (xmPrimitiveClassRec.core_class.expose);
      _XmProcessUnlock();

      /* Envelop our superclass expose method */
      (*(expose))((Widget) lw, event, region);
    }
}

/**********************************************************************
 *
 * Enter
 *
 *********************************************************************/

static void 
Enter(Widget wid,
      XEvent *event,
      String *params,
      Cardinal *num_params)
{
  XmLabelWidget w = (XmLabelWidget) wid;

  if (w->primitive.highlight_on_enter)
    _XmPrimitiveEnter (wid, event, params, num_params);
}

/**********************************************************************
 *
 * Leave
 *
 *********************************************************************/

static void 
Leave(Widget wid,
      XEvent *event,
      String *params,
      Cardinal *num_params)
{
  XmLabelWidget w = (XmLabelWidget) wid;

  if (w->primitive.highlight_on_enter)
    _XmPrimitiveLeave ((Widget) w, event, params, num_params);
}

/************************************************************************
 *
 * SetValues
 *	This routine will take care of any changes that have been made.
 *
 ************************************************************************/

/*ARGSUSED*/
static Boolean 
SetValues(Widget cw,
	  Widget rw,
	  Widget nw,
	  ArgList args,		/* unused */
	  Cardinal *num_args)	/* unused */
{
  XmLabelWidget current = (XmLabelWidget) cw;
  XmLabelWidget req = (XmLabelWidget) rw;
  XmLabelWidget new_w = (XmLabelWidget) nw;
  Boolean flag = FALSE;
  Boolean newstring = FALSE;
  XmLabelPart        *newlp, *curlp, *reqlp;
  Boolean ProcessFlag = FALSE;
  Boolean CleanupFontFlag = FALSE;
  Boolean Call_Resize = False;
  XmMenuSystemTrait menuSTrait;
  
  /* Get pointers to the label parts  */
  newlp = &(new_w->label);
  curlp = &(current->label);
  reqlp = &(req->label);
  
  
  /* Discard the baseline cache if it is no longer valid. */
  if ((newlp->_label != curlp->_label) ||
      (newlp->font != curlp->font))
    {
      if (newlp->baselines)
	{
	  XtFree ((char*) newlp->baselines);
	  newlp->baselines = NULL;
	}
    }

  /* If the label has changed, make a copy of the new label */
  /* and free the old label.                                */
  
  if (newlp->_label != curlp->_label)
    {   
      newstring = TRUE;
      if (newlp->_label == NULL)
	{ 
          newlp->_label = XmStringCreateLocalized(new_w->core.name);
	}
      else
	{ 
	  if (XmeStringIsValid((XmString) newlp->_label))
	    newlp->_label = XmStringCopy((XmString) newlp->_label);     
	  else
	    {
	      XmeWarning((Widget) new_w, CS_STRING_MESSAGE);
	      
	      newlp->_label = XmStringCreateLocalized(new_w->core.name);
	    }
	}
      
      XmStringFree(curlp->_label);
      curlp->_label= NULL;
      reqlp->_label= NULL;
    }
  
  
  if (newlp->margin_right != curlp->margin_right)
    newlp->acc_right_delta = 0;
  if (newlp->margin_left != curlp->margin_left)
    newlp->acc_left_delta = 0;
  
  if ((newlp->_acc_text != curlp->_acc_text) && 
      Lab_IsMenupane(new_w))
    {
      /* BEGIN OSF Fix pir 1098 */
      newstring = TRUE;
      /* END OSF Fix pir 1098 */
      if (newlp->_acc_text != NULL)
	{
	  if (XmeStringIsValid((XmString) newlp->_acc_text))
	    {
	      if ((XmIsCascadeButton (new_w)) && (newlp->_acc_text != NULL))
		newlp->_acc_text = NULL;
	      else
		newlp->_acc_text = XmStringCopy((XmString) newlp->_acc_text);

	      XmStringFree(curlp->_acc_text);
	      curlp->_acc_text= NULL;
	      reqlp->_acc_text= NULL;
	    }
	  else
	    {
	      XmeWarning((Widget) new_w, ACC_MESSAGE);
	      newlp->_acc_text = NULL;
	      curlp->_acc_text= NULL;
	      reqlp->_acc_text= NULL;
	    }
	}
      /* BEGIN OSF Fix pir 1098 */
      else if (curlp->_acc_text)
	{
	  /* CR 3481:  Don't blindly force the margin back to 0; */
	  /* 	try to preserve the user specified value. */
	  if (LayoutIsRtoLP(new_w))
	    {
	      newlp->margin_left -= newlp->acc_left_delta;
	      newlp->acc_left_delta = 0;
	    }
	  else
	    {
	      newlp->margin_right -= newlp->acc_right_delta;
	      newlp->acc_right_delta = 0;
	    }
	}
      /* END OSF Fix pir 1098 */
    }
  else
    newlp->_acc_text = curlp->_acc_text;
  
  
  if (newlp->font != curlp->font)
    {
      CleanupFontFlag = True;
      if (newlp->font == NULL)
	{
	  /* CR 2990:  Let subclasses determine default fonts. */
	  newlp->font =
	    XmeGetDefaultRenderTable((Widget) new_w, XmLABEL_FONTLIST);
	}
      newlp->font = XmFontListCopy (newlp->font);
      
    }
  
  if ((new_w->label.menu_type == XmMENU_POPUP) ||
      (new_w->label.menu_type == XmMENU_PULLDOWN) ||
      (new_w->label.menu_type == XmMENU_BAR))
    new_w->primitive.highlight_thickness = 0;
  
  if (!XmRepTypeValidValue(XmRID_LABEL_TYPE, new_w->label.label_type,
			   (Widget) new_w))
    {
      new_w->label.label_type = current->label.label_type;
    }
  
  if (LayoutP(new_w) != LayoutP(current))
    {
      /* if no new margins specified swap them */
      if ((LayoutIsRtoLP(current) != LayoutIsRtoLP(new_w)) &&
	  (Lab_MarginLeft(current)  == Lab_MarginLeft(new_w)) &&
	  (Lab_MarginRight(current) == Lab_MarginRight(new_w)))
	{
	  Lab_MarginLeft(new_w)  = Lab_MarginRight(current);
	  Lab_MarginRight(new_w) = Lab_MarginLeft(current);
	}
      flag = TRUE;
    }
  
  /* ValidateInputs(new_w); */
  
  if ((Lab_IsText(new_w) && 
       ((newstring) ||
	(newlp->font != curlp->font))) ||
      (Lab_IsPixmap(new_w) &&
       ((newlp->pixmap != curlp->pixmap) ||
	(newlp->pixmap_insen  != curlp->pixmap_insen) ||
	/* When you have different sized pixmaps for sensitive and */
	/* insensitive states and sensitivity changes, */
	/* the right size is chosen. (osfP2560) */
	(XtIsSensitive(nw) != XtIsSensitive(cw)))) ||
      (newlp->label_type != curlp->label_type))
    {
      /* CR 9179: Redo CR 5419 changes. */

      if (newlp->recompute_size)
	{
	  if (req->core.width == current->core.width)
	    new_w->core.width = 0;
	  if (req->core.height == current->core.height)
	    new_w->core.height = 0;
	}
	  
      _XmCalcLabelDimensions((Widget) new_w);

      Call_Resize = True;

      flag = True;
    }
  
  if ((newlp->alignment != curlp->alignment) ||
      (XmPrim_layout_direction(new_w) != 
       XmPrim_layout_direction(current))) 
    {
      if (!XmRepTypeValidValue(XmRID_ALIGNMENT, new_w->label.alignment,
			       (Widget) new_w))
	{
	  new_w->label.alignment = current->label.alignment;
	}
      
      Call_Resize = True;
      
      flag = True;
    }
  
  if ((newlp->margin_height != curlp->margin_height) ||
      (newlp->margin_width != curlp->margin_width) ||
      (newlp->margin_left != curlp->margin_left) ||
      (newlp->margin_right != curlp->margin_right) ||
      (newlp->margin_top != curlp->margin_top) ||
      (newlp->margin_bottom != curlp->margin_bottom) ||
      (new_w->primitive.shadow_thickness !=
       current->primitive.shadow_thickness) ||
      (new_w->primitive.highlight_thickness !=
       current->primitive.highlight_thickness) ||
      ((new_w->core.width <= 0) || (new_w->core.height <= 0)))
    {
      if (!XmRepTypeValidValue(XmRID_ALIGNMENT, new_w->label.alignment,
			       (Widget) new_w))
        {
	  new_w->label.alignment = current->label.alignment;
        }
      
      if (!XmRepTypeValidValue(XmRID_STRING_DIRECTION,
			       new_w->label.string_direction, (Widget) new_w))
        {
	  new_w->label.string_direction = current->label.string_direction;
        }
      
      if (newlp->recompute_size)
        {
          if (req->core.width == current->core.width)
            new_w->core.width = 0;
          if (req->core.height == current->core.height)
            new_w->core.height = 0;
        }
      
      Call_Resize = True;
      
      flag = True;
    }
  
  
  /* Resize is called only if we need to calculate the dimensions or */
  /* coordinates  for the string.				     */
  if (Call_Resize)
    {
      XtWidgetProc resize;

      /* CR 5419: Suppress redundant calls to DrawnB's resize callbacks. */
      Boolean was_computing = newlp->computing_size;

      newlp->computing_size = TRUE;

      _XmProcessLock();
      resize = new_w->core.widget_class->core_class.resize;
      _XmProcessUnlock();

      (* (resize)) ((Widget) new_w); 
      newlp->computing_size = was_computing;
    }
  
  
  
  /*
   * If sensitivity of the label has changed then we must redisplay
   *  the label.
   */
  if (XtIsSensitive(nw) != XtIsSensitive(cw))
    {
      flag = TRUE;
    }
  
  if ((new_w->primitive.foreground != current->primitive.foreground) ||
      (new_w->core.background_pixel != current->core.background_pixel) ||
      (newlp->font != curlp->font))
    {
      XtReleaseGC((Widget) current, current->label.normal_GC);
      XtReleaseGC((Widget) current, current->label.insensitive_GC);
      SetNormalGC(new_w);
      flag = TRUE;
    }
  
  /*  Force the traversal flag when in a menu.  */
  
  if ((XtClass(new_w) == xmLabelWidgetClass) &&
      ((new_w->label.menu_type == XmMENU_POPUP) ||
       (new_w->label.menu_type == XmMENU_PULLDOWN) ||
       (new_w->label.menu_type == XmMENU_OPTION)))
    {
      new_w->primitive.traversal_on = FALSE;
      new_w->primitive.highlight_on_enter = FALSE;
    }
  
  if (new_w->primitive.traversal_on &&
      (new_w->primitive.traversal_on != current->primitive.traversal_on) &&
      new_w->core.tm.translations)
    {

     XtTranslations trans;

     if ((new_w->label.menu_type == XmMENU_POPUP) ||
	  (new_w->label.menu_type == XmMENU_PULLDOWN) ||
	  (new_w->label.menu_type == XmMENU_BAR) ||
	  (new_w->label.menu_type == XmMENU_OPTION))
	{

	  _XmProcessLock();
	  trans = (XtTranslations) 
	      ((XmLabelClassRec *)XtClass(new_w))->label_class.translations;
	  _XmProcessUnlock();	    
	  if (trans) XtOverrideTranslations((Widget)new_w, trans);
	}
      else
	{
	    
	  _XmProcessLock();
	  trans = (XtTranslations) 
	     ((XmLabelClassRec*) XtClass(new_w))->primitive_class.translations;
	  _XmProcessUnlock();	    
	  if (trans) XtOverrideTranslations ((Widget)new_w, trans);
	}
    }
  
  if ((new_w->label.menu_type != XmWORK_AREA) &&
      (new_w->label.mnemonic != current->label.mnemonic))
    {
      /* New grabs only required if mnemonic changes */
      ProcessFlag = TRUE;
      if (new_w->label.label_type == XmSTRING)
	flag = TRUE;
    }
  
  if (new_w->label.mnemonicCharset != current->label.mnemonicCharset)
    {
      if (new_w->label.mnemonicCharset)
	new_w->label.mnemonicCharset =
	  _XmStringCharSetCreate(new_w->label.mnemonicCharset);
      else
	new_w->label.mnemonicCharset =
	  _XmStringCharSetCreate(XmFONTLIST_DEFAULT_TAG);
      
      if (current->label.mnemonicCharset != NULL)
	XtFree (current->label.mnemonicCharset);
      
      if (new_w->label.label_type == XmSTRING)
	flag = TRUE;
    }
  
  if (Lab_IsMenupane(new_w) &&
      (new_w->label.accelerator != current->label.accelerator))
    {
      if (newlp->accelerator != NULL)
	{
	  /* Copy the accelerator into local space */
	  newlp->accelerator = XtNewString(newlp->accelerator);
	}

      XtFree(curlp->accelerator);
      curlp->accelerator = NULL;
      reqlp->accelerator = NULL;
      ProcessFlag = TRUE;
    }
  else
    newlp->accelerator = curlp->accelerator;
  
  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass(XtParent(current)), XmQTmenuSystem);
  
  if (ProcessFlag && menuSTrait != NULL)
    menuSTrait->updateBindings((Widget)new_w, XmREPLACE);
  
  if (flag &&
      (new_w->label.menu_type == XmMENU_PULLDOWN) && menuSTrait != NULL)
    menuSTrait->updateHistory(XtParent(new_w), (Widget) new_w, True);
  
  if (CleanupFontFlag)
    if (curlp->font) XmFontListFree(curlp->font); 
  
  return flag;
}

/************************************************************************
 *
 *  SetActivateCallbackState
 *
 * This function is used as the method of the menuSavvy trait. It is 
 * used by menu savvy parents to set whether or not the child will
 * invoke its own activate callback or whether it will defer to the
 * entryCallback of the parent.
 *
 ************************************************************************/

static void 
SetActivateCallbackState(Widget          wid,
			 XmActivateState state)
{
  XmLabelWidget w = (XmLabelWidget) wid;

  switch (state)
    {
    case XmDISABLE_ACTIVATE:
      w->label.skipCallback = True;
      break;

    case XmENABLE_ACTIVATE:
      w->label.skipCallback = False;
      break;
    }
}

/************************************************************************
 *
 * SetOverrideCallback
 *	Used by subclasses.  If this is set true, then there is a RowColumn
 * parent with the entryCallback resource set.  The subclasses do not
 * do their activate callbacks, instead the RowColumn callbacks are called
 * by RowColumn.
 ************************************************************************/

static void 
SetOverrideCallback(Widget wid)
{
  XmLabelWidget w = (XmLabelWidget) wid;

  w->label.skipCallback = True;
}

/************************************************************************
 *
 *  Help
 *      This routine is called if the user made a help selection
 *      on the widget.
 *
 ************************************************************************/

static void 
Help(Widget w,
     XEvent *event,
     String *params,
     Cardinal *num_params)
{
  XmLabelWidget lw = (XmLabelWidget) w;
  Widget parent = XtParent(lw);
  XmMenuSystemTrait menuSTrait;
  
  menuSTrait = (XmMenuSystemTrait) 
    XmeTraitGet((XtPointer) XtClass(XtParent(lw)), XmQTmenuSystem);
  
  if (Lab_IsMenupane(lw) && menuSTrait != NULL)
    menuSTrait->popdown((Widget) parent, event);
  
  _XmPrimitiveHelp((Widget) w, event, params, num_params);
}

/************************************************************************
 *
 * GetLabelString
 *	This is a get values hook function that returns the external
 * form of the label string from the internal form.
 *
 ***********************************************************************/

/*ARGSUSED*/
static void 
GetLabelString(Widget wid,
	       int resource,	/* unused */
	       XtArgVal *value)
{
  XmLabelWidget lw = (XmLabelWidget) wid;
  XmString string;
 
  string = XmStringCopy(lw->label._label);

  *value = (XtArgVal) string;
}

/************************************************************************
 *
 *  GetAccelerator
 *     This is a get values hook function that returns a copy
 *     of the accelerator string.
 *
 ***********************************************************************/

/*ARGSUSED*/
static void
GetAccelerator(Widget wid,
	       int resource,	/* unused */
	       XtArgVal *value)
{
  XmLabelWidget lw = (XmLabelWidget) wid;
  String string;

  string = XtNewString(Lab_Accelerator(lw));

  *value = (XtArgVal) string;
}

/************************************************************************
 *
 *  GetAcceleratorText
 *     This is a get values hook function that returns the external
 *     form of the accelerator text from the internal form.
 *
 ***********************************************************************/

/*ARGSUSED*/
static void 
GetAcceleratorText(Widget wid,
		   int resource, /* unused */
		   XtArgVal *value)
{
  XmLabelWidget lw = (XmLabelWidget) wid;
  XmString string;

  string = XmStringCopy(lw->label._acc_text);

  *value = (XtArgVal) string;
}

/************************************************************************
 *
 *  XmCreateLabelWidget
 *      Externally accessable function for creating a label gadget.
 *
 ************************************************************************/

Widget 
XmCreateLabel(Widget parent,
	      char *name,
	      Arg *arglist,
	      Cardinal argCount)
{
  return XtCreateWidget(name,xmLabelWidgetClass,parent,arglist,argCount);
}

static XmStringCharSet 
_XmStringCharSetCreate(XmStringCharSet stringcharset)
{
  return (XmStringCharSet) XtNewString((char*) stringcharset);
}

/************************************************************************
 *
 * GetMnemonicCharSet
 *	 This is a get values hook function that returns the external
 * form of the mnemonicCharSet from the internal form.  Returns a
 * string containg the mnemonicCharSet.  Caller must free the string.
 ***********************************************************************/

/*ARGSUSED*/
static void 
GetMnemonicCharSet(Widget wid,
		   int resource, /* unused */
		   XtArgVal *value)
{
  XmLabelWidget lw = (XmLabelWidget) wid;
  char *cset;
  int   size;
  
  cset = NULL;
  if (lw->label.mnemonicCharset)
    { 
      size = strlen (lw->label.mnemonicCharset);
      if (size > 0)
	cset = (char *) (_XmStringCharSetCreate(lw->label.mnemonicCharset));
    }
  
  *value = (XtArgVal) cset;
}

/*ARGSUSED*/
static void 
SetValuesAlmost(Widget cw,	/* unused */
		Widget nw,
		XtWidgetGeometry *request,
		XtWidgetGeometry *reply)
{  
  XmLabelWidget new_w = (XmLabelWidget) nw;
  XtWidgetProc resize;
  
  _XmProcessLock();
  resize = new_w->core.widget_class->core_class.resize;
  _XmProcessUnlock();

  (* (resize)) ((Widget) new_w); 
  *request = *reply;
}

/************************************************************************
 *
 * XmLabelGetDisplayRect
 *	A Class function which returns True if the widget being passed in
 * has a display rectangle associated with it.  It also determines the
 * x,y coordinates of the character cell or pixmap relative to the origin,
 * and the width and height in pixels of the smallest rectangle that encloses
 * the text or pixmap.  This is assigned to the variable being passed in
 *
 ***********************************************************************/

static Boolean
XmLabelGetDisplayRect(Widget w,
		      XRectangle *displayrect)
{
  XmLabelWidget wid = (XmLabelWidget) w;

  (*displayrect).x = wid->label.TextRect.x;
  (*displayrect).y = wid->label.TextRect.y;
  (*displayrect).width = wid->label.TextRect.width;
  (*displayrect).height = wid->label.TextRect.height;

  return TRUE;
}

/************************************************************************
 *
 * XmLabelGetBaselines
 *	A Class function which when called returns True, if the widget
 * has a baseline and also determines the number of pixels from the y
 * origin to the first line of text and assigns it to the variable
 * being passed in.
 *
 ************************************************************************/

static Boolean
XmLabelGetBaselines(Widget wid,
		    Dimension **baselines,
		    int *line_count)
{
  XmLabelWidget lw = (XmLabelWidget)wid;
  Cardinal count;
  int delta;
  
  if (Lab_IsPixmap(wid)) 
    return False;

  /* Compute raw baselines if unavailable. */
  if (lw->label.baselines == NULL)
    {
      _XmStringGetBaselines(lw->label.font, lw->label._label,
			    &(lw->label.baselines), &count);
      assert(lw->label.baselines != NULL);

      /* Store the current offset in an extra location. */
      lw->label.baselines = (Dimension*)
	XtRealloc((char*) lw->label.baselines, (count+1) * sizeof(Dimension));
      lw->label.baselines[count] = 0;
    }
  else
    {
      count = XmStringLineCount(lw->label._label);
    }

  /* Readjust offsets if necessary. */
  delta = Lab_TextRect_y(lw) - lw->label.baselines[count];
  if (delta)
    {
      int tmp;
      for (tmp = 0; tmp <= count; tmp++)
	lw->label.baselines[tmp] += delta;
    }

  /* Copy the cached data. */
  *line_count = count;
  *baselines = (Dimension*) XtMalloc(*line_count * sizeof(Dimension));
  memcpy((char*) *baselines, (char*) lw->label.baselines,
	 *line_count * sizeof(Dimension));

  return True;
}
/************************************************************************
 *
 * XmLabelMarginsProc
 *
 ***********************************************************************/

/* ARGSUSED */
static void
XmLabelMarginsProc(Widget w,
		   XmBaselineMargins *margins_rec)
{
  
  if (margins_rec->get_or_set == XmBASELINE_SET) {
    Lab_MarginTop(w) = margins_rec->margin_top;
    Lab_MarginBottom(w) = margins_rec->margin_bottom;
  } else {
    margins_rec->margin_top = Lab_MarginTop(w);
    margins_rec->margin_bottom = Lab_MarginBottom(w);
    margins_rec->shadow = Lab_Shadow(w);
    margins_rec->highlight = Lab_Highlight(w);
    margins_rec->text_height = Lab_TextRect_height(w);
    margins_rec->margin_height = Lab_MarginHeight(w);
  }
}


static Widget
GetPixmapDragIcon(Widget w)
{
  XmLabelWidget lw = (XmLabelWidget) w;
  Arg args[10];
  int n;
  Widget drag_icon;
  Widget screen_object = XmGetXmScreen(XtScreen(w));
  unsigned int width, height;
  int depth;
  
  /* It's a labelPixmap, use directly the pixmap */
  
  XmeGetPixmapData(XtScreen(lw), Pix(lw), NULL, &depth, 
		   NULL, NULL, NULL, NULL, &width, &height);   
  
  n = 0;
  XtSetArg(args[n], XmNhotX, 0),				n++;
  XtSetArg(args[n], XmNhotY, 0),				n++;
  XtSetArg(args[n], XmNwidth, width),				n++;
  XtSetArg(args[n], XmNheight, height),				n++;
  XtSetArg(args[n], XmNmaxWidth, width),			n++;
  XtSetArg(args[n], XmNmaxHeight, height),			n++;
  XtSetArg(args[n], XmNdepth, depth),				n++;
  XtSetArg(args[n], XmNpixmap, Pix(lw)),			n++;
  XtSetArg(args[n], XmNforeground, lw->core.background_pixel),	n++;
  XtSetArg(args[n], XmNbackground, lw->primitive.foreground),	n++;
  assert(n <= XtNumber(args));
  drag_icon = XtCreateWidget("drag_icon", xmDragIconObjectClass,
			     screen_object, args, n);
  return drag_icon;
}

/*ARGSUSED*/
static void
ProcessDrag(Widget w,
	    XEvent *event,
	    String *params,
	    Cardinal *num_params)
{
  XmLabelWidget lw = (XmLabelWidget) w;
  Widget drag_icon;
  Arg args[10];
  int n;
  Time _time = _XmGetDefaultTime(w, event);
  XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(w));
  
  if (Lab_IsMenupane(w))
    XAllowEvents(XtDisplay(w), SyncPointer, _time);

  /* Disallow drag if this is a cascade button and armed - Hack alert */
  if (XmIsCascadeButton(w) && CB_IsArmed(w)) return;
  
  /* CDE - allow user to not drag labels and label subclasses
     also,  disable drag if enable_btn1_transfer is set to
     BUTTON2_ADJUST and the trigger was button2 */
  if (! dpy -> display.enable_unselectable_drag ||
      (dpy -> display.enable_btn1_transfer == XmBUTTON2_ADJUST &&
       event && event -> xany.type == ButtonPress &&
       event -> xbutton.button == 2)) return;

  /* CR 5141: Don't allow multi-button drags; they just cause confusion. */
  if (! (event->xbutton.state &
	 ~((Button1Mask >> 1) << event->xbutton.button) &
	 (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask)))
    {
      n = 0;
      XtSetArg(args[n], XmNcursorBackground, lw->core.background_pixel), n++;
      XtSetArg(args[n], XmNcursorForeground, lw->primitive.foreground),  n++;
  
      /* If it's a labelPixmap, only specify the pixmap icon */
      if (Lab_IsPixmap(lw) && (Pix(lw) != XmUNSPECIFIED_PIXMAP))
	{
	  drag_icon = GetPixmapDragIcon(w);
	  XtSetArg(args[n], XmNsourcePixmapIcon, drag_icon), n++;
	} 
      else
	{
	  drag_icon = XmeGetTextualDragIcon(w);
	  XtSetArg(args[n], XmNsourceCursorIcon, drag_icon), n++; 
	}
      XtSetArg(args[n], XmNdragOperations, XmDROP_COPY), n++;
      (void) XmeDragSource(w, NULL, event, args, n);
    }
}

/*ARGSUSED*/
void
_XmLabelConvert(Widget w, 
		XtPointer ignore, 
		XmConvertCallbackStruct *cs)
{
  enum { XmA_MOTIF_COMPOUND_STRING, XmACOMPOUND_TEXT, XmATEXT,
	 XmATARGETS, XmA_MOTIF_DROP, XmABACKGROUND, XmAFOREGROUND,
	 XmAPIXEL, XmA_MOTIF_EXPORT_TARGETS,
	 XmA_MOTIF_CLIPBOARD_TARGETS, NUM_ATOMS };
  static char *atom_names[] = {
    XmS_MOTIF_COMPOUND_STRING, XmSCOMPOUND_TEXT, XmSTEXT,
    XmSTARGETS, XmS_MOTIF_DROP, XmIBACKGROUND, XmIFOREGROUND,
    XmIPIXEL, XmS_MOTIF_EXPORT_TARGETS, XmS_MOTIF_CLIPBOARD_TARGETS };

  Atom atoms[XtNumber(atom_names)];
  Atom C_ENCODING;
  int target_count = 0;
  Atom type = None;
  XtPointer value = NULL;
  unsigned long size = 0;
  int format = 8;
  XmString label_string;
  Pixmap label_pixmap;
  Boolean is_pixmap;
  
  if (w == (Widget) NULL)
    {
      cs->status = XmCONVERT_REFUSE;
      return;
    }
  
  C_ENCODING = XmeGetEncodingAtom(w);
  assert(XtNumber(atom_names) == NUM_ATOMS);
  XInternAtoms(XtDisplayOfObject(w), atom_names, XtNumber(atom_names), 
	       False, atoms);

  if (cs->selection != atoms[XmA_MOTIF_DROP])
    {
      cs->status = XmCONVERT_REFUSE;
      return;
    }
  
  if (XtIsWidget(w)) 
    {
      label_string = ((XmLabelWidget) w)->label._label;
      label_pixmap = ((XmLabelWidget) w)->label.pixmap;
      is_pixmap = Lab_IsPixmap(w);
    } 
  else
    {
      label_string = ((XmLabelGadget) w)->label._label;
      label_pixmap = ((XmLabelGadget) w)->label.pixmap;
      is_pixmap = LabG_IsPixmap(w);
    }
  
  if (cs->target == atoms[XmATARGETS] ||
      cs->target == atoms[XmA_MOTIF_EXPORT_TARGETS] ||
      cs->target == atoms[XmA_MOTIF_CLIPBOARD_TARGETS]) 
    {
      Atom *targs;

      if (cs->target == atoms[XmATARGETS]) {
	targs = XmeStandardTargets(w, 5, &target_count);
      } else {
	target_count = 0;
	targs = (Atom *) XtMalloc(sizeof(Atom) * 5);
      }
      
      value = (XtPointer) targs;
      
      if (is_pixmap)
	{
	  targs[target_count] = XA_PIXMAP; target_count++;
	} 
      else 
	{
	  XtPointer temp;
	  unsigned long length;
	  char* ctext;
	  Boolean success;
	  
	  ctext = XmCvtXmStringToCT(label_string);
	  targs[target_count] = atoms[XmA_MOTIF_COMPOUND_STRING]; target_count++;
	  targs[target_count] = atoms[XmACOMPOUND_TEXT]; target_count++;
	  targs[target_count] = atoms[XmATEXT]; target_count++;
	  if (C_ENCODING != XA_STRING) {
	    temp = ConvertToEncoding(w, ctext, C_ENCODING, &length, &success);
	    if (success) {
	      targs[target_count] = C_ENCODING; 
	      target_count++;
	    }
	    XtFree((char*) temp);
	  }
	  temp = ConvertToEncoding(w, ctext, XA_STRING, &length, &success);
	  if (success) {
	    targs[target_count] = XA_STRING;
	    target_count++;
	  }
	  XtFree((char*) temp);
	  XtFree((char*) ctext);
	}
      type = XA_ATOM;
      size = target_count;
      format = 32;
    }
  
  if (cs->target == atoms[XmA_MOTIF_COMPOUND_STRING]) 
    {
      type = atoms[XmA_MOTIF_COMPOUND_STRING];
      format = 8;
      size = XmCvtXmStringToByteStream(label_string,
				       (unsigned char **) &value);
    }
  else if (cs->target == atoms[XmACOMPOUND_TEXT] ||
	   cs->target == atoms[XmATEXT] ||
	   cs->target == XA_STRING || 
	   cs->target == C_ENCODING) 
    {
      type = atoms[XmACOMPOUND_TEXT];
      format = 8;
      value = XmCvtXmStringToCT(label_string);
      if (value != NULL)
	size = strlen((char*) value);
      else
	size = 0;

      if (cs->target == XA_STRING) 
	{
	  Boolean success;

	  value = ConvertToEncoding(w, (char*) value, 
				    XA_STRING, &size, &success);

	  if (value != NULL && success == False)
	    cs->flags |= XmCONVERTING_PARTIAL;
	  type = XA_STRING;
	} 
      else if ((cs->target == atoms[XmATEXT] ||
		cs->target == C_ENCODING) &&
	       value != NULL) 
	{
	  char *cvt;
	  Boolean success;

	  cvt = (char*) ConvertToEncoding(w, (char*) value, 
					  C_ENCODING, &size, &success);

	  if (cvt != NULL && success == False)
	    cs->flags |= XmCONVERTING_PARTIAL;
	  
	  if (cvt != NULL && success) 
	    {
	      /* 100% ok */
	      XtFree((char*) value);
	      value = cvt;
	      type = C_ENCODING;
	    } 
	  else
	    {
	      /* If the request was C_ENCODING,  then return only C_ENCODING,
	       * not atoms[XmACOMPOUND_TEXT] */
	      if (cs->target == C_ENCODING) 
		{
		  XtFree((char*) value);
		  value = cvt;
		  type = C_ENCODING;
		} 
	      else
		if (cvt != NULL) XtFree(cvt);
	      type = atoms[XmACOMPOUND_TEXT];
	    }
	}
    }
  
  if (cs->target == XA_PIXMAP) 
    {
      /* Get widget's pixmap */
      Pixmap *pix;
      
      pix = (Pixmap *) XtMalloc(sizeof(Pixmap));
      *pix = label_pixmap;
      /* value, type, size, and format must be set */
      value = (XtPointer) pix;
      type = XA_DRAWABLE;
      size = 1;
      format = 32;
    }
  
  if (cs->target == atoms[XmABACKGROUND])
    {
      /* Get widget's background */
      Pixel *background;
      
      background = (Pixel *) XtMalloc(sizeof(Pixel));
      if (XtIsWidget(w))
	*background = ((XmLabelWidget) w)->core.background_pixel;
      else
	*background = LabG_Background(w);
      /* value, type, size, and format must be set */
      value = (XtPointer) background;
      type = atoms[XmAPIXEL];
      size = 1;
      format = 32;
    }
  
  if (cs->target == atoms[XmAFOREGROUND])
    {
      /* Get widget's foreground */
      Pixel *foreground;
      
      foreground = (Pixel *) XtMalloc(sizeof(Pixel));
      if (XtIsWidget(w))
	*foreground = ((XmLabelWidget) w)->primitive.foreground;
      else
	*foreground = LabG_Foreground(w);
      /* value, type, size, and format must be set */
      value = (XtPointer) foreground;
      type = atoms[XmAPIXEL];
      size = 1;
      format = 32;
    }
  
  if (cs->target == XA_COLORMAP)
    {
      /* Get widget's colormap */
      Colormap *colormap;
      
      colormap = (Colormap *) XtMalloc(sizeof(Colormap));
      if (XtIsWidget(w))
	*colormap = w->core.colormap;
      else
	*colormap = XtParent(w)->core.colormap;
      /* value, type, size, and format must be set */
      value = (XtPointer) colormap;
      type = XA_COLORMAP;
      size = 1;
      format = 32;
    }
  
  _XmConvertComplete(w, value, size, format, type, cs);
}

/**************************************************************************
 * ConvertToEncoding
 *
 * This contains conversion code which is needed more than once in
 * _XmLabelConvert.  The first calls are to check for 100% conversion
 * in _MOTIF_EXPORT_TARGETS and _MOTIF_CLIPBOARD_TARGETS.
 * The second are for the real conversion
 **************************************************************************/
static XtPointer 
ConvertToEncoding(Widget w, char* str, Atom encoding, 
		  unsigned long *length, Boolean *flag)
{
  XtPointer rval = NULL;
  XTextProperty tmp_prop;
  Atom COMPOUND_TEXT = XInternAtom(XtDisplay(w), XmSCOMPOUND_TEXT, False);
  int ret_status;

  if (encoding == XA_STRING) {
    /* convert value to 8859.1 */
    ret_status = 
      XmbTextListToTextProperty(XtDisplay(w), (char**) &str, 1, 
				(XICCEncodingStyle)XStringStyle,
				&tmp_prop);

    if (ret_status == Success || ret_status > 0) 
      {
	rval = (XtPointer) tmp_prop.value;
	*length = tmp_prop.nitems;
      } 
    else
      {
	rval = NULL;
	*length = 0;
      }

    *flag = (ret_status == Success);
  } else {
    /* Locale encoding */
    rval = _XmTextToLocaleText(w, (XtPointer) str,
			       COMPOUND_TEXT, 8, strlen(str),
			       flag);
  }

  return(rval);
}

    
/*
 * XmRCallProc routine for checking label.font before setting it to NULL
 * If "check_set_render_table" is True, then function has 
 * been called twice on same widget, thus resource needs to be set NULL, 
 * otherwise leave it alone.
 */

/*ARGSUSED*/
static void 
CheckSetRenderTable(Widget wid,
		    int offset,
		    XrmValue *value)
{
  XmLabelWidget lw = (XmLabelWidget)wid;

  /* Check if been here before */
  if (lw->label.check_set_render_table)
      value->addr = NULL;
  else {
      lw->label.check_set_render_table = True;
      value->addr = (char*)&(lw->label.font);
  }

}

static XtPointer
LabelGetValue(Widget w, int type)
{
  XmString value;
  
  XtVaGetValues(w, XmNlabelString, &value, 0);
  
  if (type == XmFORMAT_XmSTRING) 
    {
      return (XtPointer) value;
    } 
  else if (type == XmFORMAT_MBYTE || 
	   type == XmFORMAT_WCS)
    {
      XtPointer temp;
      temp = (type == XmFORMAT_MBYTE) ?
	_XmStringUngenerate(value, NULL, 
			    XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT) :
	_XmStringUngenerate(value, NULL, 
			    XmWIDECHAR_TEXT, XmWIDECHAR_TEXT);
      XmStringFree(value);
      return temp;
    }
  else
    return NULL;
}

static void
LabelSetValue(Widget w, XtPointer value, int type)
{
  Arg args[1];
  Cardinal nargs;
  XmString temp;
  Boolean freetemp = True;
  
  if (type == XmFORMAT_XmSTRING) 
    {
      temp = (XmString) value;
      freetemp = False;
    } 
  else
    {
      if (type == XmFORMAT_WCS) 
	{
	  int length;
	  char *str;
	  wchar_t *str2;
	  str2 = (wchar_t *) value;

	  /* Get length of wchar string */
	  length = 0;
	  while (str2[length] != 0)
	    length++;
	  str = (char*) XtMalloc(MB_CUR_MAX * length);
	  wcstombs(str, str2, length * MB_CUR_MAX);
	  XtFree((char*) value);
	  value = str;
	}
      temp = XmStringCreateLocalized((char*) value);
    }
  
  nargs = 0;
  XtSetArg(args[nargs], XmNlabelString, temp), nargs++;
  assert(nargs <= XtNumber(args));
  XtSetValues(w, args, nargs);
  
  if (freetemp) 
    XmStringFree(temp);
}

/*ARGSUSED*/
static int
LabelPreferredValue(Widget w)	/* unused */
{
  return XmFORMAT_XmSTRING;
}

static char*
GetLabelAccelerator(Widget w)
{
  if (XtClass(w) == xmLabelWidgetClass)
    return NULL;
  else
    return Lab_Accelerator(w);
}

static KeySym 
GetLabelMnemonic(Widget w)
{
  if (XtClass(w) == xmLabelWidgetClass)
    return XK_VoidSymbol;
  else
    return Lab_Mnemonic(w);
}

