/*
 * 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
 * 
 */
/*
 * COPYRIGHT NOTICE
 * Copyright (c) 1995 Integrated Computer Solutions
 */
/*
 * SYMBOLS
 * =======
 *
 * DEMO             - Controls if this is a demo version or not
 * SCROLLED_LAYOUT  - Controls if the scrolled layout features are supported
 * OVERLAYED_LAYOUT - Controls if the overlayed layout is supported
 *
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>
#include "XmI.h"
#include <Xm/TabBoxP.h>
#ifdef SCROLLED_LAYOUT
#include <Xm/ArrowB.h>
#endif
#include <Xm/PrimitiveP.h>
#include <Xm/TabStackP.h>
#include <Xm/DrawUtils.h>
#include <Xm/XmP.h>

#define FIX_1503

#ifdef USE_XFT
#include <X11/Xft/Xft.h>
#endif

#define _XiBoolean Boolean

typedef enum {XiQUAD_1, XiQUAD_2, XiQUAD_3, XiQUAD_4} XiQuadrant;
#ifdef FIX_1381
typedef enum {normal, insensitive, shadow} GC_type;
#endif

typedef struct _XmTabRect {
    int    x, y;
    int    width, height;
    int    row, column;
} XiTabRect;

typedef struct _XmCache {
    XImage *pixmap;
    XImage *label;
    Boolean sensitive;
} XiCache;

#ifdef _ARGS
#undef _ARGS
#endif
#ifndef _NO_PROTO
#define _ARGS(a) a
#else
#define _ARGS(a) ()
#endif

extern XmTabAttributes _XmTabbedStackListGet _ARGS((XmTabbedStackList, int));
extern XmTabAttributes _XmTabbedStackListArray _ARGS((XmTabbedStackList));
extern int             _XmTabbedStackListCount _ARGS((XmTabbedStackList));


#ifndef _NO_PROTO
static void ClassInitialize (void);
static void ClassPartInitialize(WidgetClass w_class);
static void TabCanvasClassInitialize (void);
#else
static void ClassPartInitialize();
static void ClassInitialize ();
static void TabCanvasClassInitialize ();
#endif
static void Initialize _ARGS((Widget, Widget, ArgList, Cardinal*));
static void Destroy _ARGS((Widget));
static void Resize _ARGS((Widget));
static Boolean SetValues _ARGS((Widget, Widget, Widget, ArgList, Cardinal*));
static XtGeometryResult QueryGeometry _ARGS((Widget, XtWidgetGeometry*,
					     XtWidgetGeometry*));

static void Realize _ARGS((Widget, XtValueMask*, XSetWindowAttributes*));

static void BorderHighlight _ARGS((Widget));
static void BorderUnhighlight _ARGS((Widget));

static void XmTabBoxArmAndActivate _ARGS((Widget, XEvent*, String*,Cardinal*));

static void _XmTabBoxTraverseRight _ARGS((Widget, XEvent*, String*,Cardinal*));
static void _XmTabBoxTraverseLeft _ARGS((Widget, XEvent*, String*, Cardinal*));
static void _XmTabBoxTraverseUp _ARGS((Widget, XEvent*, String*, Cardinal*));
static void _XmTabBoxTraverseDown _ARGS((Widget, XEvent*, String*, Cardinal*));

static void XmTabBoxArmTab _ARGS((Widget, XEvent*, String*, Cardinal*));
static void XmTabBoxSelectTab _ARGS((Widget, XEvent*, String*, Cardinal*));
static void XmTabBoxTraverseRight _ARGS((Widget, XEvent*, String*, Cardinal*));
static void XmTabBoxTraverseLeft _ARGS((Widget, XEvent*, String*, Cardinal*));
static void XmTabBoxTraverseUp _ARGS((Widget, XEvent*, String*, Cardinal*));
static void XmTabBoxTraverseDown _ARGS((Widget, XEvent*, String*, Cardinal*));
static void XmTabBoxTraversePrevious _ARGS((Widget, XEvent*, String*,
					    Cardinal*));
static void XmTabBoxTraverseNext _ARGS((Widget, XEvent*, String*, Cardinal*));

static void CalcTabSize _ARGS((XmTabBoxWidget, XmTabAttributes,
			       XmTabOrientation, XmFontList, int, int, int,
			       int, int, int, Dimension*, Dimension*));

static void CalcStackedGeometry _ARGS((XmTabBoxWidget, XRectangle*));
static void HorizontalStackedLayout _ARGS((XmTabBoxWidget, _XiBoolean));
static void HorizontalStackedRedisplay _ARGS((XmTabBoxWidget));
static void VerticalStackedRedisplay _ARGS((XmTabBoxWidget));
static void VerticalStackedLayout _ARGS((XmTabBoxWidget, _XiBoolean));

static void CalcUnlimitedGeometry _ARGS((XmTabBoxWidget, XRectangle*));
static void CalcGeometry _ARGS((XmTabBoxWidget, XRectangle*));

static void HorizontalBasicLayout _ARGS((XmTabBoxWidget));
static void VerticalBasicLayout _ARGS((XmTabBoxWidget));
static void Layout _ARGS((XmTabBoxWidget));
static void Redisplay _ARGS((Widget, XEvent*, Region));
static void RedisplayTabs _ARGS((XmTabBoxWidget, Region));

static void DrawTab _ARGS((XmTabBoxWidget, XmTabAttributes, XiTabRect*,
			   _XiBoolean, _XiBoolean));

static Boolean CvtStringToTabOrientation _ARGS((Display*, XrmValue*, Cardinal*,
						XrmValue*, XrmValue*,
						XtPointer*));
static Boolean CvtStringToTabSide _ARGS((Display*, XrmValue*, Cardinal*,
					 XrmValue*, XrmValue*,
					 XtPointer*));
static Boolean CvtStringToTabStyle _ARGS((Display*, XrmValue*, Cardinal*,
					  XrmValue*, XrmValue*, XtPointer*));
static Boolean CvtStringToTabMode _ARGS((Display*, XrmValue*, Cardinal*,
					 XrmValue*, XrmValue*, XtPointer*));
static Boolean CvtStringToTabEdge _ARGS((Display*, XrmValue*, Cardinal*,
					 XrmValue*, XrmValue*, XtPointer*));

#ifdef SCROLLED_LAYOUT
static Boolean CvtStringToArrowPlacement _ARGS((Display*, XrmValue*, Cardinal*,
						XrmValue*, XrmValue*,
						XtPointer*));
#endif
static Boolean CvtStringToTabList _ARGS((Display*, XrmValue*, Cardinal*,
					 XrmValue*, XrmValue*, XtPointer*));
static void CvtDestroyTabList _ARGS((XtAppContext, XrmValue*, XtPointer,
				     XrmValue*, Cardinal*));

static void XiDrawCorner _ARGS((Display*, Drawable, GC, GC, int, int,
				unsigned int, unsigned int, unsigned int,
				XiQuadrant));


static void HorizontalBasicRedisplay _ARGS((XmTabBoxWidget));
static void VerticalBasicRedisplay _ARGS((XmTabBoxWidget));

static XImage *XiRotateImage _ARGS((XmTabBoxWidget, XImage*, int));

static void CalcCornerSize _ARGS((XmTabBoxWidget));
static int XiXYtoTab _ARGS((XmTabBoxWidget, int, int));

static void CalcTabGeometry _ARGS((XmTabBoxWidget));
static int CalcGeometryMinor _ARGS((XmTabBoxWidget, int));
static int CalcGeometryMajor _ARGS((XmTabBoxWidget, int));

static void CallCallbacks _ARGS((XmTabBoxWidget, XEvent*, int, int));

#ifdef FIX_1381
static void SetRightGC(XmTabBoxWidget tab, GC gc, GC_type);
#endif
static void DrawVerticalTab _ARGS((XmTabBoxWidget, XmTabAttributes, GC,
				   _XiBoolean, int, int, int, _XiBoolean, int,
				   int, XRectangle*, _XiBoolean, _XiBoolean));
static void DrawLeftToRightTab _ARGS((XmTabBoxWidget, XmTabAttributes, GC,
				      _XiBoolean, int, int, int, _XiBoolean,
				      int, int, XRectangle*));
static void DrawRightToLeftTab _ARGS((XmTabBoxWidget, XmTabAttributes, GC,
				      _XiBoolean, int, int, int, _XiBoolean,
				      int, int, XRectangle*, _XiBoolean));
static void DrawTopToBottomTab _ARGS((XmTabBoxWidget, XmTabAttributes, GC,
				      _XiBoolean, int, int, int, _XiBoolean,
				      int, int, XRectangle*, _XiBoolean));
static void DrawBottomToTopTab _ARGS((XmTabBoxWidget, XmTabAttributes, GC,
				      _XiBoolean, int, int, int, _XiBoolean,
				      int, int, XRectangle*, _XiBoolean));

static void FillRoundedTab _ARGS((XmTabBoxWidget, GC, XiTabRect*, XmTabEdge));
static void FillBeveledTab _ARGS((XmTabBoxWidget, GC, XiTabRect*, XmTabEdge));

static XmTabAttributes GetTabInfo _ARGS((XmTabBoxWidget, int, int));
static int GetTabIndex _ARGS((XmTabBoxWidget, int, int));
static void SelectTab _ARGS((XmTabBoxWidget, XEvent*, int, int));
static Boolean IsTabSensitive _ARGS((XmTabBoxWidget, int));
static Widget XiGCParent _ARGS((XmTabBoxWidget));

static void ResetImageCache _ARGS((XmTabBoxWidget));
static void FreeImageCache _ARGS((XmTabBoxWidget));
static int InfoToIndex _ARGS((XmTabBoxWidget, XmTabAttributes));

static Visual* GetShellVisual _ARGS((Widget));

static void CheckSetRenderTable(Widget wid, int offs, XrmValue *value); 

#define CachePixmap(t,i) XmTabBox__cache((t))[InfoToIndex(t,i)].pixmap
#define CacheLabel(t,i)  XmTabBox__cache((t))[InfoToIndex(t,i)].label
#define CacheSensitive(t,i)  XmTabBox__cache((t))[InfoToIndex(t,i)].sensitive

#ifndef AssignMax
#define AssignMax(x,y) if((y)>(x)) (x)=(y); else
#endif
#ifndef AssignMin
#define AssignMin(x,y) if((y)<(x)) (x)=(y); else
#endif
#ifndef Max
#define Max(x,y) (((x)>(y))?(x):(y))
#endif

#define XiRectInRegion(r,x,y,w,h) ((r) == False ? RectangleIn : \
				   XRectInRegion(r,x,y,w,h))
#define XiCanvas(x) (XtWindow(XmTabBox__canvas((x))))
#define XiTabParent(x) ((XmTabBoxWidget) XtParent(x))
#define XImageWidth(i) (i)->width
#define XImageHeight(i) (i)->height
#define XImageDepth(i) (i)->depth;
#define XiTabDegree(x) ((x) == XmTABS_RIGHT_TO_LEFT ? 180 \
			: ((x) == XmTABS_TOP_TO_BOTTOM ? 90 \
			   : ((x) == XmTABS_BOTTOM_TO_TOP ? 270 : 0)))

#define ValidPixmap(p) ((p) != (Pixmap)NULL && \
			(p) != (Pixmap)XmUNSPECIFIED_PIXMAP && \
			(p) != XmPIXMAP_DYNAMIC )
#define XiCalcTabSize(t,i,w,h) \
	CalcTabSize((t),(i), XmTabBox_tab_orientation((t)), \
		    XmTabBox_font_list((t)), (t)->manager.shadow_thickness, \
		    XmTabBox_highlight_thickness((t)), \
		    XmTabBox_tab_margin_width((t)), \
		    XmTabBox_tab_margin_height((t)), \
		    XmTabBox_tab_label_spacing((t)), \
		    XmTabBox__corner_size((t)), (w), (h))

#define SetSolidGC(d,g,p) \
{ \
      XGCValues _macro_gc_values; \
      _macro_gc_values.foreground = (p); \
      _macro_gc_values.fill_style = FillSolid; \
      XChangeGC((d),(g), GCForeground | GCFillStyle, &_macro_gc_values); \
}

#define SetTiledGC(d,g,p) \
{ \
      XGCValues _macro_gc_values; \
      _macro_gc_values.tile = (p); \
      _macro_gc_values.fill_style = FillTiled; \
      XChangeGC((d),(g), GCTile | GCFillStyle, &_macro_gc_values); \
}

#define SetTiledXYGC(d,g,p,x,y) \
{ \
      XGCValues _macro_gc_values; \
      _macro_gc_values.tile = (p); \
      _macro_gc_values.fill_style = FillTiled; \
      _macro_gc_values.ts_x_origin = (x); \
      _macro_gc_values.ts_y_origin = (y); \
      XChangeGC((d),(g), GCTile | GCFillStyle | GCTileStipXOrigin | \
		GCTileStipYOrigin, &_macro_gc_values); \
}

#define SetStippledGC(d,g,p) \
{ \
      XGCValues _macro_gc_values; \
      _macro_gc_values.stipple = (p); \
      _macro_gc_values.fill_style = FillStippled; \
      _macro_gc_values.ts_x_origin = (x); \
      _macro_gc_values.ts_y_origin = (y); \
      XChangeGC((d),(g), GCStipple | GCFillStyle | GCTileStipXOrigin | \
		GCTileStipYOrigin, &_macro_gc_values); \
}

#define SetStippledXYGC(d,g,p,x,y) \
{ \
      XGCValues _macro_gc_values; \
      _macro_gc_values.stipple = (p); \
      _macro_gc_values.fill_style = FillStippled; \
      _macro_gc_values.ts_x_origin = (x); \
      _macro_gc_values.ts_y_origin = (y); \
      XChangeGC((d),(g), GCStipple | GCFillStyle | GCTileStipXOrigin | \
		GCTileStipYOrigin, &_macro_gc_values); \
}

#define XiBackgroundSpecified(i) \
	((i)->background != XmCOLOR_DYNAMIC || \
	 ValidPixmap((i)->background_pixmap))

#define SetBackgroundGC(t,i,g) \
{ \
      if( ValidPixmap((i)->background_pixmap) ) \
      { \
	    SetTiledGC(XtDisplay(t), (g), (i)->background_pixmap); \
      } \
      else \
      { \
	    SetSolidGC(XtDisplay(t), (g), (i)->background); \
      }\
}

#define XiSelectSpecified(t) \
	(XmTabBox_select_color((t)) != XmCOLOR_DYNAMIC || \
	 ValidPixmap(XmTabBox_select_pixmap((t))))

#define SetSelectGC(t,g) \
{ \
      if( ValidPixmap(XmTabBox_select_pixmap((t))) ) \
      { \
	    SetTiledGC(XtDisplay(t), (g), XmTabBox_select_pixmap((t))); \
      } \
      else \
      { \
	    SetSolidGC(XtDisplay(t), (g), XmTabBox_select_color((t))); \
      }\
}

#define XiChildSpecified(c) \
	(XmTabStackC_tab_background(c) != XmCOLOR_DYNAMIC || \
	 ValidPixmap(XmTabStackC_tab_background_pixmap(c)))

#define RemoveStipple(d,g) XSetFillStyle((d),(g), FillSolid)

static XtActionsRec actions[] = {
    { "XmTabBoxArmAndActivate",	  (XtActionProc) XmTabBoxArmAndActivate   },
    { "XmTabBoxArmTab",           (XtActionProc) XmTabBoxArmTab           },
    { "XmTabBoxSelectTab",        (XtActionProc) XmTabBoxSelectTab        },
    { "XmTabBoxTraverseRight",    (XtActionProc) XmTabBoxTraverseRight    },
    { "XmTabBoxTraverseLeft",     (XtActionProc) XmTabBoxTraverseLeft     },
    { "XmTabBoxTraverseUp",       (XtActionProc) XmTabBoxTraverseUp       },
    { "XmTabBoxTraverseDown",     (XtActionProc) XmTabBoxTraverseDown     },
    { "XmTabBoxTraversePrevious", (XtActionProc) XmTabBoxTraversePrevious },
    { "XmTabBoxTraverseNext",     (XtActionProc) XmTabBoxTraverseNext     },
};

static char traversal_translations[] =
    "<Key>osfRight:    XmTabBoxTraverseRight()\n\
     <Key>osfLeft:     XmTabBoxTraverseLeft()\n\
     <Key>osfUp:       XmTabBoxTraverseUp()\n\
     <Key>osfDown:     XmTabBoxTraverseDown()\n\
     ~c s <Key>Tab:    PrimitivePrevTabGroup()\n\
     ~c ~s <Key>Tab:   PrimitiveNextTabGroup()\n\
     c s <Key>Tab:     PrimitivePrevTabGroup()\n\
     c ~s <Key>Tab:    PrimitiveNextTabGroup()\n\
     <Key>osfHelp:     PrimitiveHelp()\n\
     <FocusIn>:        PrimitiveFocusIn()\n\
     <FocusOut>:       PrimitiveFocusOut()\n\
     <Enter>:	       PrimitiveEnter()\n\
     <Leave>:          PrimitiveLeave()\n\
     <Unmap>:          PrimitiveUnmap()";

static char canvas_translations[] = 
    "<Btn1Down>:       XmTabBoxArmTab()\n\
     <Btn1Up>:         XmTabBoxSelectTab()\n\
     <Key>osfActivate: XmTabBoxArmAndActivate()\n\
     <Key>space:       XmTabBoxArmAndActivate()";

/* because this is a private widget for the TabStack, the resources are
** assumed already to be in pixels
*/

static XtResource resources[] =
{
  /* Inherit (but changed default) resources */
  {
    XmNshadowThickness, XmCShadowThickness, XmRDimension,
    sizeof(Dimension), XtOffsetOf(XmManagerRec, manager.shadow_thickness),
    XmRImmediate, (XtPointer) 2
  },

  /* TabBox Resources */
  {
    XmNtabStyle, XmCTabStyle, XmRTabStyle,
    sizeof(XmTabStyle), XtOffsetOf(XmTabBoxRec, tab_box.tab_style),
    XmRImmediate, (XtPointer) XmTABS_BEVELED
  },

  {
    XmNtabMode, XmCTabMode, XmRTabMode,
    sizeof(XmTabMode), XtOffsetOf(XmTabBoxRec, tab_box.tab_mode),
    XmRImmediate, (XtPointer) XmTABS_BASIC
  },

  {
    XmNtabList, XmCTabList, XmRTabList,
    sizeof(XmTabbedStackList), XtOffsetOf(XmTabBoxRec, tab_box.tab_list),
    XmRImmediate, (XtPointer) NULL
  },

  {
    XmNtabOrientation, XmCTabOrientation, XmRTabOrientation,
    sizeof(XmTabOrientation), XtOffsetOf(XmTabBoxRec, tab_box.tab_orientation),
    XmRImmediate, (XtPointer) XmTABS_LEFT_TO_RIGHT
  },

  {
    XmNtabAutoSelect, XmCTabAutoSelect, XmRBoolean,
    sizeof(Boolean), XtOffsetOf(XmTabBoxRec, tab_box.tab_auto_select),
    XmRImmediate, (XtPointer) True
  },

  {
    XmNorientation, XmCOrientation, XmROrientation,
    sizeof(unsigned char), XtOffsetOf(XmTabBoxRec, tab_box.orientation),
    XmRImmediate, (XtPointer) XmHORIZONTAL
  },

  {
      XmNuniformTabSize, XmCUniformTabSize, XmRBoolean,
      sizeof(Boolean), XtOffsetOf(XmTabBoxRec, tab_box.uniform_tab_size),
      XmRImmediate, (XtPointer) True
  },

  {
    XmNtabSelectColor, XmCTabSelectColor, XmRXmPixel,
    sizeof(Pixel), XtOffsetOf(XmTabBoxRec, tab_box.select_color),
    XmRImmediate, (XtPointer) XmCOLOR_DYNAMIC
  },

  {
    XmNtabSelectPixmap, XmCTabSelectPixmap, XmRXmPixmap,
    sizeof(Pixel), XtOffsetOf(XmTabBoxRec, tab_box.select_pixmap),
    XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
  },

  {
    XmNtabMarginWidth, XmCMarginWidth, XmRDimension,
    sizeof(Dimension), XtOffsetOf(XmTabBoxRec, tab_box.tab_margin_width),
    XmRImmediate, (XtPointer) 2
  },

  {
    XmNtabMarginHeight, XmCMarginHeight, XmRDimension,
    sizeof(Dimension), XtOffsetOf(XmTabBoxRec, tab_box.tab_margin_height),
    XmRImmediate, (XtPointer) 2
  },

  {
      XmNtabLabelSpacing, XmCTabLabelSpacing, XmRDimension,
      sizeof(Dimension), XtOffsetOf(XmTabBoxRec, tab_box.tab_label_spacing),
      XmRImmediate, (XtPointer) 2
  },

  {
    XmNtabCornerPercent, XmCTabCornerPercent, XmRInt,
    sizeof(int), XtOffsetOf(XmTabBoxRec, tab_box.tab_corner_percent),
    XmRImmediate, (XtPointer) 40
  },

  {
      XmNnumStacks, XmCNumStacks, XmRInt,
      sizeof(int), XtOffsetOf(XmTabBoxRec, tab_box.num_stacks),
      XmRImmediate, (XtPointer) 5
  },
#ifdef SCROLLED_LAYOUT
  {
    XmNtabArrowPlacement, XmCTabArrowPlacement, XmRTabArrowPlacement,
    sizeof(int), XtOffsetOf(XmTabBoxRec, tab_box.arrow_placement),
    XmRImmediate, (XtPointer) XmTAB_ARROWS_ON_LEFT
  },
#endif
  {
    XmNtabEdge, XmCTabEdge, XmRTabEdge,
    sizeof(XmTabEdge), XtOffsetOf(XmTabBoxRec, tab_box.tab_edge),
    XmRImmediate, (XtPointer) XmTAB_EDGE_BOTTOM_RIGHT
  },

  {
    XmNtabOffset, XmCTabOffset, XmRDimension,
    sizeof(Dimension), XtOffsetOf(XmTabBoxRec, tab_box.tab_offset),
    XmRImmediate, (XtPointer) 10
  },

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

  {
    XmNfontList, XmCFontList, XmRFontList,
    sizeof(XmFontList), XtOffsetOf(XmTabBoxRec, tab_box.font_list),
    XmRCallProc, (XtPointer) CheckSetRenderTable
  },

  {
    XmNrenderTable, XmCRenderTable, XmRRenderTable,
    sizeof(XmRenderTable), XtOffsetOf(XmTabBoxRec, tab_box.font_list),
    XmRCallProc, (XtPointer) CheckSetRenderTable
  },

  {
    XmNhighlightThickness, XmCHighlightThickness, XmRDimension,
    sizeof(Dimension), XtOffsetOf(XmTabBoxRec, tab_box.highlight_thickness),
     XmRImmediate, (XtPointer) 2
  },

  {
    XmNstackedEffect, XmCStackedEffect, XmRBoolean,
    sizeof(Boolean), XtOffsetOf(XmTabBoxRec, tab_box.stacked_effect),
    XmRImmediate, (XtPointer) True
  },

  {
    XmNuseImageCache, XmCUseImageCache, XmRBoolean,
    sizeof(Boolean), XtOffsetOf(XmTabBoxRec, tab_box.use_image_cache),
    XmRImmediate, (XtPointer) True
  },
 
  {
    XmNselectedIndex, XmCSelectedIndex, XmRInt,
    sizeof(int), XtOffsetOf(XmTabBoxRec, tab_box.selected_index),
    XmRImmediate, (XtPointer) -1
  },
  
  {
    XmNtraversalIndex, XmCTraversalIndex, XmRInt,
    sizeof(int), XtOffsetOf(XmTabBoxRec, tab_box.traversal_index),
    XmRImmediate, (XtPointer) -1
  },

  {
    XmNselectCallback, XmCCallback, XmRCallback,
    sizeof(XtCallbackList), XtOffsetOf(XmTabBoxRec, tab_box.select_callback),
    XmRImmediate, (XtPointer) NULL
  },

  {
    XmNunselectCallback, XmCCallback, XmRCallback,
    sizeof(XtCallbackList), XtOffsetOf(XmTabBoxRec, tab_box.unselect_callback),
    XmRImmediate, (XtPointer) NULL
  }
};

typedef struct _XiTabCanvasClassPart {
    XtPointer extension;
} XiTabCanvasClassPart;

typedef struct _XiTabCanvasClassRec {
    CoreClassPart        core_class;
    XmPrimitiveClassPart primitive_class;
    XiTabCanvasClassPart canvas_class;
} XiTabCanvasClassRec;

typedef struct _XiTabCanvasPart {
    XtPointer extension;
} XiTabCanvasPart;

typedef struct _XiTabCanvasRec {
    CorePart        core;
    XmPrimitivePart primitive;
    XiTabCanvasPart canvas;
} XiTabCanvasRec;

XiTabCanvasClassRec xmTabCanvasClassRec = {
  { /* Core Fields */
    /* superclass	  */	(WidgetClass) &xmPrimitiveClassRec,
    /* class_name	  */	"XiTabCanvas",
    /* widget_size	  */	sizeof(XiTabCanvasRec),
    /* class_initialize   */    TabCanvasClassInitialize,
    /* chained class init */	ClassPartInitialize,
    /* class_inited       */	False,
    /* initialize	  */	NULL,
    /* initialize hook    */    NULL,
    /* realize		  */	XtInheritRealize,
    /* actions		  */	NULL,
    /* num_actions	  */	0,
    /* resources	  */	NULL,
    /* num_resources	  */	0,
    /* xrm_class	  */	NULLQUARK,
    /* compress_motion	  */	True,
    /* compress_exposure  */	XtExposeCompressMultiple,  
    /* compress enter/exit*/    True,
    /* visible_interest	  */	False,
    /* destroy		  */	NULL,
    /* resize		  */	NULL,
    /* expose		  */	Redisplay,
    /* set_values	  */	NULL,
    /* set values hook    */    NULL,
    /* set values almost  */    XtInheritSetValuesAlmost,
    /* get values hook    */    NULL,
    /* accept_focus	  */	NULL,
    /* version            */    XtVersion,
    /* callback offsetlst */    NULL,
    /* default trans      */    canvas_translations,
    /* query geo proc	  */	QueryGeometry,
    /* display accelerator*/	NULL,
    /* extension record   */    (XtPointer) NULL },
  { /* OSF/Motif Primitive Fields */
    /* border_highlight   */	BorderHighlight,
    /* border_unhighlight */	BorderUnhighlight,
    /* translations       */	traversal_translations,
    /* arm_and_activate   */	NULL,
    /* syn resources      */    NULL,
    /* num syn_resources  */	0,
    /* extension          */    NULL
  },
  { /* EPak Tab Canvas Fields */
    /* extension          */	NULL
  }
};

XmTabBoxClassRec xmTabBoxClassRec = {
  { /* Core Fields */
    /* superclass	  */	(WidgetClass) &xmManagerClassRec,
    /* class_name	  */	"XmTabBox",
    /* widget_size	  */	sizeof(XmTabBoxRec),
    /* class_initialize   */    ClassInitialize,
    /* class_part_initial */	NULL,
    /* class_inited       */	False,
    /* initialize	  */	Initialize,
    /* initialize hook    */    NULL,
    /* realize		  */	Realize,
    /* actions		  */	actions,
    /* num_actions	  */	XtNumber(actions),
    /* resources	  */	resources,
    /* num_resources	  */	XtNumber(resources),
    /* xrm_class	  */	NULLQUARK,
    /* compress_motion	  */	True,
    /* compress_exposure  */	XtExposeCompressMultiple,  
    /* compress enter/exit*/    True,
    /* visible_interest	  */	False,
    /* destroy		  */	Destroy,
    /* resize		  */	Resize,
    /* expose		  */	NULL,
    /* set_values	  */	SetValues,
    /* set values hook    */    NULL,
    /* set values almost  */    XtInheritSetValuesAlmost,
    /* get values hook    */    NULL,
    /* accept_focus	  */	NULL,
    /* version            */    XtVersion,
    /* callback offsetlst */    NULL,
    /* default trans      */    XtInheritTranslations,
    /* query geo proc	  */	QueryGeometry,
    /* display accelerator*/	NULL,
    /* extension record   */    (XtPointer) NULL },
  { /* Composite Fields */
    /* geometry_manager   */    XtInheritGeometryManager,
    /* change_managed     */    XtInheritChangeManaged,
    /* insert_child       */    XtInheritInsertChild,
    /* delete_child       */    XtInheritDeleteChild,
    /* extension          */    (XtPointer) NULL },
  { /* Constraint Fields */
    /* resources          */    NULL,
    /* num_resources      */    0,
    /* constraint_size    */    sizeof (XmManagerConstraintRec),
    /* initialize         */    NULL,
    /* destroy            */    NULL,
    /* set_values         */    NULL,
    /* extension          */    (XtPointer) NULL },
  { /* OSF/Motif Manager Fields */
    /* translations       */    XtInheritTranslations,
    /* syn_resources      */    NULL,
    /* num_syn_resources  */    0,
    /* syn_resources      */    NULL,
    /* num_syn_resources  */    0,
    /* parent_process     */    XmInheritParentProcess,
    /* extension          */    (XtPointer) NULL },
  { /* EPak Tab Box Fields */
    /* extension          */    (XtPointer) NULL }
};

WidgetClass xmTabCanvasWidgetClass = (WidgetClass) &xmTabCanvasClassRec;
WidgetClass xmTabBoxWidgetClass = (WidgetClass) &xmTabBoxClassRec;

static void
#ifndef _NO_PROTO
TabCanvasClassInitialize(void)
#else
TabCanvasClassInitialize()
#endif
{
  /* do nothing */
}

/*
 * ClassPartInitialize sets up the fast subclassing for the widget.
 */
static void 
#ifdef _NO_PROTO
ClassPartInitialize(w_class)
        WidgetClass w_class ;
#else
ClassPartInitialize(WidgetClass w_class)
#endif /* _NO_PROTO */
{
    _XmFastSubclassInit (w_class, XmTABBOX_BIT);
}



static void
#ifndef _NO_PROTO
ClassInitialize(void)
#else
ClassInitialize()
#endif
{
    XtSetTypeConverter(XmRString, XmRTabOrientation,
		       CvtStringToTabOrientation, NULL, 0, XtCacheNone, NULL);
    XtSetTypeConverter(XmRString, XmRTabStyle,
		       CvtStringToTabStyle, NULL, 0, XtCacheNone, NULL);
    XtSetTypeConverter(XmRString, XmRTabMode,
		       CvtStringToTabMode, NULL, 0, XtCacheNone, NULL);
    XtSetTypeConverter(XmRString, XmRTabEdge,
		       CvtStringToTabEdge, NULL, 0, XtCacheNone, NULL);
    XtSetTypeConverter(XmRString, XmRTabSide,
		       CvtStringToTabSide, NULL, 0, XtCacheNone, NULL);
#ifdef SCROLLED_LAYOUT
    XtSetTypeConverter(XmRString, XmRTabArrowPlacement,
		       CvtStringToArrowPlacement, NULL, 0, XtCacheNone, NULL);
#endif
    XtSetTypeConverter(XmRString, XmRTabList,
		       CvtStringToTabList, NULL, 0, XtCacheNone,
		       CvtDestroyTabList);
}

static void
#ifndef _NO_PROTO
Initialize(Widget request, Widget set, ArgList arg_list, Cardinal *arg_cnt)
#else
Initialize(request, set, arg_list, arg_cnt)
    Widget   request, set;
    ArgList  arg_list;
    Cardinal *arg_cnt;
#endif
{
    XmTabBoxWidget   st = (XmTabBoxWidget) set;
    XRectangle       want;
    ArgList          filtered_args;
    Cardinal	     num_filtered_args;

    XmTabBox__inited(st) = False;

    /*
     * Lets start by first making a copy of our TabList.  We do this so
     * that we are not sharing memory with the user.
     */
    XmTabBox_tab_list(st) = XmTabbedStackListCopy(XmTabBox_tab_list(st));

    /*
     * Now lets see if the creator set our font list and if not lets
     * grab the default.
     */
    if( XmTabBox_font_list(st) == NULL )
    {
	XmTabBox_font_list(st) = XmeGetDefaultRenderTable((Widget) st, 
						      XmLABEL_FONTLIST);
    }
    XmTabBox_font_list(st) = XmFontListCopy(XmTabBox_font_list(st));


    _XmFilterArgs(arg_list, *arg_cnt, xm_std_filter,
		  &filtered_args, &num_filtered_args);
    XmTabBox__canvas(st) =
	XtCreateManagedWidget("canvas", xmTabCanvasWidgetClass, set,
			      filtered_args, num_filtered_args);

#ifdef SCROLLED_LAYOUT
    XmTabBox__left_arrow(st) =
	XtCreateWidget("leftArrow", xmArrowButtonWidgetClass, set,
		       filtered_args, num_filtered_args);
    XmTabBox__right_arrow(st) =
	XtCreateWidget("rightArrow", xmArrowButtonWidgetClass, set,
		       filtered_args, num_filtered_args);
#endif

    XtFree((XtPointer)filtered_args);

    XmTabBox__bitmap(st) = XmUNSPECIFIED_PIXMAP;
    XmTabBox__bitmap_width(st) = XmTabBox__bitmap_height(st) = 0;
    XmTabBox__zero_GC(st) = NULL;
    XmTabBox__one_GC(st) = NULL;
    XmTabBox__tab_GC(st) = NULL;
    XmTabBox__text_GC(st) = NULL;
    XmTabBox__wanted(st) = (XRectangle*) NULL;
    XmTabBox__num_wanted(st) = 0;
    XmTabBox__actual(st) = (XiTabRect*) NULL;
    XmTabBox__num_actual(st) = 0;
    XmTabBox__scroll_x(st) = 0;
    XmTabBox__selected(st) = -1;
    XmTabBox__keyboard(st) = -1;
    XmTabBox__armed_tab(st) = -1;
    XmTabBox__num_columns(st) = 0;
    XmTabBox__num_rows(st) = 0;
    XmTabBox__gray_stipple(st) = XmGetPixmapByDepth(XtScreen(st), 
						   "50_foreground", 1, 0, 1);

    XmTabBox__cache(st) = NULL;
    XmTabBox__cache_size(st) = 0;

    CalcCornerSize(st);

    CalcGeometry(st, &want);

    if( XtWidth(request) == 0 )
    {
	set->core.width = want.width;
    }
    if( XtHeight(request) == 0 )
    {
	set->core.height = want.height;
    }

    Resize((Widget) st);

    XmTabBox__inited(st) = True;
}

static void
Realize(Widget widget, XtValueMask *value_mask,
	XSetWindowAttributes *attributes)
{
    XmTabBoxWidget   tb = (XmTabBoxWidget) widget;
    XGCValues        gcValues;
    XFontStruct      *font = NULL;
    XtGCMask         gcMask;

    XtRealizeProc realize;

    _XmProcessLock();
    realize = xmTabBoxWidgetClass->core_class.superclass->core_class.realize;
    _XmProcessUnlock();
    
    (*realize) (widget, value_mask, attributes);

    /*
     * Now lets create a GC that we will use for drawing.  We create
     * this GC as opposed to share it because we will be changing 
     * attributes of it a, what seems like, random.
     */
    XmeRenderTableGetDefaultFont(XmTabBox_font_list(tb), &font);
    gcValues.background = tb->core.background_pixel;
    gcMask = GCBackground;
    if (font) {
        gcValues.font = font->fid;
	gcMask |= GCFont;
    }
    /* CR03128 */
    XmTabBox__tab_GC(tb) = XmTabBox__text_GC(tb) = XtGetGC(widget, gcMask, &gcValues);
}

static void
#ifndef _NO_PROTO
Destroy(Widget widget)
#else
Destroy(widget)
    Widget widget;
#endif
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    XmTabbedStackListFree(XmTabBox_tab_list(tab));
    XmFontListFree(XmTabBox_font_list(tab));
    if( ValidPixmap(XmTabBox__bitmap(tab)) )
    {
	XFreePixmap(XtDisplay(tab), XmTabBox__bitmap(tab));
    }
    if( XmTabBox__zero_GC(tab) != NULL )
    {
	XFreeGC(XtDisplay(tab), XmTabBox__zero_GC(tab));
    }
    if( XmTabBox__one_GC(tab) != NULL )
    {
	XFreeGC(XtDisplay(tab), XmTabBox__one_GC(tab));
    }
    if( ValidPixmap(XmTabBox__gray_stipple(tab)) )
    {
	XmDestroyPixmap(XtScreen(tab), XmTabBox__gray_stipple(tab));
    }
    if( XmTabBox__cache(tab) != NULL )
    {
	FreeImageCache(tab);
    }
    /* CR03218 */
    if(XmTabBox__tab_GC(tab)) XtReleaseGC((Widget)tab, XmTabBox__tab_GC(tab));

    XtFree((XtPointer) XmTabBox__actual(tab));
    XtFree((XtPointer) XmTabBox__wanted(tab));
}

static void
#ifndef _NO_PROTO
Resize(Widget widget)
#else
Resize(widget)
    Widget widget;
#endif
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    Layout(tab);

    XtConfigureWidget(XmTabBox__canvas(tab), 0, 0,
		      XtWidth(tab), XtHeight(tab), 0);

    if( XtIsRealized(XmTabBox__canvas(tab)) )
    {
	XClearWindow(XtDisplay(widget), XiCanvas(tab));
	Redisplay(XmTabBox__canvas(tab), NULL, False);
    }
}

static void
#ifndef _NO_PROTO
Redisplay(Widget widget, XEvent *event, Region region)
#else
Redisplay(widget, event, region)
    Widget widget;
    XEvent *event;
    Region region;
#endif
{
    Widget           parent;
    XmTabBoxWidget   tab = (XmTabBoxWidget) XtParent(widget);
    XmTabbedStackList        list = XmTabBox_tab_list(tab);
    int              count = _XmTabbedStackListCount(list),
                     shadow = tab->manager.shadow_thickness;
    GC               gc = XmTabBox__tab_GC(tab);
    Pixel            pixel= 0 ;
    Pixmap           pixmap= 0 ;
    XGCValues gcValues; /* CR03218 begin */
    Boolean getNewGC = False;
    if(gc)
    {
      XGetGCValues(XtDisplay(widget), gc, GCBackground, &gcValues);
      if (tab->core.background_pixel != gcValues.background)
      {
        XtReleaseGC(widget, gc);
        getNewGC = True;
      }
    }
    else getNewGC = True;
    if (getNewGC)
    {
      XFontStruct *font = NULL;
      XtGCMask    gcMask;
      XmeRenderTableGetDefaultFont(XmTabBox_font_list(tab), &font);
      gcValues.background = tab->core.background_pixel;
      gcMask = GCBackground;
      if (font) {
          gcValues.font = font->fid;
	  gcMask |= GCFont;
      }
      XmTabBox__tab_GC(tab) = XmTabBox__text_GC(tab) = XtGetGC((Widget)tab, gcMask, &gcValues);
    } /* CR03218 end */
    if( XmTabBox__inited(tab) == False ) return;

    /*
     * The first thing we want to do is fill in our background with the
     * same color/pixmap our parent has.  This will give us a "see-through"
     * appearance.
     */
    parent = XtParent(tab);

    /*
     * If our parent happens to be a tab stack then we know that we
     * actually want to look at the background of its parent.
     */
    if( XmIsTabStack(parent) )
    {
	parent = XtParent(parent);
	pixmap = parent->core.background_pixmap;
	pixel = parent->core.background_pixel;

	/*
	 * If we are the grand child of a tab stack then we want to use
	 * the background color of the active child.
	 */
	if( XmIsTabStack(parent) )
	{
	    XmTabStackWidget ts = (XmTabStackWidget) parent;
	    Widget           child;
	    
	    if( (child = ts->tab_stack._active_child) != NULL &&
	        XiChildSpecified(child) )
	    {
		pixel = XmTabStackC_tab_background(child);
		if( ValidPixmap(XmTabStackC_tab_background_pixmap(child)) )
		{
		    pixmap = XmTabStackC_tab_background_pixmap(child);
		}
		else
		{
		    pixmap = XmUNSPECIFIED_PIXMAP;
		}
	    }
	}
    }
    if( ValidPixmap(pixmap) )
    {
	Widget kid;
	int    x = 0, y = 0;

	/*
	 * What we need to do here is find out the offset for the
	 * tile.  To do this we need to walk up our hierarchy until
	 * we come accross our parent.
	 */
	for( kid = widget; kid != parent; kid = XtParent(kid) )
	{
	    x += kid->core.x;
	    y += kid->core.y;
	}
	SetTiledXYGC(XtDisplay(tab), gc, pixmap, -x, -y);
    }
    else
    {
	SetSolidGC(XtDisplay(tab), gc, pixel);
    }
    /*
     * Well if we have a region then lets set our clipping region so we
     * confine our drawing to that area.
     */
    if( region != False )
    {
	XSetRegion(XtDisplay(tab), XmTabBox__tab_GC(tab), region);
	XSetRegion(XtDisplay(tab), tab->manager.bottom_shadow_GC, region);
	XSetRegion(XtDisplay(tab), tab->manager.top_shadow_GC, region);
	XSetRegion(XtDisplay(tab), tab->manager.background_GC, region);
    }
    else
    {
	XSetClipMask(XtDisplay(tab), gc, None);
	XSetClipMask(XtDisplay(tab), tab->manager.bottom_shadow_GC, None);
	XSetClipMask(XtDisplay(tab), tab->manager.top_shadow_GC, None);
	XSetClipMask(XtDisplay(tab), tab->manager.background_GC, None);
    }
    
    if( XmTabBox_tab_mode(tab) != XmTABS_STACKED &&
        XmTabBox_tab_mode(tab) != XmTABS_STACKED_STATIC )
    {
	if( event == NULL || event->xany.type != Expose )
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc, 0, 0,
			   XtWidth(widget), XtHeight(widget));
	}
	else
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc, event->xexpose.x,
			   event->xexpose.y, event->xexpose.width,
			   event->xexpose.height);
	}
    }

    /*
     * Lets check something real quick first.  If we do not have any
     * tabs then what we want to do is just draw a shadow line as an
     * edge.
     */
    if( count == 0 )
    {
	/*
	 * It seems that we have no tabs so lets draw just the shadow
	 * line with the correct GC in the correct place.
	 */
	switch( XmTabBox_tab_edge(tab) )
	{
	case XmTAB_EDGE_BOTTOM_RIGHT:
	default:
	    /*
	     * Well if appears that we need to draw the shadow line either
	     * on the bottom or the right so lets check our orientation
	     * to decide which one.
	     */
	    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	    {
		/*
		 * Here we need to draw a shadow along the bottom
		 * edge of our window and a beveled corner on the 
		 * right side.
		 */
		XFillRectangle(XtDisplay(widget), XtWindow(widget),
			       tab->manager.top_shadow_GC,
			       0, (int)XtHeight(widget) - shadow,
			       XtWidth(widget), shadow);
		XmDrawBevel(XtDisplay(widget), XtWindow(widget),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    (int)XtWidth(widget) - shadow,
			    (int)XtHeight(widget) - shadow,
			    shadow, XmBEVEL_BOTH);
	    }
	    else
	    {
		/*
		 * Here we need to draw a shadow along the right side and
		 * a beveled corner on the bottom.
		 */
		XFillRectangle(XtDisplay(widget), XtWindow(widget),
			       tab->manager.top_shadow_GC,
			       (int)XtWidth(widget) - shadow, 0,
			       shadow, XtHeight(widget));
		XmDrawBevel(XtDisplay(widget), XtWindow(widget),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    (int)XtWidth(widget) - shadow,
			    (int)XtHeight(widget) - shadow,
			    shadow, XmBEVEL_BOTH);
			     
	    }
	    break;
	case XmTAB_EDGE_TOP_LEFT:
	    /*
	     * Well if appears that we need to draw the shadow line either
	     * on the top or the left side so lets check our orientation
	     * to decide which one.
	     */
	    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	    {
		/*
		 * Here we need to draw a line across the top of our
		 * window and a corner in the left.
		 */
		XFillRectangle(XtDisplay(widget), XtWindow(widget),
			       tab->manager.bottom_shadow_GC,
			       0, 0, XtWidth(widget), shadow);
		XmDrawBevel(XtDisplay(widget), XtWindow(widget),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    0, 0, shadow, XmBEVEL_BOTH);
	    }
	    else
	    {
		/*
		 * Here we need a shadow along our windows left edge and
		 * a coner towards the top.
		 */
		XFillRectangle(XtDisplay(widget), XtWindow(widget),
			       tab->manager.bottom_shadow_GC,
			       0, 0, shadow, XtHeight(widget));
		XmDrawBevel(XtDisplay(widget), XtWindow(widget),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    0, 0, shadow, XmBEVEL_BOTH);
	    }
	    break;
	}

	if( region != False )
	{
	    XSetClipMask(XtDisplay(tab), XmTabBox__tab_GC(tab), None);
	    XSetClipMask(XtDisplay(tab), tab->manager.bottom_shadow_GC, None);
	    XSetClipMask(XtDisplay(tab), tab->manager.top_shadow_GC, None);
	    XSetClipMask(XtDisplay(tab), tab->manager.background_GC, None);
	}
	return;
    }

    /*
     * Well if we have a region then lets set our clipping region so we
     * confine our drawing to that area.
     */
    if( region != False )
    {
	XSetRegion(XtDisplay(tab), XmTabBox__tab_GC(tab), region);
	XSetRegion(XtDisplay(tab), tab->manager.bottom_shadow_GC, region);
	XSetRegion(XtDisplay(tab), tab->manager.top_shadow_GC, region);
	XSetRegion(XtDisplay(tab), tab->manager.background_GC, region);
    }

    /*
     * Call this handy dandy tab redisplay routine. This is kindof the
     * equivalent to XmRedisplayGadgets.
     */
    RedisplayTabs(tab, region);

    /*
     * Now lets do the orientation/mode dependant redisplay part.
     */
    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
    {
	switch( XmTabBox_tab_mode(tab) )
	{
	case XmTABS_BASIC:
	    HorizontalBasicRedisplay(tab);
	    break;
	case XmTABS_STACKED:
	case XmTABS_STACKED_STATIC:
	    HorizontalStackedRedisplay(tab);
	    break;
	case XmTABS_OVERLAYED:
	    break;
	case XmTABS_SCROLLED:
	    break;
	}
    }
    else
    {
	switch( XmTabBox_tab_mode(tab) )
	{
	case XmTABS_BASIC:
	    VerticalBasicRedisplay(tab);
	    break;
	case XmTABS_STACKED:
	case XmTABS_STACKED_STATIC:
	    VerticalStackedRedisplay(tab);
	    break;
	case XmTABS_OVERLAYED:
	    break;
	case XmTABS_SCROLLED:
	    break;
	}
    }

    /*
     * If we set a clipping are, be sure to unset it since we are probably
     * using shared GCs.
     */
    if( region != False )
    {
	XSetClipMask(XtDisplay(tab), XmTabBox__tab_GC(tab), None);
	XSetClipMask(XtDisplay(tab), tab->manager.bottom_shadow_GC, None);
	XSetClipMask(XtDisplay(tab), tab->manager.top_shadow_GC, None);
	XSetClipMask(XtDisplay(tab), tab->manager.background_GC, None);
    }
}

#define cfield(f) XmTabBox_##f(c_tab)
#define rfield(f) XmTabBox_##f(r_tab)
#define sfield(f) XmTabBox_##f(s_tab)
static Boolean
#ifndef _NO_PROTO
SetValues(Widget current, Widget request, Widget set, ArgList arg_list, 
	  Cardinal *arg_cnt)
#else
SetValues(current, request, set, arg_list, arg_cnt)
    Widget   current, request, set;
    ArgList  arg_list;
    Cardinal *arg_cnt;
#endif
{
    XmTabBoxWidget c_tab = (XmTabBoxWidget) current,
                   s_tab = (XmTabBoxWidget) set;
        
    Boolean        need_layout = False, need_resize = False,
                   clear_cache = False;
    ArgList        filtered_args = NULL;
    Cardinal       num_filtered_args = 0;

    /*
     * First lets start by passing down our resources to our children.
     */
    if( XmTabBox__inited(s_tab) && XmTabBox__canvas(s_tab) != NULL )
    {
	_XmFilterArgs(arg_list, *arg_cnt, xm_std_filter,
		      &filtered_args, &num_filtered_args);
	XtSetValues(XmTabBox__canvas(s_tab), filtered_args, num_filtered_args);
#ifdef SCROLLED_LAYOUT
	XtSetValues(XmTabBox__left_arrow(s_tab), filtered_args,
		    num_filtered_args);
	XtSetValues(XmTabBox__right_arrow(s_tab), filtered_args,
		    num_filtered_args);
#endif
	XtFree((XtPointer)filtered_args);
    }

    if( XmTabBox_tab_list(c_tab) != XmTabBox_tab_list(s_tab) )
    {
	if( XmTabbedStackListCompare(XmTabBox_tab_list(s_tab),
			     XmTabBox_tab_list(c_tab)) == XmTAB_CMP_SIZE )
	{
	    clear_cache = True;
	    need_resize = True;
	}

	XmTabbedStackListFree(XmTabBox_tab_list(c_tab));
	XmTabBox_tab_list(c_tab) = (XmTabbedStackList) NULL;
	XmTabBox_tab_list(s_tab) = XmTabbedStackListCopy(XmTabBox_tab_list(s_tab));

	CalcTabGeometry(s_tab);
	need_layout = True;
    }

    if( sfield(_selected) > _XmTabbedStackListCount(sfield(tab_list)) )
    {
	sfield(_selected) = -1;
	if( _XmTabbedStackListCount(sfield(tab_list)) > 0 )
	{
	    sfield(_selected) = 0;
	}
	need_layout = True;
    }

    if( sfield(_keyboard) > _XmTabbedStackListCount(sfield(tab_list)) )
    {
	sfield(_keyboard) = -1;
	if( _XmTabbedStackListCount(sfield(tab_list)) > 0 )
	{
	    sfield(_keyboard) = 0;
	}
	need_layout = True;
    }

    if( sfield(selected_index) != -1 || sfield(traversal_index) != -1 )
    {
	sfield(_selected) = sfield(selected_index);
	sfield(_keyboard) = sfield(traversal_index);

	sfield(selected_index) = -1;
	sfield(traversal_index) = -1;

	need_layout = True;
    }

    if( cfield(font_list) != sfield(font_list) )
    {
	XmFontListFree(cfield(font_list));
	cfield(font_list) = (XmFontList) NULL;
	if( sfield(font_list) == NULL )
	{
	    sfield(font_list) = XmeGetDefaultRenderTable(set, XmLABEL_FONTLIST);
	}
	sfield(font_list) == XmFontListCopy(sfield(font_list));
	need_layout = True;
	need_resize = True;
    }

    if( c_tab->manager.shadow_thickness != s_tab->manager.shadow_thickness ||
        cfield(tab_style) != sfield(tab_style) ||
        cfield(tab_mode) != sfield(tab_mode) ||
        cfield(tab_orientation) != sfield(tab_orientation) ||
        cfield(orientation) != sfield(orientation) ||
        cfield(uniform_tab_size) != sfield(uniform_tab_size) ||
        cfield(tab_margin_width) != sfield(tab_margin_width) ||
        cfield(tab_margin_height) != sfield(tab_margin_height) ||
        cfield(tab_label_spacing) != sfield(tab_label_spacing) ||
        cfield(tab_corner_percent) != sfield(tab_corner_percent) ||
#ifdef SCROLLED_LAYOUT
        cfield(arrow_placement) != sfield(arrow_placement) ||
#endif
        cfield(tab_edge) != sfield(tab_edge) ||
        cfield(tab_offset) != sfield(tab_offset) ||
        cfield(highlight_thickness) != sfield(highlight_thickness) )
    {
	need_layout = True;
	need_resize = True;
    }

    if( cfield(tab_orientation) != sfield(tab_orientation) )
    {
	clear_cache = True;
    }

    if( cfield(use_image_cache) != sfield(use_image_cache) )
    {
	if( sfield(use_image_cache) )
	{
	    clear_cache = True;
	}
	else
	{
	    FreeImageCache(s_tab);
	    clear_cache = False;
	}
    }
    if( clear_cache ) ResetImageCache(s_tab);

    if( need_layout )
    {
	Resize(set);
    }

    /*
     * Now lets check to see if we are supposed to pick a new size, and
     * if we are lets find out that size.
     */
    if( need_resize )
    {
	XRectangle geom;

	CalcGeometry(s_tab, &geom);

	/*
	 * Now that we know the size that we want to be lets set the
	 * width and height for ourselves so the geometry can be
	 * passed up to our parent.  If that size is accepted we
	 * should get a resize callback.
	 */
        if( XtWidth(request) == XtWidth(current) )
	{
	    s_tab->core.width = geom.width;
	}
	if( XtHeight(request) == XtHeight(current) )
	{
	    s_tab->core.height = geom.height;
	}
    }

    return( need_layout || need_resize );
}
#undef cfield
#undef rfield
#undef sfield

static XtGeometryResult
#ifndef _NO_PROTO
QueryGeometry(Widget widget, XtWidgetGeometry *request,
	      XtWidgetGeometry *allowed)
#else
QueryGeometry(widget, request, allowed)
    Widget           widget;
    XtWidgetGeometry *request, *allowed;
#endif
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;
    XRectangle     rect;

    /*
     * Lets start with the easy case.  If they gave us nothing then
     * lets return to them the geometry that we really want.
     */
    if( request == NULL || request->request_mode == 0 )
    {
	CalcGeometry(tab, &rect);
	
	allowed->request_mode = CWWidth | CWHeight;
	allowed->width = rect.width;
	allowed->height = rect.height;

	return( XtGeometryAlmost );
    }

    /*
     * If we got here that means that they are asking us something so
     * lets see what they want.  We will first check if they are
     * inquering about something other then width and height, because
     * we only care about width and height.  If they give us something
     * else we will gladly accept it.
     */
    if( !(request->request_mode & (CWWidth | CWHeight)) )
    {
	/*
	 * Ok it appears that they only care about attributes that we
	 * do not care about so lets just return them a big YES.
	 */
	return( XtGeometryYes );
    }

    /*
     * Now comes the big work.  It appears that they gave us a partial
     * or suggested geometry and they want to know how we will react to
     * that geometry.  Since we have an orientation we will take our
     * major dimension and give that priority.
     */
    *allowed = *request;
    allowed->request_mode |= (CWWidth | CWHeight);
    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
    {
	if( request->request_mode & CWWidth )
	{
	    /*
	     * They gave us a width so lets take that width and figure
	     * out our minor dimension using that width.
	     */
	    allowed->height = CalcGeometryMinor(tab, (int)request->width);
	}
	else if( request->request_mode & CWHeight )
	{
	    /*
	     * Well it looks like they gave us the minor geometry they
	     * want us to fit into so lets calculate the major.
	     */
	    allowed->width = CalcGeometryMinor(tab, (int)request->height);
	}
    }
    else
    {
	if( request->request_mode & CWHeight )
	{
	    /*
	     * They gave us a height so lets take that height and figure
	     * out our minor dimension using that height.
	     */
	    allowed->width = CalcGeometryMinor(tab, (int)request->height);
	}
	else if( request->request_mode & CWWidth )
	{
	    /*
	     * Well it looks like they gave us the minor geometry they
	     * want us to fit into so lets calculate the major.
	     */
	    allowed->height = CalcGeometryMajor(tab, request->width);
	}
    }

    if( XmCompareXtWidgetGeometryToWidget(allowed, widget) )
    {
	return( XtGeometryNo );
    }
    if( XmCompareXtWidgetGeometry(request, allowed) ) return( XtGeometryYes );
    return( XtGeometryAlmost );
}

#define XmTAB_HIGHLIGHT_RECT 0
#define XmTAB_TEXT_RECT 1

static XRectangle*
#ifndef _NO_PROTO
GetTabRectangle(XmTabBoxWidget tab, int type, XiTabRect *draw)
#else
GetTabRectangle(tab, type, draw)
    XmTabBoxWidget tab;
    int            type;
    XiTabRect      *draw;
#endif
{
    static XRectangle rect;
    int               highlight = XmTabBox_highlight_thickness(tab),
                      shadow = tab->manager.shadow_thickness,
                      margin_height = XmTabBox_tab_margin_height(tab),
                      margin_width = XmTabBox_tab_margin_width(tab),
                      spacing = XmTabBox_tab_label_spacing(tab),
                      size, horiz, vert;

    if( draw == NULL )
    {
	if( XmTabBox__keyboard(tab) >= 0 )
	{
	    draw = &(XmTabBox__actual(tab)[XmTabBox__keyboard(tab)]);
	}
	else
	{
	    rect.x = rect.y = 0;
	    rect.width = rect.height = 0;
	}
    }

    size = XmTabBox__corner_size(tab);
    if( draw->width < draw->height )
    {
	AssignMin(size,(int)(draw->width/2));
    }
    else
    {
	AssignMin(size,(int)draw->height/2);
    }

    margin_width += shadow;
    margin_height += shadow;
    if( type == XmTAB_HIGHLIGHT_RECT )
    {
	horiz = Max(size, margin_width);
	vert = Max(size, margin_height);
    }
    else
    {
	horiz = Max(size, margin_width) + highlight + spacing;
	vert = Max(size, margin_height) + highlight + spacing;
    }

    switch( XmTabBox_tab_orientation(tab) )
    {
    case XmTABS_LEFT_TO_RIGHT:
    case XmTABS_RIGHT_TO_LEFT:
    default:
	break;
    case XmTABS_TOP_TO_BOTTOM:
    case XmTABS_BOTTOM_TO_TOP:
        {
	    int tmp = horiz;
	    horiz = vert;
	    vert = tmp;
	}
	break;
    }

    rect.x = draw->x + horiz;
    rect.y = draw->y + vert;
    rect.width = draw->width - (2 * horiz);
    rect.height = draw->height - (2 * vert);

    return( &rect );
}

static void
#ifndef _NO_PROTO
DrawBorder(XmTabBoxWidget tab, GC gc, int idx)
#else
DrawBorder(tab, gc, idx)
    XmTabBoxWidget tab;
    GC             gc;
    int            idx;
#endif
{
    int             highlight = XmTabBox_highlight_thickness(tab);
    XiTabRect       *geometry;
    XRectangle      *draw, rect[4];
    XmTabAttributes info;

    if( idx < 0 )
    {
	if( XmTabBox__keyboard(tab) < 0 ) return;
	geometry = &(XmTabBox__actual(tab)[XmTabBox__keyboard(tab)]);
	idx = XmTabBox__keyboard(tab);
    }
    else
    {
	geometry = &(XmTabBox__actual(tab)[idx]);
    }
    if( gc == tab->manager.background_GC && 
        (((info = _XmTabbedStackListGet(XmTabBox_tab_list(tab), idx)) != NULL &&
	  XiBackgroundSpecified(info)) ||
	 (idx == XmTabBox__selected(tab) && XiSelectSpecified(tab))) )
    {
	gc = XmTabBox__tab_GC(tab);

	if( idx == XmTabBox__selected(tab) && XiSelectSpecified(tab) )
	{
	    SetSelectGC(tab, gc);
	}
	else
	{
	    SetBackgroundGC(tab, info, gc);
	}
    }

    draw = GetTabRectangle(tab, XmTAB_HIGHLIGHT_RECT, geometry);

    rect[0].x = draw->x;
    rect[0].y = draw->y;
    rect[0].width = Max((int)draw->width, 1);
    rect[0].height = highlight;

    rect[1].x = rect[0].x;
    rect[1].y = rect[0].y;
    rect[1].width = highlight;
    rect[1].height = Max((int)draw->height, 1);

    rect[2].x = rect[0].x + (int)draw->width - highlight;
    rect[2].y = rect[0].y;
    rect[2].width = highlight;
    rect[2].height = Max((int)draw->height, 1);

    rect[3].x = rect[0].x;
    rect[3].y = rect[0].y + (int)draw->height - highlight;
    rect[3].width = Max((int)draw->width, 1);
    rect[3].height = highlight;

    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, 4);
}

static void
#ifndef _NO_PROTO
BorderHighlight(Widget widget)
#else
BorderHighlight(widget)
    Widget widget;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);

    DrawBorder(tab, tab->manager.highlight_GC, -1);
}

static void
#ifndef _NO_PROTO
BorderUnhighlight(Widget widget)
#else
BorderUnhighlight(widget)
    Widget widget;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);

    DrawBorder(tab, tab->manager.background_GC, -1);
}

/*
 * Function:
 *	XmTabBoxArmAndActivate(widget, event, params, num_params)
 * Description:
 *	This action is activate when keyboard traversal is used to
 *	select a tab.  This action selects the tabs and calls the
 *	unselect and select callbacks.
 * Input:
 *	widget     : Widget    - the XiTabCanvas
 *	event      : XEvent*   - unused
 *	params     : String*   - unused
 *	num_params : Cardinal* - unused
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
#ifndef _NO_PROTO
XmTabBoxArmAndActivate(Widget widget, XEvent *event, String *params,
		       Cardinal *num_params)
#else
XmTabBoxArmAndActivate(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget         tab = XiTabParent(widget);
    int                    old = XmTabBox__selected(tab),
                           idx = XmTabBox__keyboard(tab);

    SelectTab(tab, event, old, idx);
}

/* ARGSUSED */
static void
#ifndef _NO_PROTO
XmTabBoxArmTab(Widget widget, XEvent *event, String *params,
	       Cardinal *num_params)
#else
XmTabBoxArmTab(widget, event, params, num_params)
    Widget    widget;
    XEvent    *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);
    int            old, idx;

    XmProcessTraversal(widget, XmTRAVERSE_CURRENT);

    if( event == NULL || event->xany.type != ButtonPress ) return;

    idx = XmTabBox__armed_tab(tab) = XiXYtoTab(tab, event->xbutton.x,
					      event->xbutton.y);

    if( !IsTabSensitive(tab, idx) ) return;

    XmTabBox__armed_tab(tab) = idx;

    old = XmTabBox__keyboard(tab);
    if( idx != -1 && idx != old )
    {
	DrawBorder(tab, tab->manager.background_GC, old);
	DrawBorder(tab, tab->manager.highlight_GC, idx);
	XmTabBox__keyboard(tab) = idx;
    }
}

/*
 * Function:
 *	XmTabBoxSelected(widget, event, params, num_params)
 * Description:
 *	This action selects a tab and calls the select and unselect
 *	callbacks.
 * Input:
 *	widget     : Widget    - the XiTabCanvas
 *	event      : XEvent*   - the event that triggered the action
 *	params     : String*   - unused
 *	num_params : Cardinal* - unused
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
#ifndef _NO_PROTO
XmTabBoxSelectTab(Widget widget, XEvent *event, String *params,
		  Cardinal *num_params)
#else
XmTabBoxSelectTab(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget         tab = XiTabParent(widget);
    int                    idx;

    /*
     * First lets do a quick check to make sure that we have an event we
     * can deal with and that we have an armed tab.
     */
    if( event == NULL || event->xany.type != ButtonRelease ||
        XmTabBox__armed_tab(tab) == -1 ) return;

    /*
     * Lets find out which tab was activated by converting the event
     * x, y to a tab index.
     */
    idx = XiXYtoTab(tab, event->xbutton.x, event->xbutton.y);

    /*
     * First lets make sure that we are trying to select the right tab
     * we do this my making sure it is not already selected and by
     * making sure it is the currently armed tab.
     */
    if( idx == XmTabBox__selected(tab) || idx != XmTabBox__armed_tab(tab) ||
        !IsTabSensitive(tab, idx) )
    {
	XmTabBox__armed_tab(tab) = -1;
	return;
    }
    XmTabBox__armed_tab(tab) = -1;
    SelectTab(tab, event, XmTabBox__selected(tab), idx);

}

static void
#ifndef _NO_PROTO
_XmTabBoxTraverseRight(Widget widget, XEvent *event, String *params,
		       Cardinal *num_params)
#else
_XmTabBoxTraverseRight(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);
    int            old, old_selected, set, col;

    switch( XmTabBox_tab_mode(tab) )
    {
    case XmTABS_BASIC:
    case XmTABS_SCROLLED:
    case XmTABS_OVERLAYED:
    default:
	XmTabBoxTraverseNext(widget, event, params, num_params);
	return;
	break;
    case XmTABS_STACKED:
    case XmTABS_STACKED_STATIC:
	old = XmTabBox__keyboard(tab);
	col = XmTabBox__actual(tab)[old].column;
	do
	{
	    set = GetTabIndex(tab, XmTabBox__actual(tab)[old].row, ++col);
	    if( set < 0 ) return;
	} while( !IsTabSensitive(tab, set) );

	if( set < 0 || set == old ) return;

	old_selected = XmTabBox__selected(tab);

	XmTabBox__keyboard(tab) = set;
	DrawBorder(tab, tab->manager.background_GC, old);
	
	if( XmTabBox_tab_auto_select(tab) )
	{
	    SelectTab(tab, event, old_selected, set);
	}
	else
	{
	    DrawBorder(tab, tab->manager.highlight_GC, set);
	}

	break;
    }
}

/* argsused */
static void
#ifndef _NO_PROTO
XmTabBoxTraverseRight(Widget widget, XEvent *event, String *params,
		      Cardinal *num_params)
#else
XmTabBoxTraverseRight(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);

    if( XmTabBox_orientation(tab) == XmVERTICAL )
    {
	_XmTabBoxTraverseDown(widget, event, params, num_params);
    }
    else
    {
	_XmTabBoxTraverseRight(widget, event, params, num_params);
    }
}

static void
#ifndef _NO_PROTO
_XmTabBoxTraverseLeft(Widget widget, XEvent *event, String *params,
		      Cardinal *num_params)
#else
_XmTabBoxTraverseLeft(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);
    int            old, old_selected, set, col;

    switch( XmTabBox_tab_mode(tab) )
    {
    case XmTABS_BASIC:
    case XmTABS_SCROLLED:
    case XmTABS_OVERLAYED:
    default:
	XmTabBoxTraversePrevious(widget, event, params, num_params);
	return;
	break;
    case XmTABS_STACKED:
    case XmTABS_STACKED_STATIC:
	old = XmTabBox__keyboard(tab);
	col = XmTabBox__actual(tab)[old].column;
	do
	{
	    set = GetTabIndex(tab, XmTabBox__actual(tab)[old].row, --col);
	    if( set < 0 ) return;
	} while( !IsTabSensitive(tab, set) );

	if( set < 0 || set == old ) return;
	
	old_selected = XmTabBox__selected(tab);
	XmTabBox__keyboard(tab) = set;
	DrawBorder(tab, tab->manager.background_GC, old);
	
	if( XmTabBox_tab_auto_select(tab) )
	{
	    SelectTab(tab, event, old_selected, set);
	}
	else
	{
	    DrawBorder(tab, tab->manager.highlight_GC, set);
	}
	break;
    }
}

static void
#ifndef _NO_PROTO
XmTabBoxTraverseLeft(Widget widget, XEvent *event, String *params,
		     Cardinal *num_params)
#else
XmTabBoxTraverseLeft(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);

    if( XmTabBox_orientation(tab) == XmVERTICAL )
    {
	_XmTabBoxTraverseUp(widget, event, params, num_params);
    }
    else
    {
	_XmTabBoxTraverseLeft(widget, event, params, num_params);
    }
}

static void
#ifndef _NO_PROTO
_XmTabBoxTraverseUp(Widget widget, XEvent *event, String *params,
		    Cardinal *num_params)
#else
_XmTabBoxTraverseUp(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);
    int            old, old_selected, set, old_row, new_row;

    switch( XmTabBox_tab_mode(tab) )
    {
    case XmTABS_BASIC:
    case XmTABS_SCROLLED:
    case XmTABS_OVERLAYED:
    default:
	XmTabBoxTraversePrevious(widget, event, params, num_params);
	return;
	break;
    case XmTABS_STACKED:
    case XmTABS_STACKED_STATIC:
	old = XmTabBox__keyboard(tab);
	new_row = old_row = XmTabBox__actual(tab)[old].row;
	do
	{
	    if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	    {
		do
		{
		    new_row++;
		    if( XmTabBox_tab_mode(tab) == XmTABS_STACKED &&
		       XmTabBox_tab_auto_select(tab) )
		    {
			if( new_row >= XmTabBox__num_rows(tab) )
			{
			    new_row = 0;
			}
		    }
		    set = GetTabIndex(tab, new_row,
				      XmTabBox__actual(tab)[old].column);
		} while( set >= 0 && 
			!IsTabSensitive(tab, set) && new_row != old_row );
	    }
	    else
	    {
		do
		{
		    new_row--;
		    if( XmTabBox_tab_mode(tab) == XmTABS_STACKED &&
		       XmTabBox_tab_auto_select(tab) )
		    {
			if( new_row < 0 )
			{
			    new_row = XmTabBox__num_rows(tab) - 1;
			}
		    }
		    set = GetTabIndex(tab, new_row,
				      XmTabBox__actual(tab)[old].column);
		} while( set >= 0 &&
			!IsTabSensitive(tab, set) && new_row != old_row );
	    }
	    set = GetTabIndex(tab, new_row,
			      XmTabBox__actual(tab)[old].column);
	} while( new_row >= 0 && new_row < XmTabBox__num_rows(tab) &&
		set < 0 );

	if( set < 0 || set == old || new_row == old_row ) return;

	old_selected = XmTabBox__selected(tab);

	XmTabBox__keyboard(tab) = set;
	DrawBorder(tab, tab->manager.background_GC, old);
	
	if( XmTabBox_tab_auto_select(tab) )
	{
	    SelectTab(tab, event, old_selected, set);
	}
	else
	{
	    DrawBorder(tab, tab->manager.highlight_GC, set);
	}
	break;
    }
}

static void
#ifndef _NO_PROTO
XmTabBoxTraverseUp(Widget widget, XEvent *event, String *params,
		   Cardinal *num_params)
#else
XmTabBoxTraverseUp(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);

    if( XmTabBox_orientation(tab) == XmVERTICAL )
    {
	_XmTabBoxTraverseLeft(widget, event, params, num_params);
    }
    else
    {
	_XmTabBoxTraverseUp(widget, event, params, num_params);
    }
}

static void
#ifndef _NO_PROTO
_XmTabBoxTraverseDown(Widget widget, XEvent *event, String *params,
		      Cardinal *num_params)
#else
_XmTabBoxTraverseDown(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);
    int            old, old_selected, set, new_row, old_row;

    switch( XmTabBox_tab_mode(tab) )
    {
    case XmTABS_BASIC:
    case XmTABS_SCROLLED:
    case XmTABS_OVERLAYED:
    default:
	XmTabBoxTraverseNext(widget, event, params, num_params);
	return;
	break;
    case XmTABS_STACKED:
    case XmTABS_STACKED_STATIC:
	old = XmTabBox__keyboard(tab);
	new_row = old_row = XmTabBox__actual(tab)[old].row ;
	
	do
	{
	    if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	    {
		do
		{
		    new_row--;
		    if( XmTabBox_tab_mode(tab) == XmTABS_STACKED &&
		        XmTabBox_tab_auto_select(tab) )
		    {
			if( new_row < 0 )
			{
			    new_row = XmTabBox__num_rows(tab) - 1;
			}
		    }
		    set = GetTabIndex(tab, new_row,
				      XmTabBox__actual(tab)[old].column);
		} while( set >= 0 &&
			 !IsTabSensitive(tab, set) && new_row != old_row );
	    }
	    else
	    {
		do
		{
		    new_row++;
		    if( XmTabBox_tab_mode(tab) == XmTABS_STACKED &&
		        XmTabBox_tab_auto_select(tab) )
		    {
			if( new_row >= XmTabBox__num_rows(tab) )
			{
			    new_row = 0;
			}
		    }
		    set = GetTabIndex(tab, new_row,
				      XmTabBox__actual(tab)[old].column);
		} while( set >= 0 && 
			 !IsTabSensitive(tab, set) && new_row != old_row );
	    }
	    set = GetTabIndex(tab, new_row, XmTabBox__actual(tab)[old].column);
	} while( new_row >= 0 && new_row < XmTabBox__num_rows(tab) && set < 0 );

	if( set < 0 || set == old || new_row == old_row ) return;

	old_selected = XmTabBox__selected(tab);

	XmTabBox__keyboard(tab) = set;
	DrawBorder(tab, tab->manager.background_GC, old);
	
	if( XmTabBox_tab_auto_select(tab) )
	{
	    SelectTab(tab, event, old_selected, set);
	}
	else
	{
	    DrawBorder(tab, tab->manager.highlight_GC, set);
	}
	break;
    }
}

static void
#ifndef _NO_PROTO
XmTabBoxTraverseDown(Widget widget, XEvent *event, String *params,
		     Cardinal *num_params)
#else
XmTabBoxTraverseDown(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);

    if( XmTabBox_orientation(tab) == XmVERTICAL )
    {
	_XmTabBoxTraverseRight(widget, event, params, num_params);
    }
    else
    {
	_XmTabBoxTraverseDown(widget, event, params, num_params);
    }
}

/* ARGSUSED */
static void
#ifndef _NO_PROTO
XmTabBoxTraversePrevious(Widget widget, XEvent *event, String *params,
			 Cardinal *num_params)
#else
XmTabBoxTraversePrevious(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);
    int            cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab)), idx, old, tmp,
                   old_selected;

    if( cnt == 0 ) return;
    
    old = XmTabBox__keyboard(tab);
    old_selected = XmTabBox__selected(tab);

    idx = old;
    if( XmTabBox_tab_mode(tab) == XmTABS_STACKED ||
        XmTabBox_tab_mode(tab) == XmTABS_STACKED_STATIC )
    {
	do {
	    tmp = idx;
	    idx = tmp - 1;
	    if( idx < 0 ) idx = cnt - 1;
	    if( idx == tmp ) return;

	    if( XmTabBox_tab_mode(tab) == XmTABS_STACKED ||
	       XmTabBox_tab_mode(tab) == XmTABS_STACKED_STATIC )
	    {
		if( XmTabBox__actual(tab)[idx].row !=
		    XmTabBox__actual(tab)[tmp].row &&
		    XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
		{
		    int row = XmTabBox__actual(tab)[tmp].row + 1, col;
		    if ( row >= XmTabBox__num_rows(tab) ) row = 0;
		    for( col = XmTabBox__num_columns(tab) - 1;
			col > 0 && (idx = GetTabIndex(tab, row, col)) < 0;
			--col );
		}
	    }
	} while( !IsTabSensitive(tab, idx) && idx != old );
    }
    else
    {
	do {
	    idx = idx - 1;
	    if( idx < 0 ) idx = cnt - 1;
	} while( !IsTabSensitive(tab, idx) && idx != old );
    }

    if( idx < 0 || idx == old ) return;

    DrawBorder(tab, tab->manager.background_GC, old);

    XmTabBox__keyboard(tab) = idx;
    if( XmTabBox_tab_auto_select(tab) )
    {
	SelectTab(tab, event, old_selected, idx);
    }
    else
    {
	DrawBorder(tab, tab->manager.highlight_GC, idx);
    }
}

/* ARGSUSED */
static void
#ifndef _NO_PROTO
XmTabBoxTraverseNext(Widget widget, XEvent *event, String *params,
		     Cardinal *num_params)
#else
XmTabBoxTraverseNext(widget, event, params, num_params)
    Widget   widget;
    XEvent   *event;
    String   *params;
    Cardinal *num_params;
#endif
{
    XmTabBoxWidget tab = XiTabParent(widget);
    int            cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab)), idx, old, tmp,
                   old_selected;

    if( cnt == 0 ) return;

    old = XmTabBox__keyboard(tab);
    old_selected = XmTabBox__selected(tab);

    idx = old;
    if( XmTabBox_tab_mode(tab) == XmTABS_STACKED ||
        XmTabBox_tab_mode(tab) == XmTABS_STACKED_STATIC )
    {
	do {
	    tmp = idx;
	    idx = (idx + 1) % cnt;
	    if( XmTabBox__actual(tab)[idx].row !=
	        XmTabBox__actual(tab)[tmp].row &&
	        XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	    {
		int row = XmTabBox__actual(tab)[tmp].row - 1;
		if( row < 0 ) row = XmTabBox__num_rows(tab) - 1;
		idx = GetTabIndex(tab, row, 0);
	    }
	} while( !IsTabSensitive(tab, idx) && idx != old );
    }
    else
    {
	do {
	    idx = (idx + 1) % cnt;
	} while( !IsTabSensitive(tab, idx) && idx != old );
    }

    if( idx < 0 || idx == old ) return;

    DrawBorder(tab, tab->manager.background_GC, old);
    XmTabBox__keyboard(tab) = idx;

    if( XmTabBox_tab_auto_select(tab) )
    {
	SelectTab(tab, event, old_selected, idx);
    }
    else
    {
	DrawBorder(tab, tab->manager.highlight_GC, idx);
    }
}

static void
#ifndef _NO_PROTO
CalcTabSize(XmTabBoxWidget tab, XmTabAttributes info,
	    XmTabOrientation orientation, XmFontList font_list,
	    int shadow_thickness, int highlight_thickness,
	    int margin_width, int margin_height,
	    int spacing, int corner_size,
	    Dimension *width, Dimension *height)
#else
CalcTabSize(tab, info, orientation, font_list, shadow_thickness,
	    highlight_thickness, margin_width, margin_height, spacing,
	    corner_size, width, height)
    XmTabBoxWidget   tab;
    XmTabAttributes  info;
    XmTabOrientation orientation;
    XmFontList       font_list;
    int              shadow_thickness, highlight_thickness, margin_width,
	             margin_height, spacing, corner_size;
    Dimension        *width, *height;
#endif
{
    Boolean   have_label = False, have_pixmap = False;
    Dimension _width = 0, _height = 0;

    /*
     * First lets take the quick out if we were not given a valid
     * tab.
     */
    if( info == NULL )
    {
	*width = *height = 0;
	return;
    }

    /*
     * The size of a tab is determined by the combined geometry of ...
     * 
     * 		- Label (if visible)
     *		- Pixmap (if visible)
     *		- highlight border (width/height)
     *		- margins (width/height)
     *		- shadows (width/height)
     *		- corner size
     *
     */


    /*
     * Lets first see if we have a visible label string and if so lets
     * add it to the size of the tab.
     */
    if( info->label_string != NULL &&
        info->pixmap_placement != XmPIXMAP_ONLY )
    {
	Dimension string_width = 0, string_height = 0;

	/*
	 * We have a label String so lets find out its dimensions and
	 * add them to the size of the tab. 
	 */
	XmStringExtent(font_list, info->label_string,
		       &string_width, &string_height);
	
	_width += string_width;
	AssignMax(_height, string_height);
	have_label = True;
    }

    /*
     * Now lets check to see if we have to deal with a pixmap, and if
     * so lets do that.
     */
    if( ValidPixmap(info->label_pixmap) &&
        info->pixmap_placement != XmPIXMAP_NONE )
    {
	Window       window_unused;
	int          int_unused;
	unsigned int uint_unused, width_return, height_return;

	/*
	 * We have a pixmap, so lets see what the size of this pixmap
	 * is.
	 */
	XGetGeometry(XtDisplay(tab), info->label_pixmap, &window_unused,
		     &int_unused, &int_unused, &width_return, &height_return,
		     &uint_unused, &uint_unused);

	/*
	 * We will add the geometry for the pixmap to the overall geometry
	 * based on the placement of the pixmap in relation to the 
	 * label string.
	 */
	switch( info->pixmap_placement )
	{
	case XmPIXMAP_TOP:
	case XmPIXMAP_BOTTOM:
	    _height += height_return;
	    AssignMax(_width, width_return);
	    break;
	case XmPIXMAP_RIGHT:
	case XmPIXMAP_LEFT:
	case XmPIXMAP_ONLY:
	    _width += width_return;
	    AssignMax(_height, height_return);
	    break;
	case XmPIXMAP_NONE:
	default:
	    /* notreached */
	    break;
	}
	have_pixmap = True;
    }

    /*
     * If we have both a label and a pixmap we need to accomidate some
     * spacing between them so lets check if we have them and add the
     * space to the appropriate place.
     */
    if( have_label && have_pixmap )
    {
	switch( info->pixmap_placement )
	{
	case XmPIXMAP_TOP:
	case XmPIXMAP_BOTTOM:
	    _height += spacing;
	    break;
	case XmPIXMAP_LEFT:
	case XmPIXMAP_RIGHT:
	    _width += spacing;
	    break;
	case XmPIXMAP_NONE:
	case XmPIXMAP_ONLY:
	default:
	    /* notreached */
	    break;
	}
    }

    /*
     * Lets add shadow thickness to our margin, because we are going to
     * consider both of them to see if we should use them or the 
     * corner size.
     */
    margin_width += shadow_thickness;
    margin_height += shadow_thickness;

    /*
     * Now lets add room for the traversal highlight and margins
     * around the label/pixmap.
     */
    AssignMax(margin_width, corner_size);
    AssignMax(margin_height, corner_size);
    _height += 2 * (highlight_thickness + margin_height + spacing);
    _width += 2 * (highlight_thickness + margin_width + spacing);
    
    /*
     * Now lets set the result depending on the orientation of the
     * tab.
     */
    switch( orientation )
    {
    case XmTABS_TOP_TO_BOTTOM:
    case XmTABS_BOTTOM_TO_TOP:
	*width = _height;
	*height = _width;
	break;
    default:
	*width = _width;
	*height = _height;
	break;
    }
}

static void
#ifndef _NO_PROTO
CalcUnlimitedGeometry(XmTabBoxWidget tab, XRectangle *geometry)
#else
CalcUnlimitedGeometry(tab, geometry)
    XmTabBoxWidget tab;
    XRectangle     *geometry;
#endif
{
    XmTabbedStackList       list = XmTabBox_tab_list(tab);
    XmTabAttributes info;
    int             i, count = _XmTabbedStackListCount(list),
                    width, height, max_width, max_height,
                    tab_width, tab_height;
    Boolean         uniform_size;

    /*
     * Start by initializing the geometry variables.  Although we are
     * calling these things width and height the may be revered depending
     * on the orientation of this thing.
     */
    width = height = max_width = max_height = 0;

    /*
     * Now lets cashe some values so we don't have to look them up
     * or calculate them.
     */
    uniform_size = XmTabBox_uniform_tab_size(tab);

    for( i = 0; i < count; ++i )
    {
	Dimension d_width = 0, d_height = 0;
	/*
	 * First the easy part, lets grabs tab and calculate its size.
	 */
	info = _XmTabbedStackListGet(list, i);
	XiCalcTabSize(tab, info, &d_width, &d_height);
	tab_width = (int) d_width;
	tab_height = (int) d_height;

	/*
	 * Now that we know the size of this tab, we need to check what
	 * that means.  Because if we are going to a uniform look part
	 * of that geometry may be droped.
	 */
	if( uniform_size )
	{
	    /*
	     * If we are calculating for unform sized tabs then lets
	     * just capture the max width and height of all the tabs
	     * to use in calculations later.
	     */
	    AssignMax(max_width, tab_width);
	    AssignMax(max_height, tab_height);
	}
	else
	{
	    /*
	     * If we are not doing uniform tabs that means that the
	     * major dimension of the tabs can vary.
	     */
	    XmTabBox__wanted(tab)[i].width = tab_width;
	    XmTabBox__wanted(tab)[i].height = tab_height;

	    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	    {
		width += tab_width;
		AssignMax(height, tab_height);
	    }
	    else
	    {
		height += tab_height;
		AssignMax(width, tab_width);
	    }
	}
    }

    /*
     * Now the big check.  If we are dealing with uniform size tabs
     * then we want to calculate the width/height that we need based
     * on the max_width/max_height of all the tabs.
     */
    if( uniform_size )
    {
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    width = count * max_width;
	    height = max_height;
	}
	else
	{
	    height = count * max_height;
	    width = max_width;
	}

	for( i = 0; i < count; ++i )
	{
	    XmTabBox__wanted(tab)[i].width = max_width;
	    XmTabBox__wanted(tab)[i].height = max_height;
	}
    }

    geometry->width = width;
    geometry->height = height;
}

/*
 * Function:
 *	CalcGeometry(tab, geometry)
 * Description:
 *	Calculates the desired geometry given no size constraints.
 * Input:
 *	tab      : XmTabBoxWidget - the tab box to work with
 *	geometry : XRectangle*    - returns the desired geometry
 * Output:
 *	None.
 */
static void
#ifndef _NO_PROTO
CalcGeometry(XmTabBoxWidget tab, XRectangle *geometry)
#else
CalcGeometry(tab, geometry)
    XmTabBoxWidget tab;
    XRectangle     *geometry;
#endif
{
    int                    count = _XmTabbedStackListCount(XmTabBox_tab_list(tab));

    /*
     * Lets start with the easy case.  This is the case where we do not
     * have any tabs.  In this case our desired size is simple the 
     * room we need to draw single line shadow.
     */
    if( count == 0 )
    {
	/*
	 * We have no tabs so the size we want is twice our shadow thinkness
	 * in our major dimension and our shadow thickness in our minor
	 * dimension.
	 */
	geometry->x = geometry->y = 0;
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    geometry->width = 2 * tab->manager.shadow_thickness;
	    geometry->height = tab->manager.shadow_thickness;
	}
	else
	{
	    geometry->width = tab->manager.shadow_thickness;
	    geometry->height = 2 * tab->manager.shadow_thickness;
	}

	/*
	 * One thing before we leave.  If we have no tabs lets make
	 * sure to "zero" out the index to the tab with keyboard
	 * traversal and selected.
	 */
	XmTabBox__keyboard(tab) = -1;
	XmTabBox__selected(tab) = -1;

	/*
	 * Since this is the easy case we are done, so lets just hop
	 * out of this routine.
	 */
	return;
    }

    /*
     * The first thing we will do is calculate the size of each of the
     * tabs.  We do this via this handy dandy Tab Calculation routine.
     */
    CalcTabGeometry(tab);

    /*
     * Now lets make sure that we have a tab marked for both keyboard
     * traversal and selected.
     */
    if( XmTabBox__keyboard(tab) < 0 ) XmTabBox__keyboard(tab) = 0;
    if( XmTabBox__selected(tab) < 0 ) XmTabBox__selected(tab) = 0;

    switch( XmTabBox_tab_mode(tab) )
    {
    case XmTABS_STACKED:
    case XmTABS_STACKED_STATIC:
	CalcStackedGeometry(tab, geometry);
	break;
    case XmTABS_BASIC:
    case XmTABS_SCROLLED:
    case XmTABS_OVERLAYED:
    default:
	CalcUnlimitedGeometry(tab, geometry);
	break;
    }

    if( geometry->width == 0 ) geometry->width = 20;
    if( geometry->height == 0 ) geometry->height = 20;
	
}

static void
#ifndef _NO_PROTO
DrawSegments(XmTabBoxWidget tab, XmTabAttributes info, XiTabRect *geometry,
	     XmTabEdge edge, int corner_size, int shadow, int selected)
#else
DrawSegments(tab, info, geometry, edge, corner_size, shadow, selected)
    XmTabBoxWidget  tab;
    XmTabAttributes info;
    XiTabRect       *geometry;
    XmTabEdge       edge;
    int             corner_size, shadow, selected;
#endif
{
    int        size, cnt = 2;
    XRectangle rect[3];
    Boolean    stacked;
    GC         gc = (GC)NULL;

    stacked = (XmTabBox_tab_mode(tab) == XmTABS_STACKED ||
	       XmTabBox_tab_mode(tab) == XmTABS_STACKED_STATIC);
    /*
     * Lets set up the GC used to draw the shadow that may or may not be
     * visible depending on the selected state.
     */
    if( selected )
    {
	if( XiSelectSpecified(tab) )
	{
	    gc = XmTabBox__tab_GC(tab);
	    SetSelectGC(tab, gc);
	}
	else
	{
	    if( XiBackgroundSpecified(info) )
	    {
		gc = XmTabBox__tab_GC(tab);
		SetBackgroundGC(tab, info, gc);
	    }
	    else
	    {
		gc = tab->manager.background_GC;
	    }
	}
    }

    size = corner_size;

    switch( edge )
    {
    case XmTAB_EDGE_TOP_LEFT:
    default:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
			   tab->manager.top_shadow_GC, geometry->x,
			   geometry->y,
			   shadow, (int) geometry->height - size);

	    rect[0].x = geometry->x + geometry->width - shadow;
	    rect[0].y = geometry->y;
	    rect[0].width = shadow;
	    rect[0].height = (int) geometry->height - size;

	    rect[1].x = geometry->x + size;
	    rect[1].y = geometry->y + (int)geometry->height - shadow;
	    rect[1].width = (int)geometry->width - (2 * size);
	    rect[1].height = shadow;

	    if( !selected && geometry->row == 0 )
	    {
		if( (geometry->column == 0 && !LayoutIsRtoLP(tab)) ||
			((geometry->column == XmTabBox__num_columns(tab)-1) &&
			LayoutIsRtoLP(tab)) )
		{
		    rect[2].x = geometry->x + shadow;
		    rect[2].width = (int)geometry->width - shadow;
		}
		else
		{
		    rect[2].x = geometry->x;
		    rect[2].width = geometry->width;
		}
		rect[2].y = geometry->y;
		rect[2].height = shadow;
		cnt = 3;
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.bottom_shadow_GC, rect, cnt);

	    if( selected )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + shadow,
			       geometry->y,
			       (int)geometry->width - 2*shadow,
			       shadow);
			       
		if( geometry->row == 0 &&
			((geometry->column > 0 && !LayoutIsRtoLP(tab)) ||
			((geometry->column < XmTabBox__num_columns(tab)-1) &&
			LayoutIsRtoLP(tab))) )
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x, geometry->y, shadow,
				XmBEVEL_BOTH);
		}
	    }
	    else if(geometry->row == 0 &&
		    ((geometry->column == 0 && !LayoutIsRtoLP(tab)) ||
		    ((geometry->column == XmTabBox__num_columns(tab)-1) &&
		    LayoutIsRtoLP(tab))) )
	    {
		XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    geometry->x, geometry->y, shadow,
			    XmBEVEL_BOTH);
	    }
	}
	else
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			   tab->manager.top_shadow_GC,
			   geometry->x, geometry->y,
			   (int)geometry->width - size, shadow);

	    rect[0].x = geometry->x;
	    rect[0].y = geometry->y + (int)geometry->height - shadow;
	    rect[0].width = (int)geometry->width - size;
	    rect[0].height = shadow;

	    rect[1].x = geometry->x + (int)geometry->width - shadow;
	    rect[1].y = geometry->y + size;
	    rect[1].width = shadow;
	    rect[1].height = (int)geometry->height - (2 * size);

	    if( !selected && geometry->row == 0 )
	    {
		if( geometry->column == 0 )
		{
		    rect[2].y = geometry->y + shadow;
		    rect[2].height = (int)geometry->height - shadow;
		}
		else
		{
		    rect[2].y = geometry->y;
		    rect[2].height = geometry->height;
		}
		rect[2].x = geometry->x;
		rect[2].width = shadow;
		cnt = 3;
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.bottom_shadow_GC, rect, cnt);

	    if( selected )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x, geometry->y + shadow,
			       shadow,
			       (int)geometry->height - 2*shadow);
		if( geometry->column != 0 )
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x, geometry->y, shadow,
				XmBEVEL_BOTH);
		}
	    }
	    else if( geometry->row == 0 && geometry->column == 0 )
	    {
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.top_shadow_GC,
				tab->manager.bottom_shadow_GC,
				geometry->x, geometry->y, shadow,
				XmBEVEL_BOTTOM);
	    }
	}
	break;
    case XmTAB_EDGE_BOTTOM_RIGHT:

	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			   tab->manager.bottom_shadow_GC,
			   geometry->x + (int)geometry->width - shadow,
			   geometry->y + size, shadow,
			   (int)geometry->height - size);

	    rect[0].x = geometry->x;
	    rect[0].y = geometry->y + size;
	    rect[0].width = shadow;
	    rect[0].height = (int) geometry->height - size;
	    
	    rect[1].x = geometry->x + size;
	    rect[1].y = geometry->y;
	    rect[1].width = (int)geometry->width - (2 * size);
	    rect[1].height = shadow;

	    if( !selected && geometry->row == 0 )
	    {
		rect[2].x = geometry->x;
		rect[2].y = geometry->y + (int)geometry->height - shadow;
		rect[2].width = geometry->width;
		rect[2].height = shadow;
		cnt = 3;
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC, rect, cnt);

	    if( selected )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + shadow,
			       geometry->y + (int)geometry->height - shadow,
			       (int)geometry->width - 2*shadow,
			       shadow);

		if( (!stacked && 
			(((geometry->column != XmTabBox__num_columns(tab) - 1) &&
			!LayoutIsRtoLP(tab)) ||
			(geometry->column != 0 && LayoutIsRtoLP(tab)))) ||
			(stacked && geometry->row == 0 &&
			(((geometry->column != XmTabBox__num_columns(tab) - 1) &&
			!LayoutIsRtoLP(tab)) ||
			XmTabBox__num_rows(tab) == 1 ||
			!XmTabBox_stacked_effect(tab))) )
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x + (int)geometry->width - shadow,
				geometry->y + (int)geometry->height - shadow,
				shadow, XmBEVEL_BOTTOM);
		}
	    }
	    else if( (stacked && XmTabBox_stacked_effect(tab) &&
		     XmTabBox__num_rows(tab) > 1 &&
		     geometry->row == 0 && 
		     ((geometry->column == XmTabBox__num_columns(tab) - 1 &&
		     !LayoutIsRtoLP(tab)) ||
		     (geometry->column == 0 && LayoutIsRtoLP(tab)))) ||
		     (!stacked &&
		     ((geometry->column == XmTabBox__num_columns(tab) - 1 &&
		     !LayoutIsRtoLP(tab)) ||
		     (geometry->column == 0 && LayoutIsRtoLP(tab)))))
	    {
		XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    geometry->x + (int)geometry->width - shadow,
			    geometry->y + (int)geometry->height - shadow,
			    shadow, XmBEVEL_BOTTOM);
	    }
	}
	else
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			   tab->manager.bottom_shadow_GC,
			   geometry->x + size,
			   geometry->y + (int)geometry->height - shadow,
			   (int)geometry->width - size, shadow);

	    rect[0].x = geometry->x + size;
	    rect[0].y = geometry->y;
	    rect[0].width = (int)geometry->width - size;
	    rect[0].height = shadow;
	    
	    rect[1].x = geometry->x;
	    rect[1].y = geometry->y + size;
	    rect[1].width = shadow;
	    rect[1].height = (int)geometry->height - (2 * size);

	    if( !selected && geometry->row == 0 )
	    {
		rect[2].x = geometry->x + (int)geometry->width - shadow;
		rect[2].y = geometry->y;
		rect[2].width = shadow;
		rect[2].height = geometry->height;
		cnt = 3;
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC, rect, cnt);

	    if( selected )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + (int)geometry->width - shadow,
			       geometry->y + shadow,
			       shadow,
			       (int)geometry->height - 2*shadow);

		if( !stacked ||
		    (stacked && geometry->row == 0 &&
		    (geometry->column != XmTabBox__num_columns(tab) - 1 ||
		    XmTabBox__num_rows(tab) == 1 ||
		    !XmTabBox_stacked_effect(tab))) )
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x + (int)geometry->width - shadow,
				geometry->y + (int)geometry->height - shadow,
				shadow, XmBEVEL_BOTTOM);
		}
	    }
	    else if( stacked && XmTabBox_stacked_effect(tab) &&
		     XmTabBox__num_rows(tab) > 1 &&
		     geometry->row == 0 &&
		     geometry->column == XmTabBox__num_columns(tab) - 1 )
	    {
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.top_shadow_GC,
				tab->manager.bottom_shadow_GC,
				geometry->x + (int)geometry->width - shadow,
				geometry->y + (int)geometry->height - shadow,
				shadow, XmBEVEL_BOTTOM);
	    }
	}
	break;
    }
}

static void
#ifndef _NO_PROTO
DrawSquareShadows(XmTabBoxWidget tab, XmTabAttributes info,
		  XiTabRect *geometry,
		  Boolean selected, XmTabEdge edge, Dimension shadow)
#else
DrawSquareShadows(tab, info, geometry, selected, edge, shadow)
    XmTabBoxWidget  tab;
    XmTabAttributes info;
    XiTabRect       *geometry;
    Boolean         selected;
    XmTabEdge       edge;
    Dimension       shadow;
#endif
{
    XRectangle rt[3];
    GC         gc = (GC)NULL;
    Boolean    stacked;
    int        cnt = 2;

    stacked = (XmTabBox_tab_mode(tab) == XmTABS_STACKED ||
	       XmTabBox_tab_mode(tab) == XmTABS_STACKED_STATIC);

    /*
     * Lets set up the GC used to draw the shadow that may or may not be
     * visible depending on the selected state.
     */
    if( selected )
    {
	if( XiSelectSpecified(tab) )
	{
	    gc = XmTabBox__tab_GC(tab);
	    SetSelectGC(tab, gc);
	}
	else
	{
	    if( XiBackgroundSpecified(info) )
	    {
		gc = XmTabBox__tab_GC(tab);
		SetBackgroundGC(tab, info, gc);
	    }
	    else
	    {
		gc = tab->manager.background_GC;
	    }
	}
    }

    switch( edge )
    {
    case XmTAB_EDGE_TOP_LEFT:
    default:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			   tab->manager.top_shadow_GC,
			   geometry->x, geometry->y,
			   shadow, (int)geometry->height - shadow);
	    
	    rt[0].x = geometry->x + (int)geometry->width - shadow;
	    rt[0].y = geometry->y;
	    rt[0].width = shadow;
	    rt[0].height = geometry->height;

	    rt[1].x = geometry->x + shadow;
	    rt[1].y = geometry->y + (int) geometry->height - shadow;
	    rt[1].width = (int)geometry->width - shadow;
	    rt[1].height = shadow;

	    if( !selected && geometry->row == 0 )
	    {
		if( (geometry->column == 0 && !LayoutIsRtoL(tab)) ||
			((geometry->column == XmTabBox__num_columns(tab)-1) &&
			LayoutIsRtoLP(tab)))
		{
		    rt[2].x = geometry->x + shadow;
		    rt[2].width = (int)geometry->width - shadow;
		}
		else
		{
		    rt[2].x = geometry->x;
		    rt[2].width = geometry->width;
		}
		rt[2].y = geometry->y;
		rt[2].height = shadow;
		cnt = 3;
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.bottom_shadow_GC, rt, cnt);

	    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			tab->manager.top_shadow_GC,
			tab->manager.bottom_shadow_GC,
			geometry->x, geometry->y +
			(int)geometry->height - shadow, shadow,
			XmBEVEL_BOTH);

	    if( selected )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + shadow,
			       geometry->y,
			       (int)geometry->width - 2*shadow,
			       shadow);
			       
		if( geometry->column == 0 && geometry->column > 0 )
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x, geometry->y, shadow,
				XmBEVEL_BOTH);
		}
	    }
	    else if( geometry->row == 0 )
	    {
		if (geometry->column == 0 && !LayoutIsRtoLP(tab))
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    geometry->x, geometry->y, shadow,
			    XmBEVEL_BOTTOM);
		}
		else if (geometry->column == XmTabBox__num_columns(tab)-1 &&
		     LayoutIsRtoLP(tab))
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    geometry->x, geometry->y, shadow,
			    XmBEVEL_BOTTOM);
			    return;
		}
		
	    }
	}
	else
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			   tab->manager.top_shadow_GC,
			   geometry->x, geometry->y,
			   (int)geometry->width - shadow, shadow);

	    rt[0].x = geometry->x + (int)geometry->width - shadow;
	    rt[0].y = geometry->y + shadow;
	    rt[0].width = shadow;
	    rt[0].height = geometry->height - shadow;

	    rt[1].x = geometry->x;
	    rt[1].y = geometry->y + (int) geometry->height - shadow;
	    rt[1].width = (int)geometry->width - shadow;
	    rt[1].height = shadow;

	    if( !selected && geometry->row == 0 )
	    {
		if( geometry->column == 0 )
		{
		    rt[2].y = geometry->y + shadow;
		    rt[2].height = (int)geometry->height - shadow;
		}
		else
		{
		    rt[2].y = geometry->y;
		    rt[2].height = geometry->height;
		}
		rt[2].x = geometry->x;
		rt[2].width = shadow;
		cnt = 3;
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.bottom_shadow_GC, rt, cnt);

	    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			tab->manager.top_shadow_GC,
			tab->manager.bottom_shadow_GC,
			geometry->x + (int)geometry->width - shadow,
			geometry->y, shadow, XmBEVEL_BOTH);

	    if( selected )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x, geometry->y + shadow,
			       shadow,
			       (int)geometry->height - 2*shadow);
		if( geometry->column != 0 )
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x, geometry->y, shadow,
				XmBEVEL_BOTH);
		}
	    }
	    else if( geometry->row == 0 && geometry->column == 0 )
	    {
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.top_shadow_GC,
				tab->manager.bottom_shadow_GC,
				geometry->x, geometry->y, shadow,
				XmBEVEL_BOTTOM);
	    }
	}
		       
	break;
    case XmTAB_EDGE_BOTTOM_RIGHT:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
		XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			   tab->manager.bottom_shadow_GC, 
			   geometry->x + (int)geometry->width - shadow,
			   geometry->y,
			   shadow,
			   (int)geometry->height);

	    rt[0].x = geometry->x;
	    rt[0].y = geometry->y;
	    rt[0].width = shadow;
	    rt[0].height = geometry->height;
	    
	    rt[1].x = geometry->x;
	    rt[1].y = geometry->y;
	    rt[1].width = (int)geometry->width - shadow;
	    rt[1].height = shadow;

	    if( !selected && geometry->row == 0 )
	    {
		rt[2].x = geometry->x;
		rt[2].y = geometry->y + (int)geometry->height - shadow;
		rt[2].width = geometry->width;
		rt[2].height = shadow;
		cnt = 3;
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC, rt, cnt);

	    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			tab->manager.top_shadow_GC,
			tab->manager.bottom_shadow_GC,
			geometry->x + (int)geometry->width - shadow,
			geometry->y, shadow, XmBEVEL_TOP);

	    if( selected )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + shadow,
			       geometry->y + (int)geometry->height - shadow,
			       (int)geometry->width - 2*shadow,
			       shadow);

		if (LayoutIsRtoLP(tab))
		{
		    if (geometry->column != 0 && geometry->row == 0)
		    {
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x + (int)geometry->width - shadow,
				geometry->y + (int)geometry->height - shadow,
				shadow, XmBEVEL_BOTH);
		    }
		}
		else
		{
		    if( (!stacked &&
			((((geometry->column != XmTabBox__num_columns(tab) - 1) &&
			!LayoutIsRtoLP(tab))) ||
			(geometry->column != 0 && LayoutIsRtoLP(tab)))) ||
			(stacked && geometry->row == 0 &&
			(geometry->column != XmTabBox__num_columns(tab) - 1 ||
			(XmTabBox__num_rows(tab) == 1) ||
			!XmTabBox_stacked_effect(tab))) )
		    {
			XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x + (int)geometry->width - shadow,
				geometry->y + (int)geometry->height - shadow,
				shadow, XmBEVEL_BOTH);
		    }
		}
	    }
	    else if( (stacked && XmTabBox_stacked_effect(tab) &&
		     XmTabBox__num_rows(tab) > 1 &&
		     geometry->row == 0 && 
		     ((geometry->column == XmTabBox__num_columns(tab) - 1 &&
		     !LayoutIsRtoLP(tab)) ||
		     (geometry->column == 0 && LayoutIsRtoLP(tab)))) ||
		     (!stacked &&
		     ((geometry->column == XmTabBox__num_columns(tab) - 1 &&
		     !LayoutIsRtoLP(tab)) ||
		     (geometry->column == 0 && LayoutIsRtoLP(tab)))))
	    {
		XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC,
			    tab->manager.bottom_shadow_GC,
			    geometry->x + (int)geometry->width - shadow,
			    geometry->y + (int)geometry->height - shadow,
			    shadow, XmBEVEL_BOTTOM);
	    }
	}
	else
	{
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			   tab->manager.bottom_shadow_GC, 
			   geometry->x + shadow,
			   geometry->y + (int)geometry->height - shadow,
			   (int)geometry->width - shadow, shadow);

	    rt[0].x = geometry->x;
	    rt[0].y = geometry->y;
	    rt[0].width = shadow;
	    rt[0].height = (int)geometry->height - shadow;
	    
	    rt[1].x = geometry->x;
	    rt[1].y = geometry->y;
	    rt[1].width = geometry->width;
	    rt[1].height = shadow;

	    if( !selected && geometry->row == 0 )
	    {
		rt[2].x = geometry->x + (int)geometry->width - shadow;
		rt[2].y = geometry->y;
		rt[2].width = shadow;
		rt[2].height = geometry->height;
		cnt = 3;
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab),
			    tab->manager.top_shadow_GC, rt, cnt);

	    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
			tab->manager.top_shadow_GC,
			tab->manager.bottom_shadow_GC,
			geometry->x,
			geometry->y + (int)geometry->height - shadow,
			shadow, XmBEVEL_BOTH);

	    if( selected )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + (int)geometry->width - shadow,
			       geometry->y + shadow,
			       shadow,
			       (int)geometry->height - 2*shadow);

		if( !stacked ||
		    (stacked && geometry->row == 0 &&
		    (geometry->column != XmTabBox__num_columns(tab) - 1 ||
		    XmTabBox__num_rows(tab) == 1 ||
		    !XmTabBox_stacked_effect(tab))) )
		{
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.bottom_shadow_GC,
				tab->manager.top_shadow_GC,
				geometry->x + (int)geometry->width - shadow,
				geometry->y + (int)geometry->height - shadow,
				shadow, XmBEVEL_BOTH);
		}
	    }
	    else if( stacked && XmTabBox_stacked_effect(tab) &&
		     XmTabBox__num_rows(tab) > 1 &&
		     geometry->row == 0 &&
		     geometry->column == XmTabBox__num_columns(tab) - 1 )
	    {
		    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
				tab->manager.top_shadow_GC,
				tab->manager.bottom_shadow_GC,
				geometry->x + (int)geometry->width - shadow,
				geometry->y + (int)geometry->height - shadow,
				shadow, XmBEVEL_BOTTOM);
	    }
	}
	break;
    }
}

static void
#ifndef _NO_PROTO
DrawRoundedShadows(XmTabBoxWidget tab, XmTabAttributes info,
		   XiTabRect *geometry,
		   Boolean selected, XmTabEdge edge,
		   int shadow)
#else
DrawRoundedShadows(tab, info, geometry, selected, edge, shadow)
    XmTabBoxWidget  tab;
    XmTabAttributes info;
    XiTabRect       *geometry;
    Boolean         selected;
    XmTabEdge       edge;
    int             shadow;
#endif
{
    int    size;

    size = XmTabBox__corner_size(tab);
    if( geometry->width < geometry->height )
    {
	if( size > (int)geometry->width/2 ) size = (int)geometry->width/2;
    }
    else
    {
	if( size > (int)geometry->height/2 ) size = (int)geometry->height/2;
    }

    DrawSegments(tab, info, geometry, edge, size, shadow, selected);

    switch( edge )
    {
    case XmTAB_EDGE_TOP_LEFT:
    default:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    XiDrawCorner(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 tab->manager.bottom_shadow_GC,
			 geometry->x, geometry->y +
			 (int)geometry->height - size,
			 size, size, tab->manager.shadow_thickness,
			 XiQUAD_3);
	    XiDrawCorner(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 tab->manager.bottom_shadow_GC,
			 geometry->x + (int)geometry->width - size,
			 geometry->y + (int)geometry->height - size,
			 size, size, tab->manager.shadow_thickness,
			 XiQUAD_4);
	}
	else
	{
	    XiDrawCorner(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 tab->manager.bottom_shadow_GC,
			 geometry->x + (int)geometry->width - size,
			 geometry->y,
			 size, size, tab->manager.shadow_thickness,
			 XiQUAD_1);
	    XiDrawCorner(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 tab->manager.bottom_shadow_GC,
			 geometry->x + (int)geometry->width - size,
			 geometry->y + (int)geometry->height - size,
			 size, size, tab->manager.shadow_thickness,
			 XiQUAD_4);
	}
	break;
    case XmTAB_EDGE_BOTTOM_RIGHT:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    XiDrawCorner(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 tab->manager.bottom_shadow_GC,
			 geometry->x + (int)geometry->width - size,
			 geometry->y, size, size,
			 tab->manager.shadow_thickness, XiQUAD_1);
	    XiDrawCorner(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 tab->manager.bottom_shadow_GC,
			 geometry->x, geometry->y,
			 size, size, tab->manager.shadow_thickness,
			 XiQUAD_2);
	}
	else
	{
	    XiDrawCorner(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 tab->manager.bottom_shadow_GC,
			 geometry->x,
			 geometry->y, size, size,
			 tab->manager.shadow_thickness, XiQUAD_2);
	    XiDrawCorner(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 tab->manager.bottom_shadow_GC,
			 geometry->x,
			 geometry->y + (int)geometry->height - size,
			 size, size, tab->manager.shadow_thickness,
			 XiQUAD_3);
	}
	break;
    }
}

static void
#ifndef _NO_PROTO
DrawBeveledShadows(XmTabBoxWidget tab, XmTabAttributes info,
		   XiTabRect *geometry,
		   Boolean selected, XmTabEdge edge,
		   int shadow)
#else
DrawBeveledShadows(tab, info, geometry, selected, edge, shadow)
    XmTabBoxWidget  tab;
    XmTabAttributes info;
    XiTabRect       *geometry;
    Boolean         selected;
    XmTabEdge       edge;
    int             shadow;
#endif
{
    int    size;
    XPoint pt[4];

    size = XmTabBox__corner_size(tab);
    if( geometry->width < geometry->height )
    {
	if( size > (int)geometry->width/2 ) size = (int)geometry->width/2;
    }
    else
    {
	if( size > (int)geometry->height/2 ) size = (int)geometry->height/2;
    }

    DrawSegments(tab, info, geometry, edge, size, shadow, selected);
    
    switch( edge )
    {
    case XmTAB_EDGE_TOP_LEFT:
    default:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    pt[0].x = geometry->x;
	    pt[0].y = geometry->y + (int)geometry->height - size;
	    pt[1].x = geometry->x + size;
	    pt[1].y = geometry->y + (int)geometry->height;
	    pt[2].x = geometry->x + size;
	    pt[2].y = geometry->y + (int)geometry->height - shadow;
	    pt[3].x = geometry->x + shadow;
	    pt[3].y = geometry->y + (int)geometry->height - size;
	    XFillPolygon(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 pt, 4, Convex, CoordModeOrigin);

	    pt[0].x = geometry->x + (int)geometry->width;
	    pt[0].y = geometry->y + (int)geometry->height - size;
	    pt[1].x = geometry->x + (int)geometry->width - size;
	    pt[1].y = geometry->y + (int)geometry->height;
	    pt[2].x = geometry->x + (int)geometry->width - size;
	    pt[2].y = geometry->y + (int)geometry->height - shadow;
	    pt[3].x = geometry->x + (int)geometry->width - shadow;
	    pt[3].y = geometry->y + (int)geometry->height - size;
	    XFillPolygon(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.bottom_shadow_GC,
			 pt, 4, Convex, CoordModeOrigin);
	}
	else
	{
	    pt[0].x = geometry->x + (int)geometry->width - size;
	    pt[0].y = geometry->y;
	    pt[1].x = geometry->x + (int)geometry->width;
	    pt[1].y = geometry->y + size;
	    pt[2].x = pt[1].x - shadow;
	    pt[2].y = pt[1].y;
	    pt[3].x = pt[0].x;
	    pt[3].y = pt[0].y + shadow;
	    XFillPolygon(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.bottom_shadow_GC,
			 pt, 4, Convex, CoordModeOrigin);

	    pt[0].x = geometry->x + (int)geometry->width - size;
	    pt[0].y = geometry->y + (int)geometry->height;
	    pt[1].x = geometry->x + (int)geometry->width;
	    pt[1].y = geometry->y + (int)geometry->height - size;
	    pt[2].x = pt[1].x - shadow;
	    pt[2].y = pt[1].y;
	    pt[3].x = pt[0].x;
	    pt[3].y = pt[0].y - shadow;
	    XFillPolygon(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.bottom_shadow_GC,
			 pt, 4, Convex, CoordModeOrigin);
	}
	break;
    case XmTAB_EDGE_BOTTOM_RIGHT:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    pt[0].x = geometry->x;
	    pt[0].y = geometry->y + size;
	    pt[1].x = geometry->x + size;
	    pt[1].y = geometry->y;
	    pt[2].x = geometry->x + size;
	    pt[2].y = geometry->y + shadow;
	    pt[3].x = geometry->x + shadow;
	    pt[3].y = geometry->y + size;
	    XFillPolygon(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 pt, 4, Convex, CoordModeOrigin);

	    pt[0].x = geometry->x + (int)geometry->width;
	    pt[0].y = geometry->y + size;
	    pt[1].x = geometry->x + (int)geometry->width - size;
	    pt[1].y = geometry->y;
	    pt[2].x = geometry->x + (int)geometry->width - size;
	    pt[2].y = geometry->y + shadow;
	    pt[3].x = geometry->x + (int)geometry->width - shadow;
	    pt[3].y = geometry->y + size;
	    XFillPolygon(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.bottom_shadow_GC,
			 pt, 4, Convex, CoordModeOrigin);
	}
	else
	{
	    pt[0].x = geometry->x + size;
	    pt[0].y = geometry->y;
	    pt[1].x = geometry->x;
	    pt[1].y = geometry->y + size;
	    pt[2].x = pt[1].x + shadow;
	    pt[2].y = pt[1].y;
	    pt[3].x = pt[0].x;
	    pt[3].y = pt[0].y + shadow;
	    XFillPolygon(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 pt, 4, Convex, CoordModeOrigin);

	    pt[0].x = geometry->x + size;
	    pt[0].y = geometry->y + (int)geometry->height;
	    pt[1].x = geometry->x;
	    pt[1].y = geometry->y + (int)geometry->height - size;
	    pt[2].x = pt[1].x + shadow;
	    pt[2].y = pt[1].y;
	    pt[3].x = pt[0].x;
	    pt[3].y = pt[0].y - shadow;
	    XFillPolygon(XtDisplay(tab), XiCanvas(tab),
			 tab->manager.top_shadow_GC,
			 pt, 4, Convex, CoordModeOrigin);
	}
	break;
    }
}

static void
#ifndef _NO_PROTO
DrawTab(XmTabBoxWidget tab, XmTabAttributes info, XiTabRect *geometry,
	Boolean selected, Boolean keyboard)
#else
DrawTab(tab, info, geometry, selected, keyboard)
    XmTabBoxWidget  tab;
    XmTabAttributes info;
    XiTabRect       *geometry;
    Boolean         selected, keyboard;
#endif
{
    XmTabEdge        edge = XmTabBox_tab_edge(tab);
    Widget           canvas = XmTabBox__canvas(tab);
    XmFontList       font_list = XmTabBox_font_list(tab);
    Dimension        shadow_thickness = tab->manager.shadow_thickness,
                     margin_width = XmTabBox_tab_margin_width(tab),
                     margin_height = XmTabBox_tab_margin_width(tab),
                     size = XmTabBox__corner_size(tab);
    XRectangle       *clip;
    int              pix_width = 0, pix_height = 0, pix_depth = 0,
                     label_width = 0, label_height = 0, row;
    Boolean          have_pixmap = False, have_label = False;
    GC               gc = XmTabBox__tab_GC(tab);
    XmTabAttributes  above;

    /*
     * Lets do the quick check here.  If we are not realized then there is
     * really nothing to draw so lets just leave.
     */
    if( !XtIsRealized(canvas) || info == NULL ) return;

    if( (XmTabBox_tab_mode(tab) == XmTABS_STACKED ||
	 XmTabBox_tab_mode(tab) == XmTABS_STACKED_STATIC) &&
         XmTabBox_tab_style(tab) != XmTABS_SQUARED )
    {
	row = geometry->row;
	do
	{
	    if( LayoutIsRtoLP(tab) )
		above = GetTabInfo(tab, ++row, geometry->column-1);
	    else
		above = GetTabInfo(tab, ++row, geometry->column);
	} while( above == NULL && row < XmTabBox__num_rows(tab) );

	if( above != NULL )
	{
	    /*
	     * Ok, what is happening here is that we are in a stacked layout
	     * and we have a tab that is above us.  This means that we
	     * need to fill in our upper corner with this tabs color.
	     */
	    if( XiBackgroundSpecified(above) )
	    {
		SetBackgroundGC(tab, above, gc);
	    }
	    else
	    {
		if( ValidPixmap(tab->core.background_pixmap) )
		{
		    SetTiledXYGC(XtDisplay(tab), gc,
				 tab->core.background_pixmap,
				 -(tab->core.x), -(tab->core.y));
		}
		else
		{
		    SetSolidGC(XtDisplay(tab), gc, tab->core.background_pixel);
		}
	    }
	}
	else
	{
	    Widget gcParent = XiGCParent(tab);
	    Pixel  pixel;
	    Pixmap pixmap;

	    XtVaGetValues(gcParent,
			  XmNbackground, &pixel,
			  XmNbackgroundPixmap, &pixmap,
			  NULL);

	    if( ValidPixmap(pixmap) )
	    {
		SetTiledXYGC(XtDisplay(tab), gc, pixmap,
			     -(tab->core.x), -(tab->core.y));
	    }
	    else
	    {
		SetSolidGC(XtDisplay(tab), gc, pixel);
	    }
			     
	}
	if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	{
	    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + geometry->width - size,
			       geometry->y, size, size);
	    }
	    else
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x,
			       geometry->y + geometry->height - size,
			       size, size);
	    }
	}
	else
	{
	    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + geometry->width - size,
			       geometry->y + geometry->height - size,
			       size, size);
	    }
	    else
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + geometry->width - size,
			       geometry->y + geometry->height - size,
			       size, size);
	    }
	}

	row = geometry->row;
	do
	{
	    if( LayoutIsRtoLP(tab) )
		above = GetTabInfo(tab, ++row, geometry->column);
	    else
		above = GetTabInfo(tab, ++row, geometry->column - 1);
	} while( above == NULL && row < XmTabBox__num_rows(tab) );

	if( above != NULL )
	{
	    /*
	     * Ok, what is happening here is that we are in a stacked layout
	     * and we have a tab that is above us.  This means that we
	     * need to fill in our upper corner with this tabs color.
	     */
	    if( XiBackgroundSpecified(above) )
	    {
		SetBackgroundGC(tab, above, gc);
	    }
	    else
	    {
		if( ValidPixmap(tab->core.background_pixmap) )
		{
		    SetTiledXYGC(XtDisplay(tab), gc,
				 tab->core.background_pixmap,
				 -(tab->core.x), -(tab->core.y));
		}
		else
		{
		    SetSolidGC(XtDisplay(tab), gc, tab->core.background_pixel);
		}
	    }
	}
	else
	{
	    Widget gcParent = XiGCParent(tab);
	    Pixel  pixel;
	    Pixmap pixmap;

	    XtVaGetValues(gcParent,
			  XmNbackground, &pixel,
			  XmNbackgroundPixmap, &pixmap,
			  NULL);

	    if( ValidPixmap(pixmap) )
	    {
		SetTiledXYGC(XtDisplay(tab), gc, pixmap,
			     -(tab->core.x), -(tab->core.y));
	    }
	    else
	    {
		SetSolidGC(XtDisplay(tab), gc, pixel);
	    }
			     
	}
	if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	{
	    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x, geometry->y, size, size);
	    }
	    else
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x, geometry->y, size, size);
	    }
	}
	else
	{
	    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x,
			       geometry->y + geometry->height - size,
			       size, size);
	    }
	    else
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), gc,
			       geometry->x + geometry->width - size,
			       geometry->y, size, size);
	    }
	}
    }

    if( selected && XiSelectSpecified(tab) )
    {
#ifdef FIX_1503
	SetSelectGC(tab, XmTabBox__tab_GC(tab));
#else
	SetSelectGC(tab, tab->manager.background_GC);
#endif
    }
    else
    {
	/*
	 * Lets see if we need to fill in the background color of this tab, or
	 * if it wants the same color as its parent.
	 */
	if( XiBackgroundSpecified(info) )
	{
	    /*
	     * It appears that this tab wants its background filled in
	     * to a specific color so lets do that.
	     */
#ifdef FIX_1503
	    SetBackgroundGC(tab, info, XmTabBox__tab_GC(tab));
#else
	    SetBackgroundGC(tab, info, tab->manager.background_GC);
#endif
	}
	else
	{
	    if( ValidPixmap(tab->core.background_pixmap) )
	    {
		SetTiledXYGC(XtDisplay(tab), gc, tab->core.background_pixmap,
			     -(tab->core.x), -(tab->core.y));
	    }
	    else
	    {
		SetSolidGC(XtDisplay(tab), gc, tab->core.background_pixel);
	    }
	}
    }
    switch( XmTabBox_tab_style(tab) )
    {
    case XmTABS_SQUARED:
#ifdef FIX_1503
	XFillRectangle(XtDisplay(tab), XiCanvas(tab), XmTabBox__tab_GC(tab), geometry->x,
		       geometry->y, geometry->width, geometry->height);
#else
	XFillRectangle(XtDisplay(tab), XiCanvas(tab), tab->manager.background_GC, geometry->x,
		       geometry->y, geometry->width, geometry->height);
#endif
	break;
    case XmTABS_ROUNDED:
#ifdef FIX_1503
	FillRoundedTab(tab, XmTabBox__tab_GC(tab), geometry, edge);
#else
	FillRoundedTab(tab, tab->manager.background_GC, geometry, edge);
#endif
	break;
    case XmTABS_BEVELED:
#ifdef FIX_1503
	FillBeveledTab(tab, XmTabBox__tab_GC(tab), geometry, edge);
#else
	FillBeveledTab(tab, tab->manager.background_GC, geometry, edge);
#endif
	break;
    }

    /*
     * The first thing that we will draw is the shadows around the tab.
     * We have a lot of nifty routines to do this.  Maybe will add more
     * someday.
     */

    switch( XmTabBox_tab_style(tab) )
    {
    case XmTABS_SQUARED:
	DrawSquareShadows(tab, info, geometry, selected, edge,
			  shadow_thickness);
	break;
    case XmTABS_ROUNDED:
	DrawRoundedShadows(tab, info, geometry, selected, edge,
			   shadow_thickness);
	break;
    case XmTABS_BEVELED:
	DrawBeveledShadows(tab, info, geometry, selected, edge,
			   shadow_thickness);
	break;
    default:
	break;
    }

    gc = XmTabBox__text_GC(tab);
    /*
     * Now comes the hard part we need to draw the label.  The label
     * consists of an XmString and a pixmap, both of which are optional.
     *
     * First lets calculate the size of both the label and the pixmap
     * so that we can calculate the amount of space we will need to 
     * display the entire tab label.
     */
    if( ValidPixmap(info->label_pixmap) && 
        info->pixmap_placement != XmPIXMAP_NONE )
    {
	Window       window_unused;
	int          int_unused;
	unsigned int uint_unused, width_return, height_return, depth_return;

	have_pixmap = True;
	
	XGetGeometry(XtDisplay(tab), info->label_pixmap, &window_unused,
		     &int_unused, &int_unused, &width_return, &height_return,
		     &uint_unused, &depth_return);

	pix_depth = depth_return;
	pix_width = width_return;
	pix_height = height_return;
    }
    else
    {
	pix_depth = 0;
	pix_width = 0;
	pix_height = 0;
    }

    if( info->label_string != NULL &&
        info->pixmap_placement != XmPIXMAP_ONLY )
    {
	Dimension string_width, string_height;
	have_label = True;

	XmStringExtent(font_list, info->label_string,
		       &string_width, &string_height);
	label_width = string_width;
	label_height = string_height;
    }
    else
    {
	label_width = 0;
	label_height = 0;
    }

    SetSolidGC(XtDisplay(tab), gc,
	       (info->foreground == XmCOLOR_DYNAMIC
		? tab->manager.foreground
		: info->foreground));

    margin_width += shadow_thickness;
    margin_height += shadow_thickness;
    AssignMax(margin_width, size);
    AssignMax(margin_height, size);

    /*
     * Now lets calculate the cliping rectangle for the area in which
     * text and images can be drawn.  And since all we have left
     * to draw is text and images lets assign this rectangle as the
     * cliping area for our drawing GC.
     */
    clip = GetTabRectangle(tab, XmTAB_TEXT_RECT, geometry);
    XSetClipRectangles(XtDisplay(tab), gc, 0, 0, clip, 1, YXBanded);

    switch( XmTabBox_tab_orientation(tab) )
    {
    case XmTABS_LEFT_TO_RIGHT:
    default:
	DrawLeftToRightTab(tab, info, gc, have_pixmap, pix_width, pix_height,
			   pix_depth, have_label, label_width, label_height,
			   clip);
	break;
    case XmTABS_RIGHT_TO_LEFT:
	DrawRightToLeftTab(tab, info, gc, have_pixmap, pix_width, pix_height,
			   pix_depth, have_label, label_width, label_height,
			   clip, selected);
	break;
    case XmTABS_TOP_TO_BOTTOM:
	DrawTopToBottomTab(tab, info, gc, have_pixmap, pix_width, pix_height,
			   pix_depth, have_label, label_width, label_height,
			   clip, selected);
	break;
    case XmTABS_BOTTOM_TO_TOP:
	DrawBottomToTopTab(tab, info, gc, have_pixmap, pix_width, pix_height,
			   pix_depth, have_label, label_width, label_height,
			   clip, selected);
	break;
    }
    /*
     * The final bit of draw we have to do is to add the highlight
     * border to the tab if it currently has keyboard traversal.
     */
    if( keyboard && Prim_HaveTraversal(XmTabBox__canvas(tab)) )
    {
	BorderHighlight(XmTabBox__canvas(tab));
    }

    /*
     * Now that our drawing is done lets be sure to zero out the
     * clipping area for our GC.
     */
    XSetClipMask(XtDisplay(tab), gc, None);
}

#define XiCvtDone(type, value) 				\
    {							\
	if( to->addr != NULL )				\
	{						\
	    if( to->size < sizeof(type) )		\
	    {						\
		to->size = sizeof(type);		\
		return( False );			\
	    }						\
	    *(type*)(to->addr) = (value);		\
	}						\
	else						\
	{						\
	    static type static_val;			\
	    static_val = (value);			\
	    to->addr = (XtPointer) &static_val;		\
	}						\
	to->size = sizeof(type);			\
	return( True );					\
    }

/* ARGSUSED */
static Boolean
#ifndef _NO_PROTO
CvtStringToTabOrientation(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt,
			  XrmValue *from, XrmValue *to, XtPointer *data)
#else
CvtStringToTabOrientation(dpy, arg_list, arg_cnt, from, to, data)
    Display   *dpy;
    XrmValue  *arg_list;
    Cardinal  *arg_cnt;
    XrmValue  *from, *to;
    XtPointer *data;
#endif
{
    static int result = XmTABS_TOP_TO_BOTTOM;
    String     str = (String) (from->addr);

    if( XmCompareISOLatin1(str, "ORIENTATION_DYNAMIC") == 0 ||
        XmCompareISOLatin1(str, "XiTABS_ORIENTATION_DYNAMIC") == 0 )
    {
	result = XmTAB_ORIENTATION_DYNAMIC;
    }
    else if( XmCompareISOLatin1(str, "TOP_TO_BOTTOM") == 0 ||
        XmCompareISOLatin1(str, "XmTABS_TOP_TO_BOTTOM") == 0 )
    {
	result = XmTABS_TOP_TO_BOTTOM;
    }
    else if( XmCompareISOLatin1(str, "BOTTOM_TO_TOP") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_BOTTOM_TO_TOP") == 0 )
    {
	result = XmTABS_BOTTOM_TO_TOP;
    }
    else if( XmCompareISOLatin1(str, "LEFT_TO_RIGHT") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_LEFT_TO_RIGHT") == 0 )
    {
	result = XmTABS_LEFT_TO_RIGHT;
    }
    else if( XmCompareISOLatin1(str, "RIGHT_TO_LEFT") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_RIGHT_TO_LEFT") == 0 )
    {
	result = XmTABS_RIGHT_TO_LEFT;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, str, XmRTabOrientation);
	return( False );
    }

    XiCvtDone(int, result);
}

static Boolean
#ifndef _NO_PROTO
CvtStringToTabSide(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt,
		    XrmValue *from, XrmValue *to, XtPointer *data)
#else
CvtStringToTabSide(dpy, arg_list, arg_cnt, from, to, data)
    Display   *dpy;
    XrmValue  *arg_list;
    Cardinal  *arg_cnt;
    XrmValue  *from, *to;
    XtPointer *data;
#endif
{
    static int result = XmTABS_ON_TOP;
    String     str = (String) (from->addr);

    if( XmCompareISOLatin1(str, "ON_TOP") == 0 ||
        XmCompareISOLatin1(str, "XmTABS_ON_TOP") == 0 )
    {
	result = XmTABS_ON_TOP;
    }
    else if( XmCompareISOLatin1(str, "ON_BOTTOM") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_ON_BOTTOM") == 0 )
    {
	result = XmTABS_ON_BOTTOM;
    }
    else if( XmCompareISOLatin1(str, "ON_LEFT") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_ON_LEFT") == 0 )
    {
	result = XmTABS_ON_LEFT;
    }
    else if( XmCompareISOLatin1(str, "ON_RIGHT") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_ON_RIGHT") == 0 )
    {
	result = XmTABS_ON_RIGHT;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, str, XmRTabSide);
	return( False );
    }

    XiCvtDone(int, result);
}

/* ARGSUSED */
static Boolean
#ifndef _NO_PROTO
CvtStringToTabStyle(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt,
		    XrmValue *from, XrmValue *to, XtPointer *data)
#else
CvtStringToTabStyle(dpy, arg_list, arg_cnt, from, to, data)
    Display   *dpy;
    XrmValue  *arg_list;
    Cardinal  *arg_cnt;
    XrmValue  *from, *to;
    XtPointer *data;
#endif
{
    static int result = XmTABS_BEVELED;
    String     str = (String) (from->addr);

    if( XmCompareISOLatin1(str, "SQUARED") == 0 ||
        XmCompareISOLatin1(str, "XmTABS_SQUARED") == 0 )
    {
	result = XmTABS_SQUARED;
    }
    else if( XmCompareISOLatin1(str, "ROUNDED") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_ROUNDED") == 0 )
    {
	result = XmTABS_ROUNDED;
    }
    else if( XmCompareISOLatin1(str, "BEVELED") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_BEVELED") == 0 )
    {
	result = XmTABS_BEVELED;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, str, XmRTabStyle);
	return( False );
    }

    XiCvtDone(int, result);
}

/* ARGSUSED */
static Boolean
#ifndef _NO_PROTO
CvtStringToTabMode(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt,
		   XrmValue *from, XrmValue *to, XtPointer *data)
#else
CvtStringToTabMode(dpy, arg_list, arg_cnt, from, to, data)
    Display   *dpy;
    XrmValue  *arg_list;
    Cardinal  *arg_cnt;
    XrmValue  *from, *to;
    XtPointer *data;
#endif
{
    static int result = XmTABS_BASIC;
    String     str = (String) from->addr;

    if( XmCompareISOLatin1(str, "BASIC") == 0 ||
        XmCompareISOLatin1(str, "XmTABS_BASIC") == 0 )
    {
    }
    else if( XmCompareISOLatin1(str, "STACKED") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_STACKED") == 0 )
    {
	result = XmTABS_STACKED;
    }
    else if( XmCompareISOLatin1(str, "STACKED_STATIC") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_STACKED_STATIC") == 0 )
    {
	result = XmTABS_STACKED_STATIC;
    }
#ifdef SCROLLED_LAYOUT
    else if( XmCompareISOLatin1(str, "SCROLLED") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_SCROLLED") == 0 )
    {
	result = XmTABS_SCROLLED;
    }
#endif
#ifdef OVERLAYED_LAYOUT
    else if( XmCompareISOLatin1(str, "OVERLAYED") == 0 ||
	     XmCompareISOLatin1(str, "XmTABS_OVERLAYED") == 0 )
    {
	result = XmTABS_OVERLAYED;
    }
#endif
    else
    {
	XtDisplayStringConversionWarning(dpy, str, XmRTabMode);
	return( False );
    }

    XiCvtDone(int, result);
}

/* ARGSUSED */
static Boolean
#ifndef _NO_PROTO
CvtStringToTabEdge(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt,
		   XrmValue *from, XrmValue *to, XtPointer *data)
#else
CvtStringToTabEdge(dpy, arg_list, arg_cnt, from, to, data)
    Display   *dpy;
    XrmValue  *arg_list;
    Cardinal  *arg_cnt;
    XrmValue  *from, *to;
    XtPointer *data;
#endif
{
    static int result = XmTAB_EDGE_BOTTOM_RIGHT;
    String     str = (String) (from->addr);

    if( XmCompareISOLatin1(str, "EDGE_TOP_LEFT") == 0 ||
        XmCompareISOLatin1(str, "XmTAB_EDGE_TOP_LEFT") == 0 )
    {
	result = XmTAB_EDGE_TOP_LEFT;
    }
    else if( XmCompareISOLatin1(str, "EDGE_BOTTOM_RIGHT") == 0 ||
        XmCompareISOLatin1(str, "XiTABS_EDGE_BOTTOM_RIGHT") == 0 )
    {
	result = XmTAB_EDGE_BOTTOM_RIGHT;
    }
    else if( XmCompareISOLatin1(str, "bottom") == 0 )
    {
	result = XmTAB_EDGE_TOP_LEFT;
    }
    else if( XmCompareISOLatin1(str, "right") == 0 )
    {
	result = XmTAB_EDGE_BOTTOM_RIGHT;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, str, XmRTabEdge);
	return( False );
    }

    XiCvtDone(int, result);
}

#ifdef SCROLLED_LAYOUT
static Boolean
#ifndef _NO_PROTO
CvtStringToArrowPlacement(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt,
			  XrmValue *from, XrmValue *to, XtPointer *data)
#else
CvtStringToArrowPlacement(dpy, arg_list, arg_cnt, from, to, data)
    Display   *dpy;
    XrmValue  *arg_list;
    Cardinal  *arg_cnt;
    XrmValue  *from, *to;
    XtPointer *data;
#endif
{
    static int result = XmTAB_ARROWS_ON_LEFT;
    String     str = (String) (from->addr);

    if( XmCompareISOLatin1(str, "left") == 0 ||
        XmCompareISOLatin1(str, "tab_arrows_on_left") == 0 )
    {
	result = XmTAB_ARROWS_ON_LEFT;
    }
    else if( XmCompareISOLatin1(str, "right") == 0 ||
             XmCompareISOLatin1(str, "tab_arrows_on_right") == 0 )
    {
	result = XmTAB_ARROWS_ON_RIGHT;
    }
    else if( XmCompareISOLatin1(str, "split") == 0 ||
             XmCompareISOLatin1(str, "tab_arrows_split") == 0 )
    {
	result = XmTAB_ARROWS_SPLIT;
    }
    else
    {
	XtDisplayStringConversionWarning(dpy, str, XmRTabArrowPlacement);
	return( False );
    }

    XiCvtDone(int, result);
}
#endif

/* ARGSUSED */
static Boolean
#ifndef _NO_PROTO
CvtStringToTabList(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt,
		   XrmValue *from, XrmValue *to, XtPointer *data)
#else
CvtStringToTabList(dpy, arg_list, arg_cnt, from, to, data)
    Display   *dpy;
    XrmValue  *arg_list;
    Cardinal  *arg_cnt;
    XrmValue  *from, *to;
    XtPointer *data;
#endif
{
    return( False );
}

/* ARGSUSED */
static void
#ifndef _NO_PROTO
CvtDestroyTabList(XtAppContext app_context, XrmValue *to, XtPointer data,
			      XrmValue *args, Cardinal *num_args)
#else
CvtDestroyTabList(app_context, to, data, args, num_args)
    XtAppContext app_context;
    XrmValue     *to;
    XtPointer    data;
    XrmValue     *args;
    Cardinal     *num_args;
#endif
{
}

static short XiCosSinData[][2] = {
    { 1000,    0 },    {  998,   52 },    {  994,  104 },    {  987,  156 },
    {  978,  207 },    {  965,  258 },    {  951,  309 },    {  933,  358 },
    {  913,  406 },    {  891,  453 },    {  866,  499 },    {  838,  544 },
    {  809,  587 },    {  777,  629 },    {  743,  669 },    {  707,  707 },
    {  669,  743 },    {  629,  777 },    {  587,  809 },    {  544,  838 },
    {  500,  866 },    {  453,  891 },    {  406,  913 },    {  358,  933 },
    {  309,  951 },    {  258,  965 },    {  207,  978 },    {  156,  987 },
    {  104,  994 },    {   52,  998 },    {    0, 1000 }};

#define NUM_PTS    31
#define NUM_PTSx2  62
#define HALF_PTS   16
#define HALF_PTSx2 32
#define NUM_PTSp1  32

static void
#ifndef _NO_PROTO
XiDrawCorner(Display *dpy, Drawable d, GC top_gc, GC bottom_gc, int x, int y,
	     unsigned int width, unsigned int height, unsigned int size,
	     XiQuadrant quadrant)
#else
XiDrawCorner(dpy, d, top_gc, bottom_gc, x, y, width, height, size, quadrant)
    Display      *dpy;
    Drawable     d;
    GC           top_gc, bottom_gc;
    int          x, y;
    unsigned int width, height, size;
    XiQuadrant   quadrant;
#endif
{
    XPoint pt[NUM_PTSx2];
    int    i, xrad1, xrad2, yrad1, yrad2, tmp;

    xrad1 = width;
    xrad2 = width - size;
    yrad1 = height;
    yrad2 = height - size;

    switch( quadrant )
    {
    case XiQUAD_1:
	y += height;
	for( i = 0; i < HALF_PTS; ++i )
	{
	    pt[i].x = x + XiCosSinData[i][0] * xrad1 / 1000;
	    pt[i].y = y - XiCosSinData[i][1] * yrad1 / 1000;

	    pt[HALF_PTSx2-1-i].x = x + XiCosSinData[i][0] * xrad2 / 1000;
	    pt[HALF_PTSx2-1-i].y = y - XiCosSinData[i][1] * yrad2 / 1000;
	}
	XFillPolygon(dpy, d, bottom_gc, pt, HALF_PTSx2, Nonconvex,
		     CoordModeOrigin);
	for( tmp = 0, i = HALF_PTS-1; i < NUM_PTS; ++i, ++tmp )
	{
	    pt[tmp].x = x + XiCosSinData[i][0] * xrad1 / 1000;
	    pt[tmp].y = y - XiCosSinData[i][1] * yrad1 / 1000;

	    pt[HALF_PTSx2-1-tmp].x = x + XiCosSinData[i][0] * xrad2 / 1000;
	    pt[HALF_PTSx2-1-tmp].y = y - XiCosSinData[i][1] * yrad2 / 1000;
	}
	XFillPolygon(dpy, d, top_gc, pt, HALF_PTSx2, Nonconvex,
		     CoordModeOrigin);
	break;
    case XiQUAD_2:
	x += width;
	y += height;

	for( i = 0; i < NUM_PTS; ++i )
	{
	    pt[i].x = x - XiCosSinData[i][0] * xrad1 / 1000;
	    pt[i].y = y - XiCosSinData[i][1] * yrad1 / 1000;
	    
	    pt[NUM_PTSx2-1-i].x = x - (int)XiCosSinData[i][0] * xrad2 / 1000;
	    pt[NUM_PTSx2-1-i].y =  y - (int)XiCosSinData[i][1] * yrad2 / 1000;
	}
	XFillPolygon(dpy, d, top_gc, pt, NUM_PTSx2, Nonconvex,
		     CoordModeOrigin);
	break;
    case XiQUAD_3:
	x += width;
	for( i = 0; i < HALF_PTS; ++i )
	{
	    pt[i].x = x - XiCosSinData[i][0] * xrad1 / 1000;
	    pt[i].y = y + XiCosSinData[i][1] * yrad1 / 1000;

	    pt[HALF_PTSx2-1-i].x = x - XiCosSinData[i][0] * xrad2 / 1000;
	    pt[HALF_PTSx2-1-i].y = y + XiCosSinData[i][1] * yrad2 / 1000;
	}
	XFillPolygon(dpy, d, top_gc, pt, HALF_PTSx2, Nonconvex,
		     CoordModeOrigin);

	for( tmp = 0, i = HALF_PTS-1; i < NUM_PTS; ++i, ++tmp )
	{
	    pt[tmp].x = x - XiCosSinData[i][0] * xrad1 / 1000;
	    pt[tmp].y = y + XiCosSinData[i][1] * yrad1 / 1000;

	    pt[HALF_PTSx2-1-tmp].x = x - XiCosSinData[i][0] * xrad2 / 1000;
	    pt[HALF_PTSx2-1-tmp].y = y + XiCosSinData[i][1] * yrad2 / 1000;
	}
	XFillPolygon(dpy, d, bottom_gc, pt, HALF_PTSx2, Nonconvex,
		     CoordModeOrigin);
	break;
    case XiQUAD_4:
	for( i = 0; i < NUM_PTS; ++i )
	{
	    pt[i].x = x + XiCosSinData[i][0] * xrad1 / 1000;
	    pt[i].y = y + XiCosSinData[i][1] * yrad1 / 1000;

	    pt[NUM_PTSx2-1-i].x = x + XiCosSinData[i][0] * xrad2 / 1000;
	    pt[NUM_PTSx2-1-i].y = y + XiCosSinData[i][1] * yrad2 / 1000;
	}
	XFillPolygon(dpy, d, bottom_gc, pt, NUM_PTSx2, Nonconvex,
		     CoordModeOrigin);
	break;
    default:
	break;
    }
}

static void
#ifndef _NO_PROTO
XiFillCorner(Display *dpy, Drawable d, GC gc, int x, int y,
	     unsigned int width, unsigned int height, XiQuadrant quadrant)
#else
XiFillCorner(dpy, d, gc, x, y, width, height, quadrant)
    Display      *dpy;
    Drawable     d;
    GC           gc;
    int          x, y;
    unsigned int width, height;
    XiQuadrant   quadrant;
#endif
{
    XPoint pt[NUM_PTSp1];
    int    i, xrad1, yrad1;

    xrad1 = width;
    yrad1 = height;

    switch( quadrant )
    {
    case XiQUAD_1:
	y += height;
	for( i = 0; i < NUM_PTS; ++i )
	{
	    pt[i].x = x + XiCosSinData[i][0] * xrad1 / 1000;
	    pt[i].y = y - XiCosSinData[i][1] * yrad1 / 1000;
	}
	pt[i].x = x;
	pt[i++].y = y + height;
	XFillPolygon(dpy, d, gc, pt, i, Nonconvex, CoordModeOrigin);
	break;
    case XiQUAD_2:
	x += width;
	y += height;

	for( i = 0; i < NUM_PTS; ++i )
	{
	    pt[i].x = x - XiCosSinData[i][0] * xrad1 / 1000;
	    pt[i].y = y - XiCosSinData[i][1] * yrad1 / 1000;
	}
	pt[i].x = x + width;
	pt[i++].y = y + height;
	XFillPolygon(dpy, d, gc, pt, i, Nonconvex, CoordModeOrigin);
	break;
    case XiQUAD_3:
	x += width;
	for( i = 0; i < NUM_PTS; ++i )
	{
	    pt[i].x = x - XiCosSinData[i][0] * xrad1 / 1000;
	    pt[i].y = y + XiCosSinData[i][1] * yrad1 / 1000;
	}
	pt[i].x = x + width;
	pt[i++].y = y;
	XFillPolygon(dpy, d, gc, pt, i, Nonconvex, CoordModeOrigin);
	break;
    case XiQUAD_4:
	for( i = 0; i < NUM_PTS; ++i )
	{
	    pt[i].x = x + XiCosSinData[i][0] * xrad1 / 1000;
	    pt[i].y = y + XiCosSinData[i][1] * yrad1 / 1000;
	}
	pt[i].x = x;
	pt[i++].y = y;
	XFillPolygon(dpy, d, gc, pt, i, Nonconvex, CoordModeOrigin);
	break;
    default:
	break;
    }
}

static void
#ifndef _NO_PROTO
HorizontalBasicLayout(XmTabBoxWidget tab)
#else
HorizontalBasicLayout(tab)
    XmTabBoxWidget tab;
#endif
{
    int        i, x, height, cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab));
    XiTabRect  *actual = XmTabBox__actual(tab);
    XRectangle *wanted = XmTabBox__wanted(tab);

    x = LayoutIsRtoLP(tab) ? (tab->core.width - wanted[0].width) : 0;
    height = XtHeight(tab);
    for( i = 0; i < cnt; ++i )
    {
	actual[i].x = x;
	actual[i].y = 0;
	actual[i].width = wanted[i].width;
	actual[i].height = height;
	actual[i].row = 0;
	actual[i].column = i;
	if (i < cnt-1)
	    x += LayoutIsRtoLP(tab) ? -actual[i+1].width : actual[i].width;
    }
    XmTabBox__num_rows(tab) = 1;
    XmTabBox__num_columns(tab) = i;
}

static void
#ifndef _NO_PROTO
VerticalBasicLayout(XmTabBoxWidget tab)
#else
VerticalBasicLayout(tab)
    XmTabBoxWidget tab;
#endif
{
    int        i, y, width, cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab));
    XiTabRect  *actual = XmTabBox__actual(tab);
    XRectangle *wanted = XmTabBox__wanted(tab);

    y = 0;
    width = XtWidth(tab);
    for( i = 0; i < cnt; ++i )
    {
	actual[i].x = 0;
	actual[i].y = y;
	actual[i].width = width;
	actual[i].height = wanted[i].height;
	actual[i].row = 0;
	actual[i].column = i;
	y += actual[i].height;
    }
    XmTabBox__num_rows(tab) = 1;
    XmTabBox__num_columns(tab) = i;
}

static void
#ifndef _NO_PROTO
Layout(XmTabBoxWidget tab)
#else
Layout(tab)
    XmTabBoxWidget tab;
#endif
{
    XmTabbedStackList  list = XmTabBox_tab_list(tab);
    int        count = _XmTabbedStackListCount(list);
    XRectangle geometry;
    
    if( count == 0 )
    {
	XmTabBox__num_columns(tab) = 0;
	XmTabBox__num_rows(tab) = 0;
	return;
    }

    if( count > XmTabBox__num_actual(tab) )
    {
	XmTabBox__num_actual(tab) = count;
	XmTabBox__actual(tab) = (XiTabRect*)
	    XtRealloc((XtPointer) XmTabBox__actual(tab),
		      sizeof(XiTabRect) * count);
    }

    switch( XmTabBox_tab_mode(tab) )
    {
    case XmTABS_BASIC:
	CalcGeometry(tab, &geometry);
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    HorizontalBasicLayout(tab);
	}
	else
	{
	    VerticalBasicLayout(tab);
	}
	break;
    case XmTABS_STACKED:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    HorizontalStackedLayout(tab, False);
	}
	else
	{
	    VerticalStackedLayout(tab, False);
	}
	break;
    case XmTABS_STACKED_STATIC:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    HorizontalStackedLayout(tab, True);
	}
	else
	{
	    VerticalStackedLayout(tab, True);
	}
	break;
    case XmTABS_SCROLLED:
	break;
    case XmTABS_OVERLAYED:
	break;
    }
}

/*
 * Function:
 *	HorizontalBasicRedisplay(tab)
 * Description:
 *	This function performs the basic tab redisplay in the horizontal
 *	direction.
 * Input:
 *	tab   : XtTabBoxWidget - the tab box to redisplay
 * Output:
 *	None.
 */
static void
#ifndef _NO_PROTO
HorizontalBasicRedisplay(XmTabBoxWidget tab)
#else
HorizontalBasicRedisplay(tab)
    XmTabBoxWidget tab;
#endif
{
    XiTabRect       *geom;
    int             count = _XmTabbedStackListCount(XmTabBox_tab_list(tab)), x,
                    shadow = tab->manager.shadow_thickness;

    geom = XmTabBox__actual(tab);
    x = geom[count-1].x + geom[count-1].width;

    /*
     * Now that we are done with the tabs we need to complete the line
     * from the last tab to the edge of the widget.
     */
    if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
    {
	if (LayoutIsRtoLP(tab))
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.top_shadow_GC,
		       0, (int)XtHeight(tab) - shadow,
		       geom[count-1].x, shadow);
	else
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.top_shadow_GC,
		       x, (int)XtHeight(tab) - shadow,
		       (int)XtWidth(tab) - x, shadow);
	XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
		    tab->manager.top_shadow_GC,
		    tab->manager.bottom_shadow_GC,
		    (int)XtWidth(tab) - shadow,
		    (int)XtHeight(tab) - shadow,
		    shadow, XmBEVEL_BOTTOM);
    }
    else
    {
	if (LayoutIsRtoLP(tab))
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.bottom_shadow_GC,
		       0, 0, geom[count-1].x, shadow);
	else
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.bottom_shadow_GC,
		       x, 0, (int)XtWidth(tab) - x, shadow);
    }
}

/*
 * Function:
 *	VerticalBasicRedisplay(tab)
 * Description:
 *	This function performs the basic tab redisplay in the Vertical
 *	direction.
 * Input:
 *	tab   : XtTabBoxWidget - the tab box to redisplay
 * Output:
 *	None.
 */
static void
#ifndef _NO_PROTO
VerticalBasicRedisplay(XmTabBoxWidget tab)
#else
VerticalBasicRedisplay(tab)
    XmTabBoxWidget tab;
#endif
{
    XiTabRect       *geom;
    int             count = _XmTabbedStackListCount(XmTabBox_tab_list(tab)), y,
                    shadow = tab->manager.shadow_thickness;

    geom = XmTabBox__actual(tab);
    y = geom[count-1].y + geom[count-1].height;

    /*
     * Now that we are done with the tabs we need to complete the line
     * from the last tab to the edge of the widget.
     */
    if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
    {
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.top_shadow_GC,
		       (int)XtWidth(tab) - shadow, y, shadow,
		       (int)XtHeight(tab) - y);
	XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
		    tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC,
		    (int)XtWidth(tab) - shadow, (int)XtHeight(tab) - shadow,
		    shadow, XmBEVEL_BOTTOM);
    }
    else
    {
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.bottom_shadow_GC,
		       0, y, shadow, (int)XtHeight(tab) - y);
    }
}

/*
 * Function:
 *	XiRotateImage(tab, src, degree)
 * Description:
 *	Returns a new XImage which is the given image rotate by either
 *	0 (a strait copy), 90, 180, or 270 degrees.
 * Input:
 *	tab    : XmTabBoxWidget - used for reference
 *	src    : XImage*        - the image to rotate
 *	degree : int            - how many degrees to rotate "floored"
 *			          to the nearest 90
 * Output:
 *	XImage* - and new allocated, rotated copy of the image
 */
static XImage*
#ifndef _NO_PROTO
XiRotateImage(XmTabBoxWidget tab, XImage *src, int degree)
#else
XiRotateImage(tab, src, degree)
    XmTabBoxWidget tab;
    XImage         *src;
    int            degree;
#endif
{
    XImage *dst;
    char   *data;
    int    x, y, width, height, depth, tmp;

    if( src == NULL ) return( NULL );

    width = XImageWidth(src);
    height = XImageHeight(src);
    depth = XImageDepth(src);

    if( depth < 8 )
    {
	int cnt = 8/depth;

	if( degree == 0 || degree == 180 )
	{
	    tmp = (width/cnt) + ((width % cnt != 0) ? 1 : 0);
	    tmp = tmp * height;
	}
	else
	{
	    tmp = (height/cnt) + ((height % cnt != 0) ? 1 : 0);
	    tmp = tmp * width;
	}
    }
    else
    {
	tmp = width * height * depth;
    }
    data = (char*) XtMalloc(tmp);

    if( degree == 0 || degree == 180 )
    {
	dst = XCreateImage(XtDisplay(tab),
			   GetShellVisual((Widget)tab),
			   depth, (depth == 1 ? XYBitmap : XYPixmap),
			   0, data, width, height,
			   8, 0);

	if( degree == 180 )
	{
	    for( y = 0; y < height; ++y )
	    {
		for( x = 0; x < width; ++x )
		{
		    XPutPixel(dst, (width-1-x), (height-1-y),
			      XGetPixel(src, x, y));
		}
	    }
	}
	else
	{
	    for( y = 0; y < height; ++y )
	    {
		for( x = 0; x < width; ++x )
		{
		    XPutPixel(dst, x, y, XGetPixel(src, x, y));
		}
	    }
	}
    }
    else
    {
	dst = XCreateImage(XtDisplay(tab),
			   GetShellVisual((Widget)tab),
			   depth, (depth == 1 ? XYBitmap : XYPixmap),
			   0, data, height, width, 8, 0);

	if( degree == 90 )
	{
	    for( y = 0; y < height; ++y )
	    {
		for( x = 0; x < width; ++x )
		{
		    XPutPixel(dst, (height-1-y), x,
			      XGetPixel(src, x, y));
		}
	    }
	}
	else
	{
	    for( y = 0; y < height; ++y )
	    {
		for( x = 0; x < width; ++x )
		{
		    XPutPixel(dst, y, (width-1-x),
			      XGetPixel(src, x, y));
		}
	    }
	}
    }

    return( dst );
}

static void
#ifndef _NO_PROTO
CalcCornerSize(XmTabBoxWidget tab)
#else
CalcCornerSize(tab)
    XmTabBoxWidget tab;
#endif
{
    XmFontContext   fc;
    XmFontListEntry entry;
    XmFontType      font_type;
    XtPointer       value;
    int             tmp, size = 0;
    
    XmFontListInitFontContext(&fc, XmTabBox_font_list(tab));

    while( (entry = XmFontListNextEntry(fc)) != NULL )
    {
	value = (XtPointer) XmFontListEntryGetFont(entry, &font_type);

	if( font_type == XmFONT_IS_FONT )
	{
	    XFontStruct     *font;

	    font = (XFontStruct*) value;
	    tmp = font->ascent + font->descent;
	    AssignMax(size, tmp);
	}
#ifdef USE_XFT
        else if (1/*font_type == XmFONT_IS_XFT*/)
	{
	    tmp = ((XftFont*)value)->ascent + ((XftFont*)value)->descent;
	    AssignMax(size, tmp);
	}
#endif
	else
	{
	    XFontSetExtents *extents;

	    extents = XExtentsOfFontSet((XFontSet) value);
	    tmp = extents->max_logical_extent.height;
	    AssignMax(size, tmp);
	}
    }
    XmFontListFreeFontContext(fc);


    XmTabBox__corner_size(tab) = size * XmTabBox_tab_corner_percent(tab)/ 100;
}

static int
#ifndef _NO_PROTO
XiXYtoTab(XmTabBoxWidget tab, int x, int y)
#else
XiXYtoTab(tab, x, y)
    XmTabBoxWidget tab;
    int            x, y;
#endif
{
    int        i, cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab)), row = -1, idx;
    XiTabRect  *area = XmTabBox__actual(tab);

    for( i = 0; i < cnt; ++i )
    {
	if( x < area[i].x || x > (area[i].x + (int)area[i].width) ||
	    y < area[i].y || y > (area[i].y + (int)area[i].height) )
	{
	    continue;
	}
	return( i );
    }

    /*
     * If we are in a stacked mode then we will do some more checking,
     * however if we are not in a stacked mode then we are done.
     */
    if( XmTabBox_tab_mode(tab) != XmTABS_STACKED &&
        XmTabBox_tab_mode(tab) != XmTABS_STACKED_STATIC )
    {
	return( -1 );
    }

    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
    {
	/*
	 * Since we are in a stacked mode it is possible that we clicked in
	 * a partial row.  So lets start by finding out which partial row
	 * we clicked in.  This is done by just looking at the height
	 * component of the tabs.
	 */
	for( i = 0; i < cnt; ++i )
	{
	    if( y >= area[i].y && y <= (area[i].y + (int)area[i].height) )
	    {
		/*
		 * We found the row we care about.
		 */
		row = area[i].row;
		break;
	    }
	}

	/*
	 * If we did not click in a row, or if that row is the last row we are
	 * done.
	 */
	if( row == -1 || row == (XmTabBox__num_rows(tab) - 1) ) return( -1 );

	/*
	 * Now we want to walk through all the columns of the previous row and
	 * see if the x position is in those columns.  And if we find a match
	 * we found a winner.
	 */
	for( i = 0, ++row, idx = 0;
	     idx >= 0 && i < XmTabBox__num_columns(tab); ++i )
	{
	    idx = GetTabIndex(tab, row, i);
	    if( idx < 0 || x < area[i].x || x > (area[i].x + area[i].width) )
	    {
		continue;
	    }
	    return( idx );
	}
    }
    else
    {
	/*
	 * Since we are in a stacked mode it is possible that we clicked in
	 * a partial row.  So lets start by finding out which partial row
	 * we clicked in.  This is done by just looking at the height
	 * component of the tabs.
	 */
	for( i = 0; i < cnt; ++i )
	{
	    if( x >= area[i].x && x <= (area[i].x + (int)area[i].width) )
	    {
		/*
		 * We found the row we care about.
		 */
		row = area[i].row;
		break;
	    }
	}

	/*
	 * If we did not click in a row, or if that row is the last row we are
	 * done.
	 */
	if( row == -1 || row == (XmTabBox__num_rows(tab) - 1) ) return( -1 );

	/*
	 * Now we want to walk through all the columns of the previous row and
	 * see if the x position is in those columns.  And if we find a match
	 * we found a winner.
	 */
	for( i = 0, ++row, idx = 0;
	     idx >= 0 && i < XmTabBox__num_columns(tab); ++i )
	{
	    idx = GetTabIndex(tab, row, i);
	    if( idx < 0 || y < area[i].y || y > (area[i].y + area[i].height) )
	    {
		continue;
	    }
	    return( idx );
	}
    }

    /*
     * If we get here we really did not find a match.
     */
    return( -1 );
}

/*
 * Function:
 *	CalcTabGeometry(XmTabBoxWidget tab)
 * Description:
 *	This function calculates and caches the geometry for all the tabs,
 *	taking into account the XmNuniformTabSize resource.
 * Input:
 *	tab : XmTabBoxWidget - the tab box who needs the geometries
 *                             calculated.
 * Output:
 *	None.
 */
static void
#ifndef _NO_PROTO
CalcTabGeometry(XmTabBoxWidget tab)
#else
CalcTabGeometry(tab)
    XmTabBoxWidget tab;
#endif
{
    XmTabbedStackList       list = XmTabBox_tab_list(tab);
    XmTabAttributes info;
    Dimension       width, height, max_width = 0, max_height = 0;
    int             count = _XmTabbedStackListCount(XmTabBox_tab_list(tab)), i;
    XRectangle      *geom;

    /*
     * First lets see if we have enough room to cache all the geometries
     * and if not lets increase our cache so there is room.
     */
    if( count > XmTabBox__num_wanted(tab) )
    {
	XmTabBox__num_wanted(tab) = count;
	XmTabBox__wanted(tab) = (XRectangle*)
	    XtRealloc((XtPointer)XmTabBox__wanted(tab),
		      sizeof(XRectangle) * count);
    }
    geom = XmTabBox__wanted(tab);

    /*
     * Now that we have enough space to cache all the Tab sizes we
     * need to walk through and calculate the size of all the tabs.
     */
    for( i = 0; i < count; ++i )
    {
	/*
	 * Now lets get the info for a tab and send it off to this handy
	 * dandy tab size calculator.
	 */
	info = _XmTabbedStackListGet(list, i);
	XiCalcTabSize(tab, info, &width, &height);

	/*
	 * Now lets do a quick check here to see if we are going to be
	 * making the tabs uniform and if so lets capture the maximum
	 * width and height of the tabs.
	 */
	if( XmTabBox_uniform_tab_size(tab) )
	{
	    AssignMax(max_width, width);
	    AssignMax(max_height, height);
	}
	else
	{
	    /*
	     * Since we are not doing uniform sized tabs here we can
	     * assign the values from our size calculation to the
	     * geometry cache.
	     */
	    geom[i].width = width;
	    geom[i].height = height;
	}
    }

    /*
     * Well if we are doing uniform tab sizes then we need to make 
     * one more pass over the tab geometry cache assigning the
     * same width and height to each tab.
     */
    if( XmTabBox_uniform_tab_size(tab) )
    {
	for( i = 0; i < count; ++i )
	{
	    geom[i].width = max_width;
	    geom[i].height = max_height;
	}
    }
}

/*
 * Function:
 *	CalcGeometryMinor(tab, major_d)
 * Description:
 *	Given the major Dimension calculates the needed minor dimension to
 *	display correctly.
 * Input:
 *	tab     : XmTabBoxWidget - the tab box to work with
 *	major_d : int            - the major dimension
 * Output:
 *	int - the desired minor dimension given the major dimension
 */
static int
#ifndef _NO_PROTO
CalcGeometryMinor(XmTabBoxWidget tab, int major_d)
#else
CalcGeometryMinor(tab, major_d)
    XmTabBoxWidget tab;
    int            major_d;
#endif
{
    XmTabbedStackList  list = XmTabBox_tab_list(tab);
    int        count = _XmTabbedStackListCount(list), i, max;
    XRectangle *geom;

    /*
     * First lets check if we have any tabs, because if we do not, then
     * our minor dimension becomes real easy ... all it is is our
     * shadow thickness.
     */
    if( count == 0 )
    {
	/*
	 * We do not have any tabs so we want to be the hieght of the
	 * shadow.
	 */
	return( tab->manager.shadow_thickness );
    }

    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
    {
	/*
	 * Ok, what is happening here is that we have a width and given this
	 * width we want to see what height we will be.  We will start with
	 * the easy check, i.e do we have any tabs.
	 */

	/*
	 * We have kids, so what we need to do is fake a given layout with
	 * the specified width but allowing our height to grow.
	 */
	switch( XmTabBox_tab_mode(tab) )
	{
	case XmTABS_BASIC:
	case XmTABS_OVERLAYED:
	case XmTABS_SCROLLED:
	default:
	    /*
	     * This is the simple layout case where all the tabs are in 
	     * one row.  So for these layouts all we have to do is find
	     * the maximum height of all the tabs.
	     */
	    for( i = 0, max = 0, geom = XmTabBox__wanted(tab); i < count; ++i )
	    {
		AssignMax(max, (int)geom[i].height);
	    }
	    return( max );
	case XmTABS_STACKED:
	case XmTABS_STACKED_STATIC:
 	    {
		int per_line, num_rows, tmp, tab_width, tab_height,
		    offset = XmTabBox_tab_offset(tab);

		tab_height = XmTabBox__wanted(tab)[0].height;
		tab_width = XmTabBox__wanted(tab)[0].width;

		per_line = count;
		num_rows = (int)(count/per_line) +
		    (count % per_line > 0 ? 1 : 0);
		tmp = (per_line * tab_width) + (num_rows * offset);
		while( per_line > 1 && tmp > major_d )
		{
		    per_line--;
		    num_rows = (int)(count/per_line) +
			(count % per_line > 0 ? 1 : 0);
		    tmp = (per_line * tab_width) + (num_rows * offset);
		}
		return( num_rows * tab_height );
	    }
	}
    }

    /* orientation == XmVERTICAL */

    switch( XmTabBox_tab_mode(tab) )
    {
    case XmTABS_BASIC:
    case XmTABS_OVERLAYED:
    case XmTABS_SCROLLED:
    default:
	for( i = 0, max = 0, geom = XmTabBox__wanted(tab); i < count; ++i )
	{
	    AssignMax(max, (int)geom[i].width);
	}
	return( max );
    case XmTABS_STACKED:
    case XmTABS_STACKED_STATIC:
        {
	    int per_line, num_rows, tmp, tab_width, tab_height,
	    offset = XmTabBox_tab_offset(tab);

	    tab_height = XmTabBox__wanted(tab)[0].height;
	    tab_width = XmTabBox__wanted(tab)[0].width;

	    per_line = count;
	    num_rows = (int)(count/per_line) +
		(count % per_line > 0 ? 1 : 0);
	    tmp = (per_line * tab_height) + (num_rows * offset);
	    while( per_line > 1 && tmp > major_d )
	    {
		per_line--;
		num_rows = (int)(count/per_line) +
		    (count % per_line > 0 ? 1 : 0);
		tmp = (per_line * tab_height) + (num_rows * offset);
	    }
	    return( num_rows * tab_width );
	}
    }
}

static int
CalcGeometryMajor(XmTabBoxWidget tab, int minor_d)
{
    XmTabbedStackList  list = XmTabBox_tab_list(tab);
    int        count = _XmTabbedStackListCount(list), i, max, total, num_rows;
    int        tmp=0, offset = XmTabBox_tab_offset(tab), num_cols;
    XRectangle *geom;

    if( count == 0 )
    {
	/*
	 * We don't have any children so our major dimension is simply
	 * our shadow.
	 */
	return( tab->manager.shadow_thickness );
    }
    
    geom = XmTabBox__wanted(tab);
    /*
     * Here the taks is to calculate the major dimension given the
     * minor one.
     */
    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
    {
	switch( XmTabBox_tab_mode(tab) )
	{
	case XmTABS_BASIC:
	case XmTABS_OVERLAYED:	
	case XmTABS_SCROLLED:
	default:
	    /*
	     * For this case the major dimension is simply the length
	     * of all the tabs in one row, reguardless of what the minor
	     * dimension is so lets figure this out.
	     */
	    for( i = 0, max = 0, total = 0; i < count; ++i )
	    {
		total += geom[i].width;
		AssignMax(max, (int)geom[i].width);
	    }

	    if( XmTabBox_uniform_tab_size(tab) )
	    {
		return( max * count );
	    }	
	    return( total );
	case XmTABS_STACKED:
	case XmTABS_STACKED_STATIC:
	    /*
	     * This case is a little harder here. What we want to do is
	     * say given this height how wide do we want to be.  So the
	     * first thing we need to do is find the height of our rows
	     * so we know how many we can fit.
	     */
	    for( i = 0, max = 1; i < count; ++i )
	    {
		AssignMax(max, (int)geom[i].height);
		AssignMax(tmp, (int)geom[i].width);
	    }
	    num_rows = minor_d/ max;
	    AssignMax(num_rows, 1);

	    /*
	     * Now that we know how many rows we are allowed all we
	     * have to do is partition the tabs between the rows and
	     * add on room for the stagger (if needed).
	     */
	    num_cols = (int)(count/num_rows) + (count % num_rows > 0 ? 1 : 0);
	    
	    total = num_cols * tmp + (num_rows - 1) * offset;

	    return( total );
	}
    }
    
    /* Vertical Orientation */

    switch( XmTabBox_tab_mode(tab) )
    {
    case XmTABS_BASIC:
    case XmTABS_OVERLAYED:	
    case XmTABS_SCROLLED:
    default:
	/*
	 * For this case the major dimension is simply the length
	 * of all the tabs in one row, reguardless of what the minor
	 * dimension is so lets figure this out.
	 */
	for( i = 0, max = 0, total = 0; i < count; ++i )
	{
	    total += geom[i].height;
	    AssignMax(max, (int)geom[i].height);
	}

	if( XmTabBox_uniform_tab_size(tab) )
	{
	    return( max * count );
	}	
	return( total );
    case XmTABS_STACKED:
    case XmTABS_STACKED_STATIC:
	/*
	 * This case is a little harder here. What we want to do is
	 * say given this height how wide do we want to be.  So the
	 * first thing we need to do is find the height of our rows
	 * so we know how many we can fit.
	 */
	for( i = 0, max = 1; i < count; ++i )
	{
	    AssignMax(max, (int)geom[i].width);
	    AssignMax(tmp, (int)geom[i].height);
	}
	num_rows = minor_d/ max;
	AssignMax(num_rows, 1);

	/*
	 * Now that we know how many rows we are allowed all we
	 * have to do is partition the tabs between the rows and
	 * add on room for the stagger (if needed).
	 */
	num_cols = (int)(count/num_rows) + (count % num_rows > 0 ? 1 : 0);
	    
	total = num_cols * tmp + (num_rows - 1) * offset;

	return( total );
    }
}

/*
 * Function:
 *	CallCallbacks(tab, event, from, to)
 * Description:
 *	Calls the unselect and select callbacks for the XmTabBox
 * Input:
 *	tab   : XmTabBoxWidget - the tab box widget
 *	event : XEvent*        - passed through
 *	from  : int            - the old selected tab
 *	to    : int	       - the new selected tab
 * Output:
 *	None.
 */
static void
CallCallbacks(XmTabBoxWidget tab, XEvent *event, int from, int to)
{
    XmTabBoxCallbackStruct cbdata;

    cbdata.reason    = XmCR_TAB_UNSELECTED;
    cbdata.event     = event;
    cbdata.tab_index = from;
    cbdata.old_index = from;
    XtCallCallbackList((Widget)tab, XmTabBox_unselect_callback(tab), (XtPointer)&cbdata);

    cbdata.reason    = XmCR_TAB_SELECTED;
    cbdata.event     = event;
    cbdata.tab_index = to;
    cbdata.old_index = from;
    XtCallCallbackList((Widget)tab, XmTabBox_select_callback(tab), (XtPointer)&cbdata);
}
#ifdef FIX_1381
static void
SetRightGC(XmTabBoxWidget tab, GC gc, GC_type gc_type)
{
    XGCValues       values;
    XtGCMask        valueMask;
    static Pixel 	p = 0;
    static GC_type 	last = normal;
    valueMask = GCForeground;
    switch( gc_type )
      {
        case normal:
          if (last !=normal)
            {
              values.foreground = p;
                XChangeGC(XtDisplay(tab),gc, valueMask, &values);
            }
          last = normal;
          break;
        case insensitive:
          if (last == normal) p=values.foreground;
            values.foreground = tab->manager.bottom_shadow_color;
            XChangeGC(XtDisplay(tab),gc, valueMask, &values);
            last = insensitive;
          break;
        case shadow:
          if (last == normal) p=values.foreground;
            values.foreground = tab->manager.top_shadow_color;
            XChangeGC(XtDisplay(tab),gc, valueMask, &values);
            last = shadow;
          break;
        default:
          break;
      }
}
#endif

/* ARGSUSED */
static void
DrawLeftToRightTab(XmTabBoxWidget tab, XmTabAttributes info, GC gc,
		   Boolean have_pixmap, int pix_width, int pix_height,
		   int pix_depth, Boolean have_label, int label_width,
		   int label_height, XRectangle *clip)
{
    XRectangle draw;
    XmFontList font_list = XmTabBox_font_list(tab);
    int        x, y, tmp, spacing = XmTabBox_tab_label_spacing(tab);
    Boolean    sensitive;

    x = draw.x = clip->x;
    y = draw.y = clip->y;
    draw.width = clip->width;
    draw.height = clip->height;
    sensitive = XtIsSensitive((Widget)tab) && info->sensitive;

    /*
     * If we are drawing both a pixmap and a label then we want to
     * give priority to the pixmap and align the text in the
     * rest of the mess.
     */
    if( have_pixmap )
    {
	/*
	 * We have a pixmap, so lets figure out where we want the
	 * pixmap to be placed.
	 */
	switch( info->pixmap_placement )
	{
	case XmPIXMAP_TOP:
	case XmPIXMAP_BOTTOM:
	case XmPIXMAP_ONLY:
	default:
	    /*
	     * In these cases we want to look at the alignment of the
	     * tab to determine where we want to place the pixmap.
	     */
	    switch( info->label_alignment )
	    {
	    case XmALIGNMENT_BEGINNING:
		/*
		 * For this alignment we want to slam the pixmap
		 * to the left of the cliping area.
		 */
		x = clip->x;
		break;
	    case XmALIGNMENT_CENTER:
	    default:
		/*
		 * For this alignment we want to center the pixmap
		 * in the cliping area.
		 */
		x = clip->x + ((int)clip->width - pix_width)/ 2;
		break;
	    case XmALIGNMENT_END:
		/*
		 * for this alignment we want to slam the pixmap
		 * to the right of the cliping area.
		 */
		x = clip->x + (int)clip->width - pix_width;
		break;
	    }
	    
	    /*
	     * Since the pixmap will affect the amount of vertical
	     * space that I have to place my text lets calculate
	     * what space I have left over (if any) for my text.
	     */
	    if( (tmp = (int)draw.height - (pix_height + spacing)) < 0 )
	    {
		draw.height = 0;
	    }
	    else
	    {
		draw.height = tmp;
	    }

	    /*
	     * OK now that we know how we want this pixmap positioned
	     * horizontally lets see what we want to do with it
	     * vertically.  If we have no label then just center it.
	     */
	    if( info->label_string == NULL )
	    {
		y = clip->y + ((int)clip->height - pix_height)/2;
	    }
	    else
	    {
		switch( info->pixmap_placement )
		{
		case XmPIXMAP_TOP:
		default:
		    y = clip->y;
		    draw.y = y + pix_height + spacing;
		    break;
		case XmPIXMAP_BOTTOM:
		    y = clip->y + (int)clip->height - pix_height;
		    break;
		case XmPIXMAP_ONLY:
		    y = clip->y + ((int)clip->height - pix_height)/2;
		    break;
		}
	    }
	    break;
	case XmPIXMAP_LEFT:
	case XmPIXMAP_RIGHT:
	    /*
	     * For this case we want to slam the pixmap to the
	     * left of the clipping area and center it in the
	     * vertical space.
	     */
	    if( info->label_string == NULL )
	    {
		x = clip->x + ((int)clip->width - pix_width)/2;
	    }
	    else
	    {
		switch( info->pixmap_placement )
		{
		case XmPIXMAP_LEFT:
		    x = clip->x;
		    draw.x = x + pix_width + spacing;
		    break;
		case XmPIXMAP_RIGHT:
		    x = clip->x + (int)clip->width - pix_width;
		    break;
		default:
		    break;
		}
	    }
	    y = clip->y + ((int)clip->height - pix_height)/2;

	    /*
	     * Since the pixmap will affect the amount of vertical
	     * space that I have to place my text lets calculate
	     * what space I have left over (if any) for my text.
	     */
	    if( (tmp = (int)draw.width - (pix_width + spacing)) < 0 )
	    {
		draw.width = 0;
	    }
	    else
	    {
		draw.width = tmp;
	    }
	    break;
	case XmPIXMAP_NONE:
	    /* notreached */
	    break;
	}
    }

    /*
     * Now that we know where we are going to draw the pixmap, lets
     * go ahead and draw the bloody thing.  We do a quick check here
     * to see if we are dealing with a bitmap or a pixmap to
     * see if we should be copying a plane or and area.  Also be sure
     * to to an XCopyArea if the depth of the pixmap matches the
     * depth of the canvas.
     */
    if( ValidPixmap(info->label_pixmap) &&
       info->pixmap_placement != XmPIXMAP_NONE )
    {
	if( pix_depth == 1 )
	{
	    XCopyPlane(XtDisplay(tab), info->label_pixmap,
		       XiCanvas(tab), gc, 0, 0, pix_width, pix_height,
		       x, y, 1);
	}
	else if( pix_depth == XmTabBox__canvas(tab)->core.depth )
	{
	    XCopyArea(XtDisplay(tab), info->label_pixmap,
		      XiCanvas(tab), gc, 0, 0, pix_width, pix_height,
		      x, y);
	}
    }
    if( !sensitive )
    {
	/*
	 * Since we are working with a non-sensitve tab, then we need to
	 * stipple the the pixmap, and the only way to do that is
	 * to copy a chess board pattern (the gray stipple) over the pixmap
	 * we just drew.
	 */
	SetStippledGC(XtDisplay(tab), tab->manager.background_GC,
		      XmTabBox__gray_stipple(tab));
	XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
		       tab->manager.background_GC, x, y, pix_width,
		       pix_height);
	RemoveStipple(XtDisplay(tab), tab->manager.background_GC);
    }

    /*
     * Now that we are done drawing the pixmap (if we have one) we
     * need to draw the textual label (if we have one).
     */
    if( have_label )
    {
	/*
	 * First if we have a pixmap we need to reset our clipping
	 * area to account for the space the pixmap took up.
	 */
	if( have_pixmap )
	{
	    XSetClipRectangles(XtDisplay(tab), gc, 0, 0, &draw, 1,
			       YXBanded);
	}

	/*
	 * Now that we know the rectangle that we are going to
	 * draw the text in lets calculate that x and y position
	 * at which we are going to draw the text.  For text it is
	 * real easy we are always going to center the text in the
	 * vertical space and align it according to the alignment
	 * specfified.
	 */
	y = draw.y + ((int)draw.height - label_height)/2;

	/*
	 * Now that we know where the text is going to go, lets
	 * go ahead and draw it.
	 */

	if( !sensitive )
	{
#ifndef FIX_1381
	    SetStippledGC(XtDisplay(tab), gc, XmTabBox__gray_stipple(tab));
#else
	  /*Draw shadow for insensitive text*/
	  SetRightGC(tab, gc, shadow);
	  XmStringDraw(XtDisplay(tab), XiCanvas(tab), font_list,
	  	info->label_string, gc, draw.x+1, (Position)y+1, draw.width,
	  	info->label_alignment, info->string_direction,
	  	NULL);
	  SetRightGC(tab, gc, insensitive);
#endif
	}
	else
	{
#ifndef FIX_1381
	    RemoveStipple(XtDisplay(tab), gc);
#else
	  SetRightGC(tab, gc, normal);
#endif
	}
	XmStringDraw(XtDisplay(tab), XiCanvas(tab), font_list,
		     info->label_string, gc, draw.x, (Position)y, draw.width,
		     info->label_alignment, info->string_direction,
		     NULL);
    }
}
    
/*
 * Function:
 *	DrawRightToLeftTab(tab, info, gc, have_pixmap, pix_width, pix_height,
 *			   pix_depth, have_label, label_width, label_height,
 *			   clip);
 * Description:
 *	Draw the pixmap and text for a tab withing the clipping rectangle
 *	passed in as "clip".
 * Input:
 *	tab          : XmTabBoxWidget - the tab box that drawing
 *	gc           : GC             - the GC to draw with
 *	have_pixmap  : Boolean        - do we need to draw a pixmap ?
 *	pix_width,
 *      pix_height,
 *      pix_depth    : int            - pixmap information
 *	have_label   : Boolean        - do we need to draw a label string ?
 *	label_width,
 *	label_height : int            - label string information
 *	clip         : XRectangle*    - the clip rectangle to draw into
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
DrawRightToLeftTab(XmTabBoxWidget tab, XmTabAttributes info, GC gc,
		   Boolean have_pixmap, int pix_width, int pix_height,
		   int pix_depth, Boolean have_label, int label_width,
		   int label_height, XRectangle *clip, Boolean selected)
{
    XRectangle draw;
    XmFontList font_list = XmTabBox_font_list(tab);
    int        x, y, tmp, spacing = XmTabBox_tab_label_spacing(tab);
    XImage     *src_ximage, *dst_ximage;
    Pixmap     bitmap;
    Boolean    sensitive;

    x = draw.x = clip->x;
    y = draw.y = clip->y;
    draw.width = clip->width;
    draw.height = clip->height;
    sensitive = XtIsSensitive((Widget)tab) && info->sensitive;

    /*
     * First lets check if we have a pixmap to draw and if we do
     * lets rotate and draw it.
     */
    if( have_pixmap )
    {
	/*
	 * We do have a pixmap so we will start by rotating the pixmap
	 * to the correct orientation.
	 */
	src_ximage = NULL;
	if( !XmTabBox_use_image_cache(tab) ||
	    (dst_ximage = CachePixmap(tab,info)) == NULL )
	{
	    src_ximage = XGetImage(XtDisplay(tab), info->label_pixmap,
				   0, 0, pix_width, pix_height,
				   AllPlanes, XYPixmap);
	    dst_ximage = XiRotateImage(tab, src_ximage,
				    XiTabDegree(XmTabBox_tab_orientation(tab)));
	    if( XmTabBox_use_image_cache(tab) )
	    {
		CachePixmap(tab,info) = dst_ximage;
	    }
	}

	/*
	 * Now that we have the rotated image lets snarf the width and height
	 * back into local cache.
	 */
	pix_width = XImageWidth(dst_ximage);
	pix_height = XImageHeight(dst_ximage);

	/*
	 * Now lets look at the pixmap placement to determine where we want
	 * to place the pixmap.
	 */
	switch( info->pixmap_placement )
	{
	case XmPIXMAP_TOP:
	case XmPIXMAP_BOTTOM:
	case XmPIXMAP_ONLY:
	default:
	    /*
	     * Now that we have rotate the ximage lets cache the width
	     * and hieght of that image away for use.
	     */
	    pix_width = XImageWidth(dst_ximage);
	    pix_height = XImageHeight(dst_ximage);

	    /*
	     * In these cases we want to look at the alignment of the
	     * tab to determine where we want to place the pixmap
	     * vertically.
	     */
	    switch( info->label_alignment )
	    {
	    case XmALIGNMENT_BEGINNING:
		/*
		 * For this alignement we want to slam the pixmap
		 * to the top of the clipping area.
		 */
		x = clip->x + (int)clip->width - pix_width;
		break;
	    case XmALIGNMENT_CENTER:
	    default:
		/*
		 * For this case we want to center the pixmap in
		 * the vertical space.
		 */
		x = clip->x + ((int)clip->width - pix_width)/2;
		break;
	    case XmALIGNMENT_END:
		/*
		 * For this alignment we want to slam the pixmap
		 * to the bottom of the clipping area.
		 */
		x = clip->x;
		break;
	    }

	    /*
	     * Since the pixmap will affect the amount of vertical
	     * space to place the text lets calculate what space is
	     * left for the text.
	     */
	    if( (tmp = (int)draw.height - (pix_height + spacing)) < 0 )
	    {
		draw.height = 0;
	    }
	    else
	    {
		draw.height = tmp;
	    }

	    /*
	     * Ok now that we have positioned the pixmap horizontally
	     * lets see what we want to do with it vertically.  If
	     * we have not label then center it.
	     */
	    if( info->label_string == NULL )
	    {
		y = clip->y + ((int)clip->height - pix_height)/2;
	    }
	    else
	    {
		switch( info->pixmap_placement )
		{
		case XmPIXMAP_TOP:
		default:
		    y = clip->y + (int)clip->height - pix_height;
		    break;
		case XmPIXMAP_BOTTOM:
		    y = clip->y;
		    draw.y = y+ pix_height + spacing;
		    break;
		case XmPIXMAP_ONLY:
		    y = clip->y + ((int)clip->height - pix_height)/2;
		    break;
		}
	    }
	    break;
	case XmPIXMAP_LEFT:
	case XmPIXMAP_RIGHT:
	    /*
	     * For this case we want to slam the pixmap to either the
	     * top or bottom of the clipping area and center it in
	     * the horizontal space.
	     */
	    if( info->label_string == NULL )
	    {
		x = clip->x + ((int)clip->width - pix_width)/2;
	    }
	    else
	    {
		switch( info->pixmap_placement )
		{
		case XmPIXMAP_LEFT:
		    x = clip->x + (int)clip->width - pix_width;
		    break;
		case XmPIXMAP_RIGHT:
		    x = clip->x;
		    draw.x = x + pix_width + spacing;
		    break;
		default:
		    break;
		}
	    }
	    y = clip->y + ((int)clip->height - pix_width)/2;

	    /*
	     * Since the pixmap will affect the amount of 
	     * vertical space that the text will have lets
	     * calculate what space is left.
	     */
	    if( (tmp = (int)draw.width - (pix_width + spacing)) < 0 )
	    {
		draw.width = 0;
	    }
	    else
	    {
		draw.width = tmp;
	    }
	    break;
	case XmPIXMAP_NONE:
	    /* notreached */
	    break;
	}

	/*
	 * Now that we know where the image is supposed to go, lets 
	 * draw the thing.
	 */
	XPutImage(XtDisplay(tab), XiCanvas(tab), gc, dst_ximage, 0, 0,
		  x, y, pix_width, pix_height);

	if( !sensitive )
	{
	    /*
	     * Since we are working with a non-sensitive tab, then we need to
	     * stipple the the pixmap, and the only way to do that is
	     * to copy a chess board pattern (the gray stipple) over the pixmap
	     * we just drew.
	     */
	    SetStippledGC(XtDisplay(tab), tab->manager.background_GC,
			  XmTabBox__gray_stipple(tab));
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
			   tab->manager.background_GC, x, y, pix_width,
			   pix_height);
	    RemoveStipple(XtDisplay(tab), tab->manager.background_GC);
	}

	/*
	 * We are done with the XImages now so lets destroy the
	 * ximages we used to rotate the pixmap.
	 */
	if( src_ximage != NULL ) XDestroyImage(src_ximage);
	if( !XmTabBox_use_image_cache(tab) && dst_ximage != NULL )
	{
	    XDestroyImage(dst_ximage);
	}
    }

    /*
     * Now that we have drawn the pixmap it is time to deal with the
     * label string.
     */
    if( !have_label || info->label_string == NULL ) return;

    /*
     * If we have a pixmap then the clipping area was modified so
     * we need to set the clip rectangle to that for the text.
     */
    if( have_pixmap )
    {
	XSetClipRectangles(XtDisplay(tab), gc, 0, 0, &draw, 1, YXBanded);
    }

    /*
     * Now we have to render and rotate the label string.  To do this
     * we need to first set up a few things like the pixmap to render
     * into and GC used to draw into a bitmap.  We will start by
     * making sure that we have a pixmap large enough to 
     * accomidate the string we are about to render.
     */
    src_ximage = NULL;
    if( !XmTabBox_use_image_cache(tab) ||
    	(sensitive != CacheSensitive(tab,info)) ||
        (dst_ximage = CacheLabel(tab, info)) == NULL )
    {
	if( ValidPixmap(XmTabBox__bitmap(tab)) &&
	   (XmTabBox__bitmap_width(tab) < label_width ||
	    XmTabBox__bitmap_height(tab) < label_height) )
	{
	    /*
	     * As it turns out our pixmap is not large enough to 
	     * hold the rendered text. So we will destroy the
	     * current pixmap so that we will allocate a pixmap
	     * of the correct size below.
	     */
	    XFreePixmap(XtDisplay(tab), XmTabBox__bitmap(tab));
	    XmTabBox__bitmap(tab) = XmUNSPECIFIED_PIXMAP;
	}

	/*
	 * If we do not have a bitmap to render the text into
	 * lets create one now.
	 */
	if( !ValidPixmap(XmTabBox__bitmap(tab)) )
	{
	    XmTabBox__bitmap(tab) = XCreatePixmap(XtDisplay(tab), XiCanvas(tab),
#ifndef FIX_1381
						 label_width, label_height, 1);
#else
					 label_width, label_height, XmTabBox__canvas(tab)->core.depth);
#endif

	    XmTabBox__bitmap_width(tab) = label_width;
	    XmTabBox__bitmap_height(tab) = label_height;
	}
	bitmap = XmTabBox__bitmap(tab);

	/*
	 * Now that we have a bitmap to render the text into lets make sure
	 * that we have GC that we can use to render the text.  We need two
	 * GC, one to clear the pixmap the other to draw into it.
	 */
	if( XmTabBox__zero_GC(tab) == NULL )
	{
	    /*
	     * We do not yet have either of the GC created so lets go
	     * ahead and create them now.
	     */
	    XFontStruct *font = NULL;
	    XGCValues   gcValues;
	    unsigned long gcMask;

#ifndef FIX_1381
	    gcValues.foreground = 0;
	    gcValues.background = 0;
#else
	    gcValues.background = tab->core.background_pixel;
	    gcValues.foreground = tab->core.background_pixel;
#endif
	    XmTabBox__zero_GC(tab) = XCreateGC(XtDisplay(tab), bitmap,
					      GCForeground | GCBackground,
					      &gcValues);
	    
	    XmeRenderTableGetDefaultFont(font_list, &font);
	    gcValues.foreground = 1;
	    gcValues.background = 0;
	    gcMask = GCForeground | GCBackground;
	    if (font) {
	        gcValues.font = font->fid;
	        gcMask |= GCFont;
	    }
	    XmTabBox__one_GC(tab) = XCreateGC(XtDisplay(tab), bitmap, gcMask,
	                                      &gcValues);
	}

	/*
	 * Now we have all that we need to render the label string, so now
	 * lets do it.  What we need to do if first zero the pixmap and
	 * then render the text.
	 */
	XFillRectangle(XtDisplay(tab), bitmap, XmTabBox__zero_GC(tab),
		       0, 0, label_width, label_height);
	if( !sensitive )
	{
#ifndef FIX_1381
	    SetStippledGC(XtDisplay(tab), XmTabBox__one_GC(tab),
			  XmTabBox__gray_stipple(tab));
#else
	  /*Draw shadow for insensitive text*/
	  SetRightGC(tab, XmTabBox__one_GC(tab), shadow);
	  XmStringDraw(XtDisplay(tab), bitmap, font_list, info->label_string,
	  XmTabBox__one_GC(tab), -1, -1, (Dimension)label_width,
	  info->label_alignment, info->string_direction, NULL);
	  SetRightGC(tab, XmTabBox__one_GC(tab), insensitive);
#endif
	}
	else
	{
#ifndef FIX_1381
	    RemoveStipple(XtDisplay(tab), XmTabBox__one_GC(tab));
#else
	  SetRightGC(tab, XmTabBox__one_GC(tab), normal);
#endif
	}
	XmStringDraw(XtDisplay(tab), bitmap, font_list, info->label_string,
		     XmTabBox__one_GC(tab), 0, 0, (Dimension)label_width,
		     info->label_alignment, info->string_direction, NULL);

	/*
	 * Now that the label string is rendered we need to grab it back
	 * into an XImage so that we can rotate it.
	 */
	src_ximage = XGetImage(XtDisplay(tab), bitmap, 0, 0, label_width, 
#ifndef FIX_1381
			       label_height, 1, XYPixmap);
#else
				label_height, AllPlanes, XYPixmap);
#endif
	dst_ximage = XiRotateImage(tab, src_ximage,
				   XiTabDegree(XmTabBox_tab_orientation(tab)));

	if( XmTabBox_use_image_cache(tab) )
	{
	    CacheLabel(tab, info) = dst_ximage;
	    CacheSensitive(tab,info) = sensitive;
	}
    }

    /*
     * Now that the text is rotated lets snarf the label width and height
     * back from the image.
     */
    label_width = XImageWidth(dst_ximage);
    label_height = XImageHeight(dst_ximage);

    /*
     * Now we need to find out where we want to but the text.  We know that
     * we want to center the text in the horizontal space that we have left,
     * then we want to use the alignment value to determine what to
     * do with the vertical space.
     */
    y = draw.y + ((int)draw.height - label_height)/2;
    
    switch( info->label_alignment )
    {
    case XmALIGNMENT_BEGINNING:
	/*
	 * Here we want to slam the text to the top of the clipping
	 * area.
	 */
	x = draw.x + (int)draw.width - label_width;
	break;
    case XmALIGNMENT_CENTER:
    default:
	/*
	 * Here we want to center the text in the clipping area.
	 */
	x = draw.x + ((int)draw.width - label_width)/2;
	break;
    case XmALIGNMENT_END:
	/*
	 * Here we want to slam the text to the bottom of the
	 * clipping area.
	 */
	x = draw.x;
	break;
    }

    /*
     * Now that we know where we want the text lets push that
     * XImage over the wire.  But first we need to check if we should
     * mask out the text so that the background pixmap show through.
     */
    if( ValidPixmap(tab->core.background_pixmap) ||
        XiBackgroundSpecified(info) ||
        (selected && XiSelectSpecified(tab)) )
    {
	/*
	 * It appears that we have a background pixmap so what we
	 * want to do is set the clip mask such that we only draw the
	 * text and not the rectangle around it.
	 *
	 * What we are going to do is create a bitmap and draw the text
	 * into this pixmap to create a GC clipping mask.
	 */
	Pixmap pix = XCreatePixmap(XtDisplay(tab),
				   (XtIsRealized((Widget)tab) 
				    ? XtWindow(tab)
				    : RootWindowOfScreen(XtScreen(tab))),
				   label_width, label_height, 1);

	/*
	 * Left first clear out the clipping mask and then draw the text
	 * into it.
	 */
	XFillRectangle(XtDisplay(tab), pix, XmTabBox__zero_GC(tab), 0, 0,
		       label_width, label_height);
	XPutImage(XtDisplay(tab), pix, XmTabBox__one_GC(tab), dst_ximage, 0, 0,
		  0, 0, label_width, label_height);

	/*
	 * Now that we have the clipping mask lets set the mask to the GC
	 * and then put the image that is the text to the display using this
	 * clipping mask.
	 */
	XSetClipMask(XtDisplay(tab), gc, pix);
	XSetClipOrigin(XtDisplay(tab), gc, x, y);
	XPutImage(XtDisplay(tab), XiCanvas(tab), gc, dst_ximage, 0, 0,
		  x, y, label_width, label_height);

	/*
	 * We are done with this cliping mask so lets destroy the pixmap.
	 */
	XFreePixmap(XtDisplay(tab), pix);
    }
    else
    {
	XPutImage(XtDisplay(tab), XiCanvas(tab), gc, dst_ximage, 0, 0,
		  x, y, label_width, label_height);
    }

    /*
     * Now that we are done with the XImages used for rotating the
     * text lets delete them.
     */
    if( src_ximage != NULL ) XDestroyImage(src_ximage);
    if( !XmTabBox_use_image_cache(tab) && dst_ximage != NULL )
    {
	XDestroyImage(dst_ximage);
    }
}

/*
 * Function:
 *	DrawBottomToTopTab(tab, info, gc, have_pixmap, pix_width, pix_height,
 *			   pix_depth, have_label, label_width, label_height,
 *			   clip);
 * Description:
 *	Draw the pixmap and text for a tab withing the clipping rectangle
 *	passed in as "clip".
 * Input:
 *	tab          : XmTabBoxWidget - the tab box that drawing
 *	gc           : GC             - the GC to draw with
 *	have_pixmap  : Boolean        - do we need to draw a pixmap ?
 *	pix_width,
 *      pix_height,
 *      pix_depth    : int            - pixmap information
 *	have_label   : Boolean        - do we need to draw a label string ?
 *	label_width,
 *	label_height : int            - label string information
 *	clip         : XRectangle*    - the clip rectangle to draw into
 * Output:
 *	None.
 */
static void
DrawBottomToTopTab(XmTabBoxWidget tab, XmTabAttributes info, GC gc,
		   Boolean have_pixmap, int pix_width, int pix_height,
		   int pix_depth, Boolean have_label, int label_width,
		   int label_height, XRectangle *clip, Boolean selected)
{
    DrawVerticalTab(tab, info, gc, have_pixmap, pix_width, pix_height,
		    pix_depth, have_label, label_width, label_height, clip,
		    False, selected);
}

/*
 * Function:
 *	DrawTopToBottomTab(tab, info, gc, have_pixmap, pix_width, pix_height,
 *			   pix_depth, have_label, label_width, label_height,
 *			   clip);
 * Description:
 *	Draw the pixmap and text for a tab withing the clipping rectangle
 *	passed in as "clip".
 * Input:
 *	tab          : XmTabBoxWidget - the tab box that drawing
 *	gc           : GC             - the GC to draw with
 *	have_pixmap  : Boolean        - do we need to draw a pixmap ?
 *	pix_width,
 *      pix_height,
 *      pix_depth    : int            - pixmap information
 *	have_label   : Boolean        - do we need to draw a label string ?
 *	label_width,
 *	label_height : int            - label string information
 *	clip         : XRectangle*    - the clip rectangle to draw into
 * Output:
 *	None.
 */
static void

DrawTopToBottomTab(XmTabBoxWidget tab, XmTabAttributes info, GC gc,
		   Boolean have_pixmap, int pix_width, int pix_height,
		   int pix_depth, Boolean have_label, int label_width,
		   int label_height, XRectangle *clip, Boolean selected)
{
    DrawVerticalTab(tab, info, gc, have_pixmap, pix_width, pix_height,
		    pix_depth, have_label, label_width, label_height, clip,
		    True, selected);
}

/*
 * Function:
 *	DrawVerticalTab(tab, info, gc, have_pixmap, pix_width, pix_height,
 *			pix_depth, have_label, label_width, label_height,
 *			clip, top_to_bottom);
 * Description:
 *	Draw the pixmap and text for a tab withing the clipping rectangle
 *	passed in as "clip".
 * Input:
 *	tab          : XmTabBoxWidget - the tab box that drawing
 *	gc           : GC             - the GC to draw with
 *	have_pixmap  : Boolean        - do we need to draw a pixmap ?
 *	pix_width,
 *      pix_height,
 *      pix_depth    : int            - pixmap information
 *	have_label   : Boolean        - do we need to draw a label string ?
 *	label_width,
 *	label_height : int            - label string information
 *	clip         : XRectangle*    - the clip rectangle to draw into
 *	top_to_bottom : Boolean       - drawing top to bottom(True) or
 *				        bottom to top(False)
 * Output:
 *	None.
 */
/* ARGSUSED */
static void
DrawVerticalTab(XmTabBoxWidget tab, XmTabAttributes info, GC gc,
		Boolean have_pixmap, int pix_width, int pix_height,
		int pix_depth, Boolean have_label, int label_width,
		int label_height, XRectangle *clip, Boolean top_to_bottom,
		Boolean selected)
{
    XRectangle draw;
    XmFontList font_list = XmTabBox_font_list(tab);
    int        x, y, tmp, spacing = XmTabBox_tab_label_spacing(tab);
    XImage     *src_ximage, *dst_ximage;
    Pixmap     bitmap;
    Boolean    sensitive;

    x = draw.x = clip->x;
    y = draw.y = clip->y;
    draw.width = clip->width;
    draw.height = clip->height;
    sensitive = XtIsSensitive((Widget)tab) && info->sensitive;

    /*
     * First lets check if we have a pixmap to draw and if we do
     * lets rotate and draw it.
     */
    if( have_pixmap )
    {
	/*
	 * We do have a pixmap so we will start by rotating the pixmap
	 * to the correct orientation.
	 */
	src_ximage = NULL;
	if( !XmTabBox_use_image_cache(tab) ||
	    (dst_ximage = CachePixmap(tab,info)) == NULL )
	{
	    src_ximage = XGetImage(XtDisplay(tab), info->label_pixmap,
				   0, 0, pix_width, pix_height,
				   AllPlanes, XYPixmap);
	    dst_ximage = XiRotateImage(tab, src_ximage,
				  XiTabDegree(XmTabBox_tab_orientation(tab)));
	    
	    if( XmTabBox_use_image_cache(tab) )
	    {
		CachePixmap(tab,info) = dst_ximage;
	    }
	}

	/*
	 * Now that we have the rotated image lets snarf the width and height
	 * back into local cache.
	 */
	pix_width = XImageWidth(dst_ximage);
	pix_height = XImageHeight(dst_ximage);

	/*
	 * Now lets look at the pixmap placement to determine where we want
	 * to place the pixmap.
	 */
	switch( info->pixmap_placement )
	{
	case XmPIXMAP_TOP:
	case XmPIXMAP_BOTTOM:
	case XmPIXMAP_ONLY:
	default:
	    /*
	     * Now that we have rotate the ximage lets cache the width
	     * and hieght of that image away for use.
	     */
	    pix_width = XImageWidth(dst_ximage);
	    pix_height = XImageHeight(dst_ximage);

	    /*
	     * In these cases we want to look at the alignment of the
	     * tab to determine where we want to place the pixmap
	     * vertically.
	     */
	    switch( info->label_alignment )
	    {
	    case XmALIGNMENT_BEGINNING:
		/*
		 * For this alignement we want to slam the pixmap
		 * to the top of the clipping area.
		 */
		if( top_to_bottom )
		{
		    y = clip->y;
		}
		else
		{
		    y = clip->y + (int)clip->height - pix_height;
		}
		break;
	    case XmALIGNMENT_CENTER:
	    default:
		/*
		 * For this case we want to center the pixmap in
		 * the vertical space.
		 */
		y = clip->y + ((int)clip->height - pix_height)/2;
		break;
	    case XmALIGNMENT_END:
		/*
		 * For this alignment we want to slam the pixmap
		 * to the bottom of the clipping area.
		 */
		if( top_to_bottom )
		{
		    y = clip->y + (int)clip->height - pix_height;
		}
		else
		{
		    y = clip->y;
		}
		break;
	    }

	    /*
	     * Since the pixmap will affect the amount of horizontal
	     * space to place the text lets calculate what space is
	     * left for the text.
	     */
	    if( (tmp = (int)draw.width - (pix_width + spacing)) < 0 )
	    {
		draw.width = 0;
	    }
	    else
	    {
		draw.width = tmp;
	    }

	    /*
	     * Ok now that we have positioned the pixmap vertically
	     * lets see what we want to do with it horizontally.  If
	     * we have not label then center it.
	     */
	    if( info->label_string == NULL )
	    {
		x = clip->x + ((int)clip->width - pix_width)/2;
	    }
	    else
	    {
		switch( info->pixmap_placement )
		{
		case XmPIXMAP_TOP:
		default:
		    if( top_to_bottom )
		    {
			x = clip->x + (int)clip->width - pix_width;
		    }
		    else
		    {
			x = clip->x;
			draw.x = x + pix_width + spacing;
		    }
		    break;
		case XmPIXMAP_BOTTOM:
		    if( top_to_bottom )
		    {
			x = clip->x;
			draw.x = x + pix_width + spacing;
		    }
		    else
		    {
			x = clip->x + (int)clip->width - pix_width;
		    }
		    break;
		case XmPIXMAP_ONLY:
		    x = clip->x + ((int)clip->width - pix_width)/2;
		    break;
		}
	    }
	    break;
	case XmPIXMAP_LEFT:
	case XmPIXMAP_RIGHT:
	    /*
	     * For this case we want to slam the pixmap to either the
	     * top or bottom of the clipping area and center it in
	     * the horizontal space.
	     */
	    if( info->label_string == NULL )
	    {
		y = clip->y + ((int)clip->height - pix_height)/2;
	    }
	    else
	    {
		switch( info->pixmap_placement )
		{
		case XmPIXMAP_LEFT:
		    if( top_to_bottom )
		    {
			y = clip->y;
			draw.y = y + pix_height + spacing;
		    }
		    else
		    {
			y = clip->y + (int)clip->height - pix_height;
		    }
		    break;
		case XmPIXMAP_RIGHT:
		    if( top_to_bottom )
		    {
			y = clip->y + (int)clip->height - pix_height;
		    }
		    else
		    {
			y = clip->y;
			draw.y = y + pix_height + spacing;
		    }
		    break;
		default:
		    break;
		}
	    }
	    x = clip->x + ((int)clip->width - pix_width)/2;

	    /*
	     * Since the pixmap will affect the amount of 
	     * vertical space that the text will have lets
	     * calculate what space is left.
	     */
	    if( (tmp = (int)draw.height - (pix_height + spacing)) < 0 )
	    {
		draw.height = 0;
	    }
	    else
	    {
		draw.height = tmp;
	    }
	    break;
	case XmPIXMAP_NONE:
	    /* notreached */
	    break;
	}

	/*
	 * Now that we know where the image is supposed to go, lets 
	 * draw the thing.
	 */
	XPutImage(XtDisplay(tab), XiCanvas(tab), gc, dst_ximage, 0, 0,
		  x, y, pix_width, pix_height);

	if( !sensitive )
	{
	    /*
	     * Since we are working with a non-sensitive tab, then we need to
	     * stipple the the pixmap, and the only way to do that is
	     * to copy a chess board pattern (the gray stipple) over the pixmap
	     * we just drew.
	     */
	    SetStippledGC(XtDisplay(tab), tab->manager.background_GC,
			  XmTabBox__gray_stipple(tab));
	    XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
			   tab->manager.background_GC, x, y, pix_width,
			   pix_height);
	    RemoveStipple(XtDisplay(tab), tab->manager.background_GC);
	}

	/*
	 * We are done with the XImages now so lets destroy the
	 * ximages we used to rotate the pixmap.
	 */
	if( src_ximage != NULL ) XDestroyImage(src_ximage);
	if( !XmTabBox_use_image_cache(tab) && dst_ximage != NULL )
	{
	    XDestroyImage(dst_ximage);
	}
    }

    /*
     * Now that we have drawn the pixmap it is time to deal with the
     * label string.
     */
    if( !have_label || info->label_string == NULL ) return;

    /*
     * If we have a pixmap then the clipping area was modified so
     * we need to set the clip rectangle to that for the text.
     */
    if( have_pixmap )
    {
	XSetClipRectangles(XtDisplay(tab), gc, 0, 0, &draw, 1, YXBanded);
    }

    src_ximage = NULL;
    if( !XmTabBox_use_image_cache(tab) ||
    	(sensitive != CacheSensitive(tab,info)) ||
        (dst_ximage = CacheLabel(tab, info)) == NULL )
    {
	/*
	 * Now we have to render and rotate the label string.  To do this
	 * we need to first set up a few things like the pixmap to render
	 * into and GC used to draw into a bitmap.  We will start by
	 * making sure that we have a pixmap large enough to 
	 * accomidate the string we are about to render.
	 */
	if( ValidPixmap(XmTabBox__bitmap(tab)) &&
	   (XmTabBox__bitmap_width(tab) < label_width ||
	    XmTabBox__bitmap_height(tab) < label_height) )
	{
	    /*
	     * As it turns out our pixmap is not large enough to 
	     * hold the rendered text. So we will destroy the
	     * current pixmap so that we will allocate a pixmap
	     * of the correct size below.
	     */
	    XFreePixmap(XtDisplay(tab), XmTabBox__bitmap(tab));
	    XmTabBox__bitmap(tab) = XmUNSPECIFIED_PIXMAP;
	}

	/*
	 * If we do not have a bitmap to render the text into
	 * lets create one now.
	 */
	if( !ValidPixmap(XmTabBox__bitmap(tab)) )
	{
	    XmTabBox__bitmap(tab) = XCreatePixmap(XtDisplay(tab), XiCanvas(tab),
#ifndef FIX_1381
						 label_width, label_height, 1);
#else
						 label_width, label_height, XmTabBox__canvas(tab)->core.depth);
#endif
	    XmTabBox__bitmap_width(tab) = label_width;
	    XmTabBox__bitmap_height(tab) = label_height;
	}
	bitmap = XmTabBox__bitmap(tab);

	/*
	 * Now that we have a bitmap to render the text into lets make sure
	 * that we have GC that we can use to render the text.  We need two
	 * GC, one to clear the pixmap the other to draw into it.
	 */
	if( XmTabBox__zero_GC(tab) == NULL )
	{
	    /*
	     * We do not yet have either of the GC created so lets go
	     * ahead and create them now.
	     */
	    XFontStruct *font = NULL;
	    XGCValues   gcValues;
	    unsigned long gcMask;

#ifndef FIX_1381
	    gcValues.foreground = 0;
	    gcValues.background = 0;
#else
	    gcValues.background = tab->core.background_pixel;
	    gcValues.foreground = tab->core.background_pixel;
#endif
	    XmTabBox__zero_GC(tab) = XCreateGC(XtDisplay(tab), bitmap,
					      GCForeground | GCBackground,
					      &gcValues);
	    
	    XmeRenderTableGetDefaultFont(font_list, &font);
	    gcValues.foreground = 1;
	    gcValues.background = 0;
	    gcMask = GCForeground | GCBackground;
	    if (font) {
	        gcValues.font = font->fid;
		gcMask |= GCFont;
	    }
	    XmTabBox__one_GC(tab) = XCreateGC(XtDisplay(tab), bitmap, gcMask,
	                                      &gcValues);
	}

	/*
	 * Now we have all that we need to render the label string, so now
	 * lets do it.  What we need to do if first zero the pixmap and
	 * then render the text.
	 */
	XFillRectangle(XtDisplay(tab), bitmap, XmTabBox__zero_GC(tab),
		       0, 0, label_width, label_height);
	if( !sensitive )
	{
#ifndef FIX_1381
	    SetStippledGC(XtDisplay(tab), XmTabBox__one_GC(tab),
			  XmTabBox__gray_stipple(tab));
#else
	  /*Draw shadow for insensitive text*/
	  /*text will be rotated below but shadow should be always under the text*/
	  int x,y;
	  if (XmTabBox_tab_orientation(tab)==XmTABS_TOP_TO_BOTTOM){
	    x=1; y=-1;
	  }
	  else
	  {
	    x=-1; y=1;
	  }
	  SetRightGC(tab, XmTabBox__one_GC(tab), shadow);
	  XmStringDraw(XtDisplay(tab), bitmap, font_list, info->label_string,
	  		XmTabBox__one_GC(tab), x, y, (Dimension)label_width,
			info->label_alignment, info->string_direction, NULL);
	  SetRightGC(tab, XmTabBox__one_GC(tab), insensitive);
#endif
	}
	else
	{
#ifndef FIX_1381
	    RemoveStipple(XtDisplay(tab), XmTabBox__one_GC(tab));
#else
	  SetRightGC(tab, XmTabBox__one_GC(tab), normal);
#endif
	}
	XmStringDraw(XtDisplay(tab), bitmap, font_list, info->label_string,
		     XmTabBox__one_GC(tab), 0, 0, (Dimension)label_width,
		     info->label_alignment, info->string_direction, NULL);

	/*
	 * Now that the label string is rendered we need to grab it back
	 * into an XImage so that we can rotate it.
	 */
	src_ximage = XGetImage(XtDisplay(tab), bitmap, 0, 0, label_width, 
#ifndef FIX_1381
			       label_height, 1, XYPixmap);
#else
			       label_height, AllPlanes, XYPixmap);
#endif
	dst_ximage = XiRotateImage(tab, src_ximage,
				   XiTabDegree(XmTabBox_tab_orientation(tab)));

	if( XmTabBox_use_image_cache(tab) )
	{
	    CacheLabel(tab, info) = dst_ximage;
	    CacheSensitive(tab,info) = sensitive;
	}
    }

    /*
     * Now that the text is rotated lets snarf the label width and height
     * back from the image.
     */
    if (dst_ximage)
    {
        label_width = XImageWidth(dst_ximage);
        label_height = XImageHeight(dst_ximage);
    }
    else
    {
        label_width = 0;
        label_height = 0;
    }

    /*
     * Now we need to find out where we want to but the text.  We know that
     * we want to center the text in the horizontal space that we have left,
     * then we want to use the alignment value to determine what to
     * do with the vertical space.
     */
    x = draw.x + ((int)draw.width - label_width)/2;
    
    switch( info->label_alignment )
    {
    case XmALIGNMENT_BEGINNING:
	/*
	 * Here we want to slam the text to the top of the clipping
	 * area.
	 */
	if( top_to_bottom )
	{
	    y = draw.y;
	}
	else
	{
	    y = draw.y + (int)draw.height - label_height;
	}
	break;
    case XmALIGNMENT_CENTER:
    default:
	/*
	 * Here we want to center the text in the clipping area.
	 */
	y = draw.y + ((int)draw.height - label_height)/2;
	break;
    case XmALIGNMENT_END:
	/*
	 * Here we want to slam the text to the bottom of the
	 * clipping area.
	 */
	if( top_to_bottom )
	{
	    y = draw.y + (int)draw.height - label_height;
	}
	else
	{
	    y = draw.y;
	}
	break;
    }

    /*
     * Now that we know where we want the text lets push that
     * XImage over the wire.  But first we need to check if we should
     * mask out the text so that the background pixmap show through.
     */
    if( ValidPixmap(tab->core.background_pixmap) ||
        XiBackgroundSpecified(info) ||
        (selected && XiSelectSpecified(tab)) ) 
    {
	/*
	 * It appears that we have a background pixmap so what we
	 * want to do is set the clip mask such that we only draw the
	 * text and not the rectangle around it.
	 *
	 * What we are going to do is create a bitmap and draw the text
	 * into this pixmap to create a GC clipping mask.
	 */
	Pixmap pix = XCreatePixmap(XtDisplay(tab),
				   (XtIsRealized((Widget)tab)
				    ? XtWindow(tab)
				    : RootWindowOfScreen(XtScreen(tab))),
				   label_width, label_height, 1);

	/*
	 * Left first clear out the clipping mask and then draw the text
	 * into it.
	 */
	XFillRectangle(XtDisplay(tab), pix, XmTabBox__zero_GC(tab), 0, 0,
		       label_width, label_height);
	XPutImage(XtDisplay(tab), pix, XmTabBox__one_GC(tab), dst_ximage, 0, 0,
		  0, 0, label_width, label_height);

	/*
	 * Now that we have the clipping mask lets set the mask to the GC
	 * and then put the image that is the text to the display using this
	 * clipping mask.
	 */
	XSetClipMask(XtDisplay(tab), gc, pix);
	XSetClipOrigin(XtDisplay(tab), gc, x, y);
	XPutImage(XtDisplay(tab), XiCanvas(tab), gc, dst_ximage, 0, 0,
		  x, y, label_width, label_height);

	/*
	 * We are done with this cliping mask so lets destroy the pixmap.
	 */
	XFreePixmap(XtDisplay(tab), pix);
    }
    else
    {
        if (dst_ximage)
            XPutImage(XtDisplay(tab), XiCanvas(tab), gc, dst_ximage, 0, 0,
		  x, y, label_width, label_height);
    }

    /*
     * Now that we are done with the XImages used for rotating the
     * text lets delete them.
     */
    if( src_ximage != NULL ) XDestroyImage(src_ximage);
    if( !XmTabBox_use_image_cache(tab) && dst_ximage != NULL )
    {
	XDestroyImage(dst_ximage);
    }
}

static void

FillRoundedTab(XmTabBoxWidget tab, GC gc, XiTabRect *geometry, XmTabEdge edge)
{
    XRectangle rect[2];
    int        x = geometry->x, y = geometry->y,
               width = geometry->width, height = geometry->height, side;

    side = XmTabBox__corner_size(tab);
    if( width < height )
    {
	AssignMin(side, (width/2));
    }
    else
    {
	AssignMin(side, (height/2));
    }

    switch( edge )
    {
    case XmTAB_EDGE_TOP_LEFT:
    default:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    rect[0].x = x;
	    rect[0].y = y;
	    rect[0].width = width;
	    rect[0].height = height - side;
	    rect[1].x = x + side;
	    rect[1].y = y + height - side;
	    rect[1].width = width - (2 * side);
	    rect[1].height = side;

	    XiFillCorner(XtDisplay(tab), XiCanvas(tab), gc,
			 x, y + height - side, side, side, XiQUAD_3);
	    XiFillCorner(XtDisplay(tab), XiCanvas(tab), gc,
			 x + width - side, y + height - side, side,
			 side, XiQUAD_4);
	}
	else
	{
	    rect[0].x = x;
	    rect[0].y = y;
	    rect[0].width = width - side;
	    rect[0].height = height;
	    rect[1].x = x + width - side;
	    rect[1].y = y + side;
	    rect[1].width = side;
	    rect[1].height = height - (2 * side);

	    XiFillCorner(XtDisplay(tab), XiCanvas(tab), gc,
			 x + width - side, y, side,
			 side, XiQUAD_1);
	    XiFillCorner(XtDisplay(tab), XiCanvas(tab), gc,
			 x + width - side, y + height - side, side,
			 side, XiQUAD_4);
	}
        break;
    case XmTAB_EDGE_BOTTOM_RIGHT:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    rect[0].x = x;
	    rect[0].y = y + side;
	    rect[0].width = width;
	    rect[0].height = height - side;
	    rect[1].x = x + side;
	    rect[1].y = y;
	    rect[1].width = width - (2 * side);
	    rect[1].height = side;

	    XiFillCorner(XtDisplay(tab), XiCanvas(tab), gc,
			 x + width - side, y, side,
			 side, XiQUAD_1);
	    XiFillCorner(XtDisplay(tab), XiCanvas(tab), gc, x, y, side,
			 side, XiQUAD_2);
	}
	else
	{
	    rect[0].x = x + side;
	    rect[0].y = y;
	    rect[0].width = width - side;
	    rect[0].height = height;
	    rect[1].x = x;
	    rect[1].y = y + side;
	    rect[1].width = side;
	    rect[1].height = height - (2 * side);

	    XiFillCorner(XtDisplay(tab), XiCanvas(tab), gc, x, y, side,
			 side, XiQUAD_2);
	    XiFillCorner(XtDisplay(tab), XiCanvas(tab), gc,
			 x, y + height - side, side, side, XiQUAD_3);
	}
	break;
    }

    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, 2);
}

static void
FillBeveledTab(XmTabBoxWidget tab, GC gc, XiTabRect *geometry, XmTabEdge edge)
{
    XPoint pt[6];
    int    x = geometry->x, y = geometry->y,
           width = geometry->width, height = geometry->height, side;

    side = XmTabBox__corner_size(tab);
    if( width < height )
    {
	AssignMin(side, (width/2));
    }
    else
    {
	AssignMin(side, (height/2));
    }

    switch( edge )
    {
    case XmTAB_EDGE_TOP_LEFT:
    default:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    pt[0].x = x;
	    pt[0].y = y;
	    pt[1].x = x;
	    pt[1].y = y + height - side;
	    pt[2].x = x + side;
	    pt[2].y = y + height;
	    pt[3].x = x + width - side;
	    pt[3].y = y + height;
	    pt[4].x = x + width;
	    pt[4].y = y + height - side;
	    pt[5].x = x + width;
	    pt[5].y = y;
	}
	else
	{
	    pt[0].x = x;
	    pt[0].y = y;
	    pt[1].x = x + width - side;
	    pt[1].y = y;
	    pt[2].x = x + width;
	    pt[2].y = y + side;
	    pt[3].x = x + width;
	    pt[3].y = y + height - side;
	    pt[4].x = x + width - side;
	    pt[4].y = y + height;
	    pt[5].x = x;
	    pt[5].y = y + height;
	}
	break;
    case XmTAB_EDGE_BOTTOM_RIGHT:
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    pt[0].x = x;
	    pt[0].y = y + height;
	    pt[1].x = x;
	    pt[1].y = y + side;
	    pt[2].x = x + side;
	    pt[2].y = y;
	    pt[3].x = x + width - side;
	    pt[3].y = y;
	    pt[4].x = x + width;
	    pt[4].y = y + side;
	    pt[5].x = x + width;
	    pt[5].y = y + height;
	}
	else
	{
	    pt[0].x = x + width;
	    pt[0].y = y + height;
	    pt[1].x = x + side;
	    pt[1].y = y + height;
	    pt[2].x = x;
	    pt[2].y = y + height - side;
	    pt[3].x = x;
	    pt[3].y = y + side;
	    pt[4].x = x + side;
	    pt[4].y = y;
	    pt[5].x = x + width;
	    pt[5].y = y;
	}
	break;
    }
    XFillPolygon(XtDisplay(tab), XiCanvas(tab), gc, pt, 6, Nonconvex,
		 CoordModeOrigin);
}

int
XmTabBoxGetIndex(Widget widget, int x, int y)
{
    return( XiXYtoTab((XmTabBoxWidget)widget, x, y) );
}

static void
CalcStackedGeometry(XmTabBoxWidget tab, XRectangle *rect)
{
    XmTabbedStackList       list = XmTabBox_tab_list(tab);
    XmTabAttributes info;
    int             i, count = _XmTabbedStackListCount(list),
                    max_width, max_height,
                    tab_width, tab_height,
                    num_stacks = XmTabBox_num_stacks(tab);
    Dimension       d_width, d_height;
    /*
     * Calculating the geometry we want for the stack layout turns
     * out to be straight forward.  What we do is find calculate the
     * size of the largest tab and then use that to calculate the
     * geometry we want.
     */
    max_width = max_height = 0;
    for( i = 0; i < count; ++i )
    {
	info = _XmTabbedStackListGet(list, i);
	XiCalcTabSize(tab, info, &d_width, &d_height);
	AssignMax(max_width, (int)d_width);
	AssignMax(max_height, (int)d_height);

	XmTabBox__wanted(tab)[i].width = d_width;
	XmTabBox__wanted(tab)[i].height = d_height;
    }

    /*
     * Since we are in stacked modes, all tabs must be the same size.
     */
    for( i = 0; i < count; ++i )
    {
	XmTabBox__wanted(tab)[i].width = max_width;
	XmTabBox__wanted(tab)[i].height = max_height;
    }
	
    /*
     * Now that we know what the max tab's size is so lets use that and
     * the XmNnumStacks resource to figure out the size that we want to
     * be.
     */
    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
    {
	tab_width = num_stacks * max_width;
	tab_height = ((int)(count/num_stacks) + (count%num_stacks ? 1 : 0)) *
	    max_height;
    }	
    else
    {
	tab_height = num_stacks * max_height;
	tab_width =  ((int)(count/num_stacks) + (count%num_stacks ? 1 : 0)) *
	    max_width;
    }

    rect->width = tab_width;
    rect->height = tab_height;
}

static void
HorizontalStackedLayout(XmTabBoxWidget tab, Boolean is_static)
{
    int        i, x, y, width, per_line, num_rows, tab_width, tab_height,
               tmp, on_line, start_x, offset, row, idx,
               cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab));
    XiTabRect  *actual = XmTabBox__actual(tab);
    XRectangle *wanted = XmTabBox__wanted(tab);

    if( cnt == 0 ) return;

    offset = XmTabBox_tab_offset(tab);

    width = XtWidth(tab);
    tab_width = 0;
    for( i = 0; i < cnt; ++i )
    {
	AssignMax(tab_width, (int)wanted[i].width);
    }

    /*
     * Since we are doing a stacked layout we know that uniform tab
     * size are a must, so lets find out how many tabs we can fit on
     * a line.
     */
    per_line = cnt;
    num_rows = (int)(cnt/per_line) + (cnt % per_line > 0 ? 1 : 0);
    tmp = (per_line * tab_width) + (num_rows * offset);
    while( per_line > 1 && tmp > width )
    {
	per_line--;
	num_rows = (int)(cnt/per_line) + (cnt % per_line > 0 ? 1 : 0);
	tmp = (per_line * tab_width) + (num_rows * offset);
    }
    AssignMax(num_rows, 1);
    AssignMax(per_line, 1);
    
    tab_height = ((int)XtHeight(tab))/ num_rows;
    if( num_rows > 1 )
    {
	tab_width = (((int)XtWidth(tab)) - ((num_rows-1) * offset))/per_line;
    }
    AssignMax(tab_height, 1);
    AssignMax(tab_width, 1);

    /*
     * Now that we know what size each tab is going to be, we need to 
     * the location for each tab. This is done differently depending
     * if we are doing a static or dynamic stacked layout. For the
     * static layout the tabs are always in the same location so we 
     * can choose a row/column as we place them. For the dynamic we
     * will first choose a row column and then a pixel location.
     */
   
    if( is_static )
    {
	start_x = x = (LayoutIsRtoLP(tab)
		? (per_line-1) * tab_width + offset * (num_rows-1)
		: 0);
	
	on_line = 0;
	row = 0;
	if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	{
	    y = (int) XtHeight(tab) - tab_height;
	    for( i = 0; i < cnt; ++i )
	    {
		actual[i].x = x;
		actual[i].y = y;
		actual[i].width = tab_width;
		actual[i].height = tab_height;
		actual[i].row = row;
		actual[i].column = on_line;
		if( ++on_line >= per_line )
		{
		    on_line = 0;
		    start_x += (LayoutIsRtoLP(tab) ? -offset : offset);
		    x = start_x;
		    y -= tab_height;
		    row++;
		}
		else
		{
		    x += (LayoutIsRtoLP(tab) ? -tab_width : tab_width);
		}
	    }	
	}
	else
	{
	    y = 0;
	    for( i = 0; i < cnt; ++i )
	    {
		actual[i].x = x;
		actual[i].y = y;
		actual[i].width = tab_width;
		actual[i].height = tab_height;
		actual[i].row = row;
		actual[i].column = on_line;
		if( ++on_line >= per_line )
		{
		    on_line = 0;
		    start_x += (LayoutIsRtoLP(tab) ? -offset : offset);
		    x = start_x;
		    y += tab_height;
		    row++;
		}
		else
		{
		    x += (LayoutIsRtoLP(tab) ? -tab_width : tab_width);
		}
	    }	
	}
	XmTabBox__num_rows(tab) = num_rows;
	XmTabBox__num_columns(tab) = per_line;
    }
    else
    {
	/*
	 * The challenge here is to make sure that the selected tab is
	 * always on row 0. So the first thing we need to do is break up
	 * the tabs into rows.
	 */
	start_x = x = (LayoutIsRtoLP(tab)
		? (per_line-1)*tab_width + offset*(num_rows-1)
		: 0);
	on_line = 0;
	row = 0;

	if( XmTabBox__selected(tab) < 0 )
	{
	    idx = 0;
	}
	else
	{
	    idx = (int)(XmTabBox__selected(tab)/ per_line) * per_line;
	}

	if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	{
	    y = (int) XtHeight(tab) - tab_height;
	    for( i = 0; i < cnt; ++i )
	    {
		actual[idx].x = x;
		actual[idx].y = y;
		actual[idx].width = tab_width;
		actual[idx].height = tab_height;
		actual[idx].row = row;
		actual[idx++].column = on_line;
		if( ++on_line >= per_line || idx >= cnt )
		{
		    on_line = 0;
		    start_x += LayoutIsRtoLP(tab) ? -offset : offset;
		    x = start_x;
		    y -= tab_height;
		    row++;
		}
		else
		{
		    x += LayoutIsRtoLP(tab) ? -tab_width : tab_width;
		}
		if( idx >= cnt ) idx = 0;
	    }
	}
	else
	{
	    y = 0;
	    for( i = 0; i < cnt; ++i )
	    {
		actual[idx].x = x;
		actual[idx].y = y;
		actual[idx].width = tab_width;
		actual[idx].height = tab_height;
		actual[idx].row = row;
		actual[idx++].column = on_line;
		if( ++on_line >= per_line || idx >= cnt )
		{
		    on_line = 0;
		    start_x += LayoutIsRtoLP(tab) ? -offset : offset;
		    x = start_x;
		    y += tab_height;
		    row++;
		}
		else
		{
		    x += LayoutIsRtoLP(tab) ? -tab_width : tab_width;
		}
		if( idx >= cnt ) idx = 0;
	    }
	}
	XmTabBox__num_rows(tab) = num_rows;
	XmTabBox__num_columns(tab) = per_line;
    }
}

static void
VerticalStackedLayout(XmTabBoxWidget tab, Boolean is_static)
{
    int        i, x, y, height, per_line, num_rows, tab_width, tab_height,
               tmp, on_line, start_y, offset, row, idx,
               cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab));
    XiTabRect  *actual = XmTabBox__actual(tab);
    XRectangle *wanted = XmTabBox__wanted(tab);

    if( cnt == 0 ) return;

    offset = XmTabBox_tab_offset(tab);

    height = XtHeight(tab);
    tab_height = 0;
    for( i = 0; i < cnt; ++i )
    {
	AssignMax(tab_height, (int)wanted[i].height);
    }

    per_line = cnt;
    num_rows = (int)(cnt/per_line) + (cnt % per_line > 0 ? 1 : 0);
    tmp = (per_line * tab_height) + (num_rows * offset);
    while( per_line > 1 && tmp > height )
    {
	per_line--;
	num_rows = (int)(cnt/per_line) + (cnt % per_line > 0 ? 1 : 0);
	tmp = (per_line * tab_height) + (num_rows * offset);
    }
    AssignMax(num_rows, 1);
    AssignMax(per_line, 1);

    if( num_rows > 1 )
    {
	tab_height = (((int)XtHeight(tab)) - ((num_rows-1) * offset))/per_line;
    }
    tab_width = ((int)XtWidth(tab))/num_rows;

    AssignMax(tab_height, 1);
    AssignMax(tab_width, 1);

    /*
     * Now that we know what size each tab is going to be, we need to 
     * the location for each tab. This is done differently depending
     * if we are doing a static or dynamic stacked layout. For the
     * static layout the tabs are always in the same location so we 
     * can choose a row/column as we place them. For the dynamic we
     * will first choose a row column and then a pixel location.
     */
    if( is_static )
    {
	start_y = y = 0;
	on_line = 0;
	row = 0;
	if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	{
	    x = (int)XtWidth(tab) - tab_width;
	    for( i = 0; i < cnt; ++i )
	    {
		actual[i].x = x;
		actual[i].y = y;
		actual[i].width = tab_width;
		actual[i].height = tab_height;
		actual[i].row = row;
		actual[i].column = on_line;
		if( ++on_line >= per_line )
		{
		    on_line = 0;
		    start_y += offset;
		    y = start_y;
		    x -= tab_width;
		    row++;
		}
		else
		{
		    y += tab_height;
		}
	    }	
	}
	else
	{
	    x = 0;
	    for( i = 0; i < cnt; ++i )
	    {
		actual[i].x = x;
		actual[i].y = y;
		actual[i].width = tab_width;
		actual[i].height = tab_height;
		actual[i].row = row;
		actual[i].column = on_line;
		if( ++on_line >= per_line )
		{
		    on_line = 0;
		    start_y += offset;
		    y = start_y;
		    x += tab_width;
		    row++;
		}
		else
		{
		    y += tab_height;
		}
	    }	
	}
	XmTabBox__num_rows(tab) = num_rows;
	XmTabBox__num_columns(tab) = per_line;
    }
    else
    {
	/*
	 * The challenge here is to make sure that the selected tab is
	 * always on row 0. So the first thing we need to do is break up
	 * the tabs into rows.
	 */
	start_y = y = 0;
	on_line = 0;
	row = 0;

	if( XmTabBox__selected(tab) < 0 )
	{
	    idx = 0;
	}
	else
	{
	    idx = (int)(XmTabBox__selected(tab)/ per_line) * per_line;
	}

	if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
	{
	    x = (int)XtWidth(tab) - tab_width;
	    for( i = 0; i < cnt; ++i )
	    {
		actual[idx].x = x;
		actual[idx].y = y;
		actual[idx].width = tab_width;
		actual[idx].height = tab_height;
		actual[idx].row = row;
		actual[idx++].column = on_line;
		if( ++on_line >= per_line || idx >= cnt )
		{
		    on_line = 0;
		    start_y += offset;
		    y = start_y;
		    x -= tab_width;
		    row++;
		}
		else
		{
		    y += tab_height;
		}
		if( idx >= cnt ) idx = 0;
	    }
	}
	else
	{
	    x = 0;
	    for( i = 0; i < cnt; ++i )
	    {
		actual[idx].x = x;
		actual[idx].y = y;
		actual[idx].width = tab_width;
		actual[idx].height = tab_height;
		actual[idx].row = row;
		actual[idx++].column = on_line;
		if( ++on_line >= per_line || idx >= cnt )
		{
		    on_line = 0;
		    start_y += offset;
		    y = start_y;
		    x += tab_width;
		    row++;
		}
		else
		{
		    y += tab_height;
		}
		if( idx >= cnt ) idx = 0;
	    }
	}
	XmTabBox__num_rows(tab) = num_rows;
	XmTabBox__num_columns(tab) = per_line;
    }
}

/*
 * Function:
 *	RedisplayTabs(tab, region)
 * Description:
 *	Walks the list of tabs and redisplays any tab that intersets with
 *	the given region. If the region specified is "False" then all tabs
 *	are exposed (see macro XiRectInRegion).
 * Input:
 *	tab    : XmTabBoxWidget - tab box, whose tabs need redisplayed
 *	region : Region         - the region to expose or False for all
 * Output:
 *	None.
 */
static void
RedisplayTabs(XmTabBoxWidget tab, Region region)
{
    XiTabRect       *geom;
    int             i, count = _XmTabbedStackListCount(XmTabBox_tab_list(tab));
    XmTabAttributes info;
    
    /*
     * Now lets walk through our list of tabs and redisplay any tab that 
     * lies in the region.
     */
    geom = XmTabBox__actual(tab);
    for( i = 0; i < count; ++i )
    {
	if( XiRectInRegion(region, geom[i].x, geom[i].y, geom[i].width,
			   geom[i].height) )
	{
	    info = _XmTabbedStackListGet(XmTabBox_tab_list(tab), i);
	    
	    DrawTab(tab, info, &(geom[i]),
		    (Boolean)(XmTabBox__selected(tab) == i),
		    (Boolean)(XmTabBox__keyboard(tab) == i));
	}
    }
}

static void
HorizontalStackedBottomEdgeRedisplay(XmTabBoxWidget tab)
{
    XmTabbedStackList       list = XmTabBox_tab_list(tab);
    int             i, count = _XmTabbedStackListCount(list), row = 0, col,
                    shadow = tab->manager.shadow_thickness, x,
                    height, offset, idx, below, corner, cnt, first, last,
                    x1, x2;
    XmTabAttributes info;
    XiTabRect       *geom;
    GC		    gc = XmTabBox__tab_GC(tab);
    Boolean	    do_top, do_bottom;
#define _NUM_RECTS 10
    XRectangle      rect[_NUM_RECTS], top = {0, 0, 0, 0}, bottom = {0, 0, 0, 0};

    /*
     * What we need to do in this mode is to extend the right most tab
     * on each row to the bottom of the widget(minus the shadow). Besides
     * the bcakground of the widget we also need to extend the shadow.
     */
    offset = XmTabBox_tab_offset(tab);
    geom = XmTabBox__actual(tab);

    /*
     * First the quick check. If we only have one row then all we need to do
     * is draw the base line from the end of the last tab to the right edge.
     */
    if( XmTabBox__num_rows(tab) == 1 &&
        (idx = GetTabIndex(tab, 0, XmTabBox__num_columns(tab) - 1)) >= 0 )
    {
	Pixel  pixel;
	Pixmap pixmap;

	XtVaGetValues(XiGCParent(tab),
		      XmNbackground, &pixel,
		      XmNbackgroundPixmap, &pixmap,
		      NULL);
	
	if( ValidPixmap(pixmap) )
	{
	    SetTiledGC(XtDisplay(tab), gc, pixmap);
	}
	else
	{
	    SetSolidGC(XtDisplay(tab), gc, pixel);
	}

	x = geom[idx].x + geom[idx].width;
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.top_shadow_GC,
		       x, (int)XtHeight(tab) - shadow,
		       (int)XtWidth(tab) - x, shadow);
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       gc, x, 0, (int)XtWidth(tab) - x,
		       (int)XtHeight(tab) - shadow);
	XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
		    tab->manager.top_shadow_GC,
		    tab->manager.bottom_shadow_GC,
		    (int)XtWidth(tab) - shadow,
		    (int)XtHeight(tab) - shadow,
		    shadow, XmBEVEL_BOTTOM);
	return;
    }

    for( i = 0; i < count; ++i )
    {
	corner = GetTabIndex(tab, geom[i].row-1, geom[i].column+1);
	below = GetTabIndex(tab, geom[i].row-1, geom[i].column);
	if( geom[i].row > 0 && (corner < 0 || below < 0) )
	{
	    cnt = 0;
	    do_top = do_bottom = False;
	    info = _XmTabbedStackListGet(list, i);

	    if( XiBackgroundSpecified(info) )
	    {
		SetBackgroundGC(tab, info, gc);
	    }
	    else if( ValidPixmap(tab->core.background_pixmap) )
	    {
		SetTiledGC(XtDisplay(tab), gc, tab->core.background_pixmap);
	    }
	    else
	    {
		SetSolidGC(XtDisplay(tab), gc, tab->core.background_pixel);
	    }

	    for( height = geom[i].height, row = geom[i].row - 2;
  		 row >= 0 && GetTabIndex(tab, row, geom[i].column+1) < 0;
		 row--, height += geom[i].height );

	    if( corner < 0 )
	    {
		if (LayoutIsRtoLP(tab))
		{
		    rect[cnt].x = geom[i].x;
		    rect[cnt].y = geom[i].y + geom[i].height;
		    rect[cnt].width = offset;
		    rect[cnt++].height = height;

		    bottom.x = geom[i].x;
		    bottom.y = geom[i].y + geom[i].height;
		}
		else
		{
		    rect[cnt].x = geom[i].x + geom[i].width - offset;
		    rect[cnt].y = geom[i].y + geom[i].height;
		    rect[cnt].width = offset;
		    rect[cnt++].height = height;

		    bottom.x = geom[i].x + geom[i].width - shadow;
		    bottom.y = geom[i].y + geom[i].height;
		}
		bottom.width = shadow;
		bottom.height = height;
		do_bottom = True;
	    }

	    if( below < 0 )
	    {
	        if( LayoutIsRtoLP(tab) )
		{
		rect[cnt].x = geom[i].x + offset;
		}
		else
		{
		rect[cnt].x = geom[i].x;
		}
		rect[cnt].y = geom[i].y + geom[i].height;
		rect[cnt].width = geom[i].width - offset;
		rect[cnt].height = geom[i].height;
		cnt++;

		if( LayoutIsRtoLP(tab) )
		{
		    top.x = geom[i].x + geom[i].width - shadow;
		}
		else
		{
		    top.x = geom[i].x;
		}
		top.y = geom[i].y + geom[i].height;
		top.width = shadow;
		top.height = geom[i].height;
		do_top = True;
		

		if( geom[i].row > 1 &&
		    geom[i].column == XmTabBox__num_columns(tab) - 1 )
		{
		    if( LayoutIsRtoLP(tab) )
		    {
		    rect[cnt].x = offset;
		    }
		    else
		    {
		    rect[cnt].x = geom[i].x + geom[i].width - (2*offset);
		    }
		    rect[cnt].y = geom[i].y + geom[i].height;
		    rect[cnt].width = offset;
		    rect[cnt].height = (int)XtHeight(tab) - rect[cnt].y;
		    cnt++;
		}
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    if( do_bottom )
	    {
		if( LayoutIsRtoLP(tab) )
		    XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
			       tab->manager.top_shadow_GC, bottom.x,
			       bottom.y, bottom.width, bottom.height);
		else
		    XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
			       tab->manager.bottom_shadow_GC, bottom.x,
			       bottom.y, bottom.width, bottom.height);
	    }
	    if( do_top )
	    {
	    	if( LayoutIsRtoLP(tab) )
		{
		    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			       tab->manager.bottom_shadow_GC, top.x,
			       top.y, top.width, top.height);
		}
		else
		{
		    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			       tab->manager.top_shadow_GC, top.x,
			       top.y, top.width, top.height);
		}
	    }
	}
    }

    /*
     * Now that all the tab stuff is done, lets clear all the background
     * areas to our parents background color.
     */
    {
	Pixel  pixel;
	Pixmap pixmap;

	XtVaGetValues(XiGCParent(tab),
		      XmNbackground, &pixel,
		      XmNbackgroundPixmap, &pixmap,
		      NULL);
	
	if( ValidPixmap(pixmap) )
	{
	    SetTiledGC(XtDisplay(tab), gc, pixmap);
	}
	else
	{
	    SetSolidGC(XtDisplay(tab), gc, pixel);
	}
    }

    cnt = 0;
    if (LayoutIsRtoLP(tab))
    {
	for( i = 1; i < XmTabBox__num_rows(tab); ++i, x -= offset )
	{
	    if( (idx = GetTabIndex(tab, i, 0)) < 0 ) continue;

	    rect[cnt].x = geom[idx].x + geom[idx].width;
	    rect[cnt].y = geom[idx].y;
	    rect[cnt].width = XtWidth(tab) - geom[idx].x;
	    rect[cnt++].height = geom[idx].height;

	    if( cnt >= _NUM_RECTS )
	    {
		XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
		cnt=0;
	    }
	}
    } else {
	x = offset;
	for( i = 1; i < XmTabBox__num_rows(tab); ++i, x += offset )
	{
	    if( (idx = GetTabIndex(tab, i, 0)) < 0 ) continue;

	    rect[cnt].x = 0;
	    rect[cnt].y = geom[idx].y;
	    rect[cnt].width = x;
	    rect[cnt++].height = geom[idx].height;

	    if( cnt >= _NUM_RECTS )
	    {
		XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
		cnt=0;
	    }
	}
    }

    /*
     * We need to clear any area on the right side of the tabs. To do this
     * we find the tab in the upper right corner and clear down to the 
     * bottom and then check the top row to see if it is full.
     */
    last = -1;
    col = XmTabBox__num_columns(tab) - 1;
    for( i = 0; i < XmTabBox__num_rows(tab); ++i )
    {
	if( (idx = GetTabIndex(tab, i, col)) >= 0 )
        {
	    last = idx;
	}
    }
    if( last != -1 )
    {
	if( LayoutIsRtoLP(tab) )
	{
	    rect[cnt].x = 0;
	    rect[cnt].y = 0;
	    rect[cnt].width = geom[last].x;
	    rect[cnt++].height = XtHeight(tab);
	    last = GetTabIndex(tab, 0, 0);
	}
	rect[cnt].x = geom[last].x + geom[last].width;
	rect[cnt].y = 0;
	rect[cnt].width = (int)XtWidth(tab) - rect[cnt].x;
	rect[cnt++].height = XtHeight(tab);
	if( cnt >= _NUM_RECTS )
	{
	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    cnt=0;
	}
    }

    row = XmTabBox__num_rows(tab) - 1;
    col = XmTabBox__num_columns(tab) - 1;
    last = -1;
    if( GetTabIndex(tab, row, col) < 0 )
    {
	for( i = col; i >= 0 && last < 0; last = GetTabIndex(tab, row, --i) );

	if( last >= 0 )
	{
	    if (LayoutIsRtoLP(tab)) {
		rect[cnt].x = 0;
		rect[cnt].width = geom[last].x;
	    } else {
		rect[cnt].x = geom[last].x + geom[last].width;
		rect[cnt].width = (int)XtWidth(tab) - rect[cnt].x;
	    }
	    rect[cnt].y = 0;
	    rect[cnt++].height = geom[last].height;

	    if( cnt >= _NUM_RECTS )
	    {
		XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
		cnt=0;
	    }
	}
    }

    if( cnt > 0 )
    {
	XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	cnt=0;
    }


    /*
     * If the users wants the special stacked effect then we are done so 
     * lets get out of here.
     */
    if( GetTabIndex(tab, 0, XmTabBox__num_columns(tab) - 1) >= 0 &&
        XmTabBox_stacked_effect(tab) ) return;

    /*
     * Now that we have all the tabs drawn we want to complete the
     * shadow line from the last tab in the first row to the last
     * tab in the last row.  Lets start by finding the last tab in the
     * first row and the last tab in the last row.
     */
    first = GetTabIndex(tab, 0, 0);;
    for( i = 0; i < XmTabBox__num_columns(tab); ++i )
    {
	if( (idx = GetTabIndex(tab, 0, i)) < 0 ) break;
	first = idx;
    }

    if( XmTabBox_stacked_effect(tab) )
    {
	if( first < 0 ) return;

	/*
	 * If we got here that means that we are doing the stacked effect
	 * and that row 0 is not complete. What this means is that we
	 * need to do is draw a line from the last tab in row 0 to the
	 * location where the row should end.
	 */
	if( LayoutIsRtoLP(tab) )
	{
	    x1 = offset * ((XmTabBox__num_rows(tab) - 1));
	    x2 = geom[first].x;
	}
	else
	{
	    x1 = geom[first].x + geom[first].width;
	    x2 = XmTabBox__num_columns(tab) * geom[first].width;
	}
    }
    else
    {
	x1 = geom[first].x + geom[first].width;
	x2 = XtWidth(tab);
    }


    /*
     * Now that we know what we are dealing with all we have to do
     * is draw the line.
     */

    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		   tab->manager.top_shadow_GC,
		   x1, (int)XtHeight(tab) - shadow,
		   x2 - x1, shadow);
  
    if( !LayoutIsRtoLP(tab) )
    {  
	XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
		tab->manager.top_shadow_GC,
		tab->manager.bottom_shadow_GC,
		x2 - shadow, (int)XtHeight(tab) - shadow,
		shadow, XmBEVEL_BOTTOM);
    }
}

static void
HorizontalStackedTopEdgeRedisplay(XmTabBoxWidget tab)
{
    XmTabbedStackList       list = XmTabBox_tab_list(tab);
    int             i, count = _XmTabbedStackListCount(list), row = 0, col,
                    shadow = tab->manager.shadow_thickness, x,
                    height, offset, idx, below, corner, cnt, first, last,
                    x1, x2;
    XmTabAttributes info;
    XiTabRect       *geom;
    GC		    gc = XmTabBox__tab_GC(tab);
    Boolean	    do_top, do_bottom;
#define _NUM_RECTS 10
    XRectangle      rect[_NUM_RECTS], top = {0, 0, 0, 0}, bottom = {0, 0, 0, 0};

    offset = XmTabBox_tab_offset(tab);
    geom = XmTabBox__actual(tab);

    /*
     * First the quick check. If we only have one row then all we need to do
     * is draw the base line from the end of the last tab to the right edge.
     */
    if( XmTabBox__num_rows(tab) == 1 &&
        (idx = GetTabIndex(tab, 0, XmTabBox__num_columns(tab) - 1)) >= 0 )
    {
	Pixel  pixel;
	Pixmap pixmap;

	XtVaGetValues(XiGCParent(tab),
		      XmNbackground, &pixel,
		      XmNbackgroundPixmap, &pixmap,
		      NULL);
	
	if( ValidPixmap(pixmap) )
	{
	    SetTiledGC(XtDisplay(tab), gc, pixmap);
	}
	else
	{
	    SetSolidGC(XtDisplay(tab), gc, pixel);
	}

	x = geom[idx].x + geom[idx].width;
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.bottom_shadow_GC,
		       x, 0, (int)XtWidth(tab) - x, shadow);
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       gc, x, shadow, (int)XtWidth(tab) - x,
		       (int)XtHeight(tab) - shadow);
	return;
    }

    for( i = 0; i < count; ++i )
    {
	corner = GetTabIndex(tab, geom[i].row-1, geom[i].column+1);
	below = GetTabIndex(tab, geom[i].row-1, geom[i].column);
	if( geom[i].row > 0 && (corner < 0 || below < 0) )
	{
	    cnt = 0;
	    do_top = do_bottom = False;
	    info = _XmTabbedStackListGet(list, i);

	    if( XiBackgroundSpecified(info) )
	    {
		SetBackgroundGC(tab, info, gc);
	    }
	    else if( ValidPixmap(tab->core.background_pixmap) )
	    {
		SetTiledGC(XtDisplay(tab), gc, tab->core.background_pixmap);
	    }
	    else
	    {
		SetSolidGC(XtDisplay(tab), gc, tab->core.background_pixel);
	    }

	    for( height = geom[i].height, row = geom[i].row - 2;
  		 row >= 0 && GetTabIndex(tab, row, geom[i].column+1) < 0;
		 row--, height += geom[i].height );

	    if( corner < 0 )
	    {
		if( LayoutIsRtoLP(tab) )
		{
		    rect[cnt].x = geom[i].x;
		    bottom.x = geom[i].x;
		}
		else
		{
		    rect[cnt].x = geom[i].x + geom[i].width - offset;
		    bottom.x = geom[i].x + geom[i].width - shadow;
		}
		rect[cnt].y = geom[i].y - height;
		rect[cnt].width = offset;
		rect[cnt++].height = height;

		bottom.y = geom[i].y - height;
		bottom.width = shadow;
		bottom.height = height;
		do_bottom = True;
	    }
	    
	    if( below < 0 )
	    {
	    	if( LayoutIsRtoLP(tab) )
		{
		    rect[cnt].x = geom[i].x + offset;
		}
		else
		{
		    rect[cnt].x = geom[i].x;
		}
		rect[cnt].y = geom[i].y - geom[i].height;
		rect[cnt].width = geom[i].width - offset;
		rect[cnt++].height = geom[i].height;

	    	if( LayoutIsRtoLP(tab) )
		{
		    top.x = geom[i].x + geom[i].width - shadow;
		}
		else
		{
		    top.x = geom[i].x;
		}
		top.y = geom[i].y - geom[i].height;
		top.width = shadow;
		top.height = geom[i].height;
		do_top = True;

		if( geom[i].row > 1 &&
		    geom[i].column == XmTabBox__num_columns(tab) - 1 )
		{
		    if( LayoutIsRtoLP(tab) )
		    {
			rect[cnt].x = offset;
		    }
		    else
		    {
			rect[cnt].x = geom[i].x + geom[i].width - (2*offset);
		    }
		    rect[cnt].y = 0;
		    rect[cnt].width = offset;
		    rect[cnt].height = geom[i].y;
		    cnt++;
		}
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);

	    if( do_bottom )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
			       LayoutIsRtoLP(tab)
			           ? tab->manager.top_shadow_GC
				   : tab->manager.bottom_shadow_GC,
			       bottom.x, bottom.y, bottom.width, bottom.height);
	    }
	    if( do_top )
	    {
		if( LayoutIsRtoLP(tab) )
		{
		    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			       tab->manager.bottom_shadow_GC, top.x,
			       top.y, top.width, top.height);
		}
		else
		{
		    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			       tab->manager.top_shadow_GC, top.x,
			       top.y, top.width, top.height);
		}
	    }
	}
    }

    /*
     * Now that all the tab stuff is done, lets clear all the background
     * areas to our parents background color.
     */
    {
	Pixel  pixel;
	Pixmap pixmap;

	XtVaGetValues(XiGCParent(tab),
		      XmNbackground, &pixel,
		      XmNbackgroundPixmap, &pixmap,
		      NULL);
	
	if( ValidPixmap(pixmap) )
	{
	    SetTiledGC(XtDisplay(tab), gc, pixmap);
	}
	else
	{
	    SetSolidGC(XtDisplay(tab), gc, pixel);
	}
    }

    x = offset;
    cnt = 0;
    for( i = 1; i < XmTabBox__num_rows(tab); ++i, x += offset )
    {
	if( (idx = GetTabIndex(tab, i, 0)) < 0 ) continue;

	rect[cnt].x = LayoutIsRtoLP(tab) ? geom[idx].x + geom[idx].width : 0;
	rect[cnt].y = geom[idx].y;
	rect[cnt].width = x;
	rect[cnt++].height = geom[idx].height;

	if( cnt >= _NUM_RECTS )
	{
	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    cnt=0;
	}
    }
    /*
     * We need to clear any area on the right side of the tabs. To do this
     * we find the tab in the upper right corner and clear down to the 
     * bottom and then check the top row to see if it is full.
     */
    last = -1;
    col = XmTabBox__num_columns(tab) - 1;
    for( i = 0; i < XmTabBox__num_rows(tab); ++i )
    {
	if( (idx = GetTabIndex(tab, i, col)) >= 0 )
	{
	    last = idx;
	}
    }

    if( last != -1 )
    {
	if( LayoutIsRtoLP(tab) )
	{
	    rect[cnt].x = 0;
	    rect[cnt].y = 0;
	    rect[cnt].width = geom[last].x;
	    rect[cnt++].height = XtHeight(tab);
	    last = GetTabIndex(tab, 0, 0);
	}
	rect[cnt].x = geom[last].x + geom[last].width;
	rect[cnt].y = 0;
	rect[cnt].width = (int)XtWidth(tab) - rect[cnt].x;
	rect[cnt++].height = XtHeight(tab);

	if( cnt >= _NUM_RECTS )
	{
	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    cnt=0;
	}
    }

    row = XmTabBox__num_rows(tab) - 1;
    col = XmTabBox__num_columns(tab) - 1;
    last = -1;
    if( GetTabIndex(tab, row, col) < 0 )
    {
	for( i = col; i >= 0 && last < 0; last = GetTabIndex(tab, row, --i) );

	if( last >= 0 )
	{
	    if( LayoutIsRtoLP(tab) )
	    {
		rect[cnt].x = 0;
		rect[cnt].y = (int)XtHeight(tab) - geom[last].height;
		rect[cnt].width = geom[last].x;
		rect[cnt++].height = geom[last].height;
	    }
	    else
	    {
		rect[cnt].x = geom[last].x + geom[last].width;
		rect[cnt].y = (int)XtHeight(tab) - geom[last].height;
		rect[cnt].width = (int)XtWidth(tab) - rect[cnt].x;
		rect[cnt++].height = geom[last].height;
	    }

	    if( cnt >= _NUM_RECTS )
	    {
		XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
		cnt=0;
	    }
	}
    }

    if( cnt > 0 )
    {
	XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	cnt=0;
    }

    /*
     * If the users wants the special stacked effect then we are done so 
     * lets get out of here.
     */
    if( GetTabIndex(tab, 0, XmTabBox__num_columns(tab) - 1) >= 0 &&
        XmTabBox_stacked_effect(tab) ) return;

    /*
     * Now that we have all the tabs drawn we want to complete the
     * shadow line from the last tab in the first row to the last
     * tab in the last row.  Lets start by finding the last tab in the
     * first row and the last tab in the last row.
     */
    first = GetTabIndex(tab, 0, 0);;
    for( i = 0; i < XmTabBox__num_columns(tab); ++i )
    {
	if( (idx = GetTabIndex(tab, 0, i)) < 0 ) break;
	first = idx;
    }

    if( XmTabBox_stacked_effect(tab) )
    {
	if( first < 0 ) return;

	/*
	 * If we got here that means that we are doing the stacked effect
	 * and that row 0 is not complete. What this means is that we
	 * need to do is draw a line from the last tab in row 0 to the
	 * location where the row should end.
	 */
	if( LayoutIsRtoLP(tab) )
	{
	    x1 = offset * (XmTabBox__num_rows(tab) - 1) + shadow;
	    x2 = geom[first].x;
	    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
		    tab->manager.top_shadow_GC,
		    tab->manager.bottom_shadow_GC,
		    x1 - shadow, 0,
		    shadow, XmBEVEL_BOTH);
	    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
		    tab->manager.bottom_shadow_GC,
		    tab->manager.top_shadow_GC,
		    x2, 0,
		    shadow, XmBEVEL_BOTH);
	}
	else
	{
	    x1 = geom[first].x + geom[first].width;
	    x2 = XmTabBox__num_columns(tab) * geom[first].width;
	}
    }
    else
    {
	x1 = geom[first].x + geom[first].width;
	x2 = XtWidth(tab);
    }

    /*
     * Now that we know what we are dealing with all we have to do
     * is draw the line.
     */

    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		   tab->manager.bottom_shadow_GC,
		   x1, 0, x2 - x1, shadow);
}

static void
HorizontalStackedRedisplay(XmTabBoxWidget tab)
{
    if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
    {
	HorizontalStackedBottomEdgeRedisplay(tab);
    }
    else
    {
	HorizontalStackedTopEdgeRedisplay(tab);
    }
}

static void
VerticalStackedRightEdgeRedisplay(XmTabBoxWidget tab)
{
    XmTabbedStackList       list = XmTabBox_tab_list(tab);
    int             i, count = _XmTabbedStackListCount(list), row = 0, col,
                    shadow = tab->manager.shadow_thickness, y, width,
                    offset, idx, below, corner, cnt = 0, first, last,
                    y1, y2;
    XmTabAttributes info;
    XiTabRect       *geom;
    GC		    gc = XmTabBox__tab_GC(tab);
    Boolean	    do_top, do_bottom;
#define _NUM_RECTS 10
    XRectangle      rect[_NUM_RECTS], top = {0, 0, 0, 0}, bottom = {0, 0, 0, 0};

    /*
     * What we need to do in this mode is to extend the right most tab
     * on each row to the bottom of the widget(minus the shadow). Besides
     * the bcakground of the widget we also need to extend the shadow.
     */
    offset = XmTabBox_tab_offset(tab);
    geom = XmTabBox__actual(tab);

    /*
     * First the quick check. If we only have one row then all we need to do
     * is draw the base line from the end of the last tab to the right edge.
     */
    if( XmTabBox__num_rows(tab) == 1 &&
        (idx = GetTabIndex(tab, 0, XmTabBox__num_columns(tab) - 1)) >= 0 )
    {
	Pixel  pixel;
	Pixmap pixmap;

	XtVaGetValues(XiGCParent(tab),
		      XmNbackground, &pixel,
		      XmNbackgroundPixmap, &pixmap,
		      NULL);
	
	if( ValidPixmap(pixmap) )
	{
	    SetTiledGC(XtDisplay(tab), gc, pixmap);
	}
	else
	{
	    SetSolidGC(XtDisplay(tab), gc, pixel);
	}

	y = geom[idx].y + geom[idx].height;
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.top_shadow_GC,
		       (int)XtWidth(tab) - shadow, y,
		       shadow, (int)XtHeight(tab) - y);
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       gc, 0, y, (int)XtWidth(tab) - shadow,
		       (int)XtHeight(tab) - y);
	XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
		    tab->manager.top_shadow_GC,
		    tab->manager.bottom_shadow_GC,
		    (int)XtWidth(tab) - shadow,
		    (int)XtHeight(tab) - shadow,
		    shadow, XmBEVEL_BOTTOM);
	return;
    }

    for( i = 0; i < count; ++i )
    {
	corner = GetTabIndex(tab, geom[i].row-1, geom[i].column+1);
	below = GetTabIndex(tab, geom[i].row-1, geom[i].column);
	if( geom[i].row > 0 && (corner < 0 || below < 0) )
	{
	    cnt = 0;
	    do_top = do_bottom = False;
	    info = _XmTabbedStackListGet(list, i);

	    if( XiBackgroundSpecified(info) )
	    {
		SetBackgroundGC(tab, info, gc);
	    }
	    else if( ValidPixmap(tab->core.background_pixmap) )
	    {
		SetTiledGC(XtDisplay(tab), gc, tab->core.background_pixmap);
	    }
	    else
	    {
		SetSolidGC(XtDisplay(tab), gc, tab->core.background_pixel);
	    }

	    for( width = geom[i].width, row = geom[i].row - 2;
		 row >= 0 && GetTabIndex(tab, row, geom[i].column+1) < 0;
		 row--, width += geom[i].width );

	    if( corner < 0 )
	    {
		rect[cnt].x = geom[i].x + geom[i].width;
		rect[cnt].y = geom[i].y + geom[i].height- offset;
		rect[cnt].width = width;
		rect[cnt++].height = offset;

		bottom.x = geom[i].x + geom[i].width;
		bottom.y = geom[i].y + geom[i].height - shadow;
		bottom.width = width;
		bottom.height = shadow;
		do_bottom = True;
	    }
	    
	    if( below < 0 )
	    {
		rect[cnt].x = geom[i].x + geom[i].width;
		rect[cnt].y = geom[i].y;
		rect[cnt].width = geom[i].width;
		rect[cnt++].height = geom[i].height - offset;

		top.x = geom[i].x + geom[i].width;
		top.y = geom[i].y;
		top.width = geom[i].width;
		top.height = shadow;
		do_top = True;

		if( geom[i].row > 1 &&
		    geom[i].column == XmTabBox__num_columns(tab) - 1 )
		{
		    rect[cnt].x = geom[i].x + geom[i].width;
		    rect[cnt].y = geom[i].y + geom[i].height - (2*offset);
		    rect[cnt].width = (int)XtWidth(tab) - rect[cnt].x;
		    rect[cnt].height = offset;
		    cnt++;
		}
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    if( do_bottom )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
			       tab->manager.bottom_shadow_GC, bottom.x,
			       bottom.y, bottom.width, bottom.height);
	    }
	    if( do_top )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			       tab->manager.top_shadow_GC, top.x,
			       top.y, top.width, top.height);
	    }
	}
    }

    /*
     * Now that all the tab stuff is done, lets clear all the background
     * areas to our parents background color.
     */
    {
	Pixel  pixel;
	Pixmap pixmap;

	XtVaGetValues(XiGCParent(tab),
		      XmNbackground, &pixel,
		      XmNbackgroundPixmap, &pixmap,
		      NULL);
	
	if( ValidPixmap(pixmap) )
	{
	    SetTiledGC(XtDisplay(tab), gc, pixmap);
	}
	else
	{
	    SetSolidGC(XtDisplay(tab), gc, pixel);
	}
    }

    y = offset;
    cnt = 0;
    for( i = 1; i < XmTabBox__num_rows(tab); ++i, y += offset )
    {
	if( (idx = GetTabIndex(tab, i, 0)) < 0 ) continue;

	rect[cnt].x = geom[idx].x;
	rect[cnt].y = 0;
	rect[cnt].width = geom[idx].width;
	rect[cnt++].height = y;

	if( cnt >= _NUM_RECTS )
	{
	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    cnt=0;
	}
    }
    /*
     * We need to clear any area on the right side of the tabs. To do this
     * we find the tab in the upper right corner and clear down to the 
     * bottom and then check the top row to see if it is full.
     */
    last = -1;
    col = XmTabBox__num_columns(tab) - 1;
    for( i = 0; i < XmTabBox__num_rows(tab); ++i )
    {
	if( (idx = GetTabIndex(tab, i, col)) >= 0 )
	{
	    last = idx;
	}
    }

    if( last != -1 )
    {
	rect[cnt].x = 0;
	rect[cnt].y = geom[last].y + geom[last].height;
	rect[cnt].width = XtWidth(tab);
	rect[cnt].height = (int)XtHeight(tab) - rect[cnt].y;
	cnt++;

	if( cnt >= _NUM_RECTS )
	{
	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    cnt=0;
	}
    }

    row = XmTabBox__num_rows(tab) - 1;
    col = XmTabBox__num_columns(tab) - 1;
    last = -1;
    if( GetTabIndex(tab, row, col) < 0 )
    {
	for( i = col; i >= 0 && last < 0; last = GetTabIndex(tab, row, --i) );

	if( last >= 0 )
	{
	    rect[cnt].x = 0;
	    rect[cnt].y = geom[last].y + geom[last].height;
	    rect[cnt].width = geom[last].width;
	    rect[cnt].height = (int)XtHeight(tab) - rect[cnt].y;
	    cnt++;

	    if( cnt >= _NUM_RECTS )
	    {
		XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
		cnt=0;
	    }
	}
    }

    if( cnt > 0 )
    {
	XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	cnt=0;
    }


    /*
     * If the users wants the special stacked effect then we are done so 
     * lets get out of here.
     */
    if( GetTabIndex(tab, 0, XmTabBox__num_columns(tab) - 1) >= 0 &&
        XmTabBox_stacked_effect(tab) ) return;

    /*
     * Now that we have all the tabs drawn we want to complete the
     * shadow line from the last tab in the first row to the last
     * tab in the last row.  Lets start by finding the last tab in the
     * first row and the last tab in the last row.
     */
    first = GetTabIndex(tab, 0, 0);;
    for( i = 0; i < XmTabBox__num_columns(tab); ++i )
    {
	if( (idx = GetTabIndex(tab, 0, i)) < 0 ) break;
	first = idx;
    }

    if( XmTabBox_stacked_effect(tab) )
    {
	if( first < 0 ) return;

	/*
	 * If we got here that means that we are doing the stacked effect
	 * and that row 0 is not complete. What this means is that we
	 * need to do is draw a line from the last tab in row 0 to the
	 * location where the row should end.
	 */
	y1 = geom[first].y + geom[first].height;
	y2 = XmTabBox__num_columns(tab) * geom[first].height;
    }
    else
    {
	y1 = geom[first].y + geom[first].height;
	y2 = XtHeight(tab);
    }


    /*
     * Now that we know what we are dealing with all we have to do
     * is draw the line.
     */

    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		   tab->manager.top_shadow_GC,
		   (int)XtWidth(tab) - shadow, y1,
		   shadow, y2 - y1);
    XmDrawBevel(XtDisplay(tab), XiCanvas(tab),
		tab->manager.top_shadow_GC,
		tab->manager.bottom_shadow_GC,
		(int)XtWidth(tab) - shadow, y2 - shadow,
		shadow, XmBEVEL_BOTTOM);
}

static void
VerticalStackedLeftEdgeRedisplay(XmTabBoxWidget tab)
{
    XmTabbedStackList       list = XmTabBox_tab_list(tab);
    int             i, count = _XmTabbedStackListCount(list), row = 0, col,
                    shadow = tab->manager.shadow_thickness, y, width,
                    offset, idx, below, corner, cnt = 0, first, last,
                    y1, y2;
    XmTabAttributes info;
    XiTabRect       *geom;
    GC		    gc = XmTabBox__tab_GC(tab);
    Boolean	    do_top, do_bottom;
#define _NUM_RECTS 10
    XRectangle      rect[_NUM_RECTS], top = {0, 0, 0, 0}, bottom = {0, 0, 0, 0};

    offset = XmTabBox_tab_offset(tab);
    geom = XmTabBox__actual(tab);

    if( XmTabBox__num_rows(tab) == 1 &&
        (idx = GetTabIndex(tab, 0, XmTabBox__num_columns(tab) - 1)) >= 0 )
    {
	Pixel  pixel;
	Pixmap pixmap;

	XtVaGetValues(XiGCParent(tab),
		      XmNbackground, &pixel,
		      XmNbackgroundPixmap, &pixmap,
		      NULL);
	
	if( ValidPixmap(pixmap) )
	{
	    SetTiledGC(XtDisplay(tab), gc, pixmap);
	}
	else
	{
	    SetSolidGC(XtDisplay(tab), gc, pixel);
	}

	y = geom[idx].y + geom[idx].height;
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       tab->manager.bottom_shadow_GC,
		       0, y, shadow, (int)XtHeight(tab) - y);
	XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		       gc, shadow, y, (int)XtWidth(tab) - shadow,
		       (int)XtHeight(tab) - y);
	return;
    }

    for( i = 0; i < count; ++i )
    {
	corner = GetTabIndex(tab, geom[i].row-1, geom[i].column+1);
	below = GetTabIndex(tab, geom[i].row-1, geom[i].column);
	if( geom[i].row > 0 && (corner < 0 || below < 0) )
	{
	    cnt = 0;
	    do_top = do_bottom = False;
	    info = _XmTabbedStackListGet(list, i);

	    if( XiBackgroundSpecified(info) )
	    {
		SetBackgroundGC(tab, info, gc);
	    }
	    else if( ValidPixmap(tab->core.background_pixmap) )
	    {
		SetTiledGC(XtDisplay(tab), gc, tab->core.background_pixmap);
	    }
	    else
	    {
		SetSolidGC(XtDisplay(tab), gc, tab->core.background_pixel);
	    }

	    for( width = geom[i].width, row = geom[i].row - 2;
  		 row >= 0 && GetTabIndex(tab, row, geom[i].column+1) < 0;
		 row--, width += geom[i].width );

	    if( corner < 0 )
	    {
		rect[cnt].x = geom[i].x - width;
		rect[cnt].y = geom[i].y + geom[i].height - offset;
		rect[cnt].width = width;
		rect[cnt++].height = offset;

		bottom.x = geom[i].x - width;
		bottom.y = geom[i].y + geom[i].height - shadow;
		bottom.width = width;
		bottom.height = shadow;
		do_bottom = True;
	    }
	    
	    if( below < 0 )
	    {
		rect[cnt].x = geom[i].x - geom[i].width;
		rect[cnt].y = geom[i].y;
		rect[cnt].width = geom[i].width;
		rect[cnt++].height = geom[i].height - offset;

		top.x = geom[i].x - geom[i].width;
		top.y = geom[i].y;
		top.width = geom[i].width;
		top.height = shadow;
		do_top = True;

		if( geom[i].row > 1 &&
		    geom[i].column == XmTabBox__num_columns(tab) - 1 )
		{
		    rect[cnt].x = 0;
		    rect[cnt].y = geom[i].y + geom[i].height - (2*offset);
		    rect[cnt].width = geom[i].x;
		    rect[cnt].height = offset;
		    cnt++;
		}
	    }

	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);

	    if( do_bottom )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab), 
			       tab->manager.bottom_shadow_GC, bottom.x,
			       bottom.y, bottom.width, bottom.height);
	    }
	    if( do_top )
	    {
		XFillRectangle(XtDisplay(tab), XiCanvas(tab),
			       tab->manager.top_shadow_GC, top.x,
			       top.y, top.width, top.height);
	    }
	}
    }
    /*
     * Now that all the tab stuff is done, lets clear all the background
     * areas to our parents background color.
     */
    {
	Pixel  pixel;
	Pixmap pixmap;

	XtVaGetValues(XiGCParent(tab),
		      XmNbackground, &pixel,
		      XmNbackgroundPixmap, &pixmap,
		      NULL);
	
	if( ValidPixmap(pixmap) )
	{
	    SetTiledGC(XtDisplay(tab), gc, pixmap);
	}
	else
	{
	    SetSolidGC(XtDisplay(tab), gc, pixel);
	}
    }

    y = offset;
    cnt = 0;
    for( i = 1; i < XmTabBox__num_rows(tab); ++i, y += offset )
    {
	if( (idx = GetTabIndex(tab, i, 0)) < 0 ) continue;

	rect[cnt].x = geom[idx].x;
	rect[cnt].y = 0;
	rect[cnt].width = geom[idx].width;
	rect[cnt++].height = y;

	if( cnt >= _NUM_RECTS )
	{
	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    cnt=0;
	}
    }
    /*
     * We need to clear any area on the right side of the tabs. To do this
     * we find the tab in the upper right corner and clear down to the 
     * bottom and then check the top row to see if it is full.
     */
    last = -1;
    col = XmTabBox__num_columns(tab) - 1;
    for( i = 0; i < XmTabBox__num_rows(tab); ++i )
    {
	if( (idx = GetTabIndex(tab, i, col)) >= 0 )
	{
	    last = idx;
	}
    }

    if( last != -1 )
    {
	rect[cnt].x = 0;
	rect[cnt].y = geom[last].y + geom[last].height;
	rect[cnt].width = XtWidth(tab);
	rect[cnt].height = (int)XtHeight(tab) - rect[cnt].y;
	cnt++;

	if( cnt >= _NUM_RECTS )
	{
	    XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	    cnt=0;
	}
    }

    row = XmTabBox__num_rows(tab) - 1;
    col = XmTabBox__num_columns(tab) - 1;
    last = -1;
    if( GetTabIndex(tab, row, col) < 0 )
    {
	for( i = col; i >= 0 && last < 0; last = GetTabIndex(tab, row, --i) );

	if( last >= 0 )
	{
	    rect[cnt].x = (int)XtWidth(tab) - geom[last].width;
	    rect[cnt].y = geom[last].y + geom[last].height;
	    rect[cnt].width = geom[last].width;
	    rect[cnt].height = (int)XtHeight(tab) - rect[cnt].y;
	    cnt++;

	    if( cnt >= _NUM_RECTS )
	    {
		XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
		cnt=0;
	    }
	}
    }

    if( cnt > 0 )
    {
	XFillRectangles(XtDisplay(tab), XiCanvas(tab), gc, rect, cnt);
	cnt=0;
    }


    /*
     * If the users wants the special stacked effect then we are done so 
     * lets get out of here.
     */
    if( GetTabIndex(tab, 0, XmTabBox__num_columns(tab) - 1) >= 0 &&
        XmTabBox_stacked_effect(tab) ) return;

    /*
     * Now that we have all the tabs drawn we want to complete the
     * shadow line from the last tab in the first row to the last
     * tab in the last row.  Lets start by finding the last tab in the
     * first row and the last tab in the last row.
     */
    first = GetTabIndex(tab, 0, 0);;
    for( i = 0; i < XmTabBox__num_columns(tab); ++i )
    {
	if( (idx = GetTabIndex(tab, 0, i)) < 0 ) break;
	first = idx;
    }

    if( XmTabBox_stacked_effect(tab) )
    {
	if( first < 0 ) return;

	/*
	 * If we got here that means that we are doing the stacked effect
	 * and that row 0 is not complete. What this means is that we
	 * need to do is draw a line from the last tab in row 0 to the
	 * location where the row should end.
	 */
	y1 = geom[first].y + geom[first].height;
	y2 = XmTabBox__num_columns(tab) * geom[first].height;
    }
    else
    {
	y1 = geom[first].y + geom[first].height;
	y2 = XtHeight(tab);
    }


    /*
     * Now that we know what we are dealing with all we have to do
     * is draw the line.
     */

    XFillRectangle(XtDisplay(tab), XiCanvas(tab),
		   tab->manager.bottom_shadow_GC,
		   0, y1, shadow, y2 - y1);
}

static void
VerticalStackedRedisplay(XmTabBoxWidget tab)
{
    if( XmTabBox_tab_edge(tab) == XmTAB_EDGE_BOTTOM_RIGHT )
    {
	VerticalStackedRightEdgeRedisplay(tab);
    }
    else
    {
	VerticalStackedLeftEdgeRedisplay(tab);
    }
}

static XmTabAttributes
GetTabInfo(XmTabBoxWidget tab, int row, int column)
{
    int idx = GetTabIndex(tab, row, column);

    if( idx < 0 ) return( NULL );

    return( _XmTabbedStackListGet(XmTabBox_tab_list(tab), idx) );
}

static int
GetTabIndex(XmTabBoxWidget tab, int row, int column)
{
    XmTabbedStackList list = XmTabBox_tab_list(tab);
    int       i, count = _XmTabbedStackListCount(list);
    XiTabRect *rect = XmTabBox__actual(tab);

    if( row < 0 || column < 0 || count < 1 ) return( -1 );

    for( i = 0; i < count; ++i )
    {
	if( row == rect[i].row && column == rect[i].column )
	{
	    return( i );
	}
    }
    return( -1 );
}

static void
SelectTab(XmTabBoxWidget tab, XEvent *event, int old, int set)
{
    int old_row, set_row;

    if( old == set ) return;

    XmTabBox__selected(tab) = set;
    old_row = set_row = XmTabBox__actual(tab)[set].row;
    if( old >= 0 )
    {
	old_row = XmTabBox__actual(tab)[old].row;
    }
    if( XmTabBox_tab_mode(tab) == XmTABS_STACKED && old_row != set_row )
    {
	Layout(tab);
	if( XtIsRealized((Widget)tab) )
	{
	    Redisplay(XmTabBox__canvas(tab), NULL, False);
	}
    }
    else
    {
	if( old != -1 )
	{
	    DrawTab(tab, _XmTabbedStackListGet(XmTabBox_tab_list(tab), old),
		    &(XmTabBox__actual(tab)[old]), False, False);
	}
	DrawTab(tab, _XmTabbedStackListGet(XmTabBox_tab_list(tab), set),
		&(XmTabBox__actual(tab)[set]), True, True);
    }
    CallCallbacks(tab, event, old, set);
}

void
_XmTabBoxSelectTab(Widget widget, int idx)
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    if( !XmIsTabBox(widget) || idx < 0 || 
        idx >=_XmTabbedStackListCount(XmTabBox_tab_list(tab)) ) return;

    SelectTab(tab, NULL, XmTabBox__selected(tab), idx);
}

static Boolean
IsTabSensitive(XmTabBoxWidget tab, int idx)
{
    XmTabAttributes info = _XmTabbedStackListGet(XmTabBox_tab_list(tab), idx);

    if( info != NULL ) return( info->sensitive );

    return( False );
}

void
_XmTabBoxStackedGeometry(XmTabBoxWidget tab, Dimension size,
			 XRectangle *rect)
{
    XmTabbedStackList       list = XmTabBox_tab_list(tab);
    XmTabAttributes info;
    int             i, count = _XmTabbedStackListCount(list),
                    max_width, max_height, tab_width, tab_height,
                    num_cols, num_rows, offset;
    Dimension       d_width, d_height;

    if( count == 0 )
    {
	if( XmTabBox_orientation(tab) == XmHORIZONTAL )
	{
	    rect->width = 2 * tab->manager.shadow_thickness;
	    rect->height = tab->manager.shadow_thickness;
	}
	else
	{
	    rect->width = tab->manager.shadow_thickness;
	    rect->height = 2 * tab->manager.shadow_thickness;
	}

	if( rect->width < 1 ) rect->width = 1;
	if( rect->height < 1 ) rect->height = 1;
	return;
    }

    /*
     * Calculating the geometry we want for the stack layout turns
     * out to be straight forward.  What we do is find calculate the
     * size of the largest tab and then use that to calculate the
     * geometry we want.
     */
    max_width = max_height = 1;
    for( i = 0; i < count; ++i )
    {
	info = _XmTabbedStackListGet(list, i);
	XiCalcTabSize(tab, info, &d_width, &d_height);
	AssignMax(max_width, (int)d_width);
	AssignMax(max_height, (int)d_height);
    }

    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
    {
	/*
	 * Now that we know how big the tabs are lets see how many can fit in
	 * the available space.
	 */
	num_cols = (int)size / max_width;
	AssignMax(num_cols, 1);
	
	/*
	 * Now we know how many fit per row, so what we now need to do is
	 * how many rows we need.
	 */
	num_rows = (count/ num_cols) + ((count % num_cols == 0) ? 0 : 1);

	/*
	 * Now that we know how many rows and columns we need we can calculate
	 * overall size.
	 */

	offset = XmTabBox_tab_offset(tab);
	tab_width = size + ((num_rows - 1) * offset);
	tab_height = num_rows * max_height;
    }
    else
    {
	num_cols = (int)size/ max_height;
	AssignMax(num_cols, 1);
	num_rows = (count/ num_cols) + ((count % num_cols == 0) ? 0 : 1);
	offset = XmTabBox_tab_offset(tab);
	tab_width = num_rows * max_width;
	tab_height = size + ((num_rows - 1) * offset);
    }

    rect->width = tab_width;
    rect->height = tab_height;
}

int
XmTabBoxGetNumRows(Widget widget)
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    if( !XmIsTabBox(widget) ) return( 0 );

    return( XmTabBox__num_rows(tab) );
}

int
XmTabBoxGetNumColumns(Widget widget)
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    if( !XmIsTabBox(widget) ) return( 0 );

    return( XmTabBox__num_columns(tab) );
}

void
_XmTabBoxGetNumRowsColumns(Widget widget, int size, int *num_rows,
			   int *num_cols)
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;
    int            i, max, _num_rows, _num_cols, tmp, offset, cnt;
    XRectangle     *wanted = XmTabBox__wanted(tab);

    *num_rows = 0;
    *num_cols = 0;
    if( !XmIsTabBox(widget) ||
        (cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab))) == 0 ||
        (XmTabBox_tab_mode(tab) != XmTABS_STACKED &&
	 XmTabBox_tab_mode(tab) != XmTABS_STACKED_STATIC) )
    {
	return;
    }

    offset = XmTabBox_tab_offset(tab);
    max = 0;

    if( XmTabBox_orientation(tab) == XmHORIZONTAL )
    { 
	for( i = 0; i < cnt; ++i )
	{
	    AssignMax(max, (int)wanted[i].width);
	}
    }
    else
    {
	for( i = 0; i < cnt; ++i )
	{
	    AssignMax(max, (int)wanted[i].height);
	}
    }

    _num_cols = cnt;
    _num_rows = (int)(cnt/ _num_cols) + (cnt % _num_cols > 0 ? 1 : 0);
    tmp = (_num_cols * max) + (_num_rows * offset);
    while( _num_cols > 1 && tmp > size )
    {
	_num_cols--;
	_num_rows = (int)(cnt/ _num_cols) + (cnt % _num_cols > 0 ? 1 : 0);
	tmp = (_num_cols * max) + (_num_rows * offset);
    }
    *num_rows = _num_rows;
    *num_cols = _num_cols;
}

int
#ifndef _NO_PROTO
XmTabBoxGetNumTabs(Widget widget)
#else
XmTabBoxGetNumTabs(widget)
    Widget widget;
#endif
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    if( !XmIsTabBox(widget) ) return( 0 );

    return( _XmTabbedStackListCount(XmTabBox_tab_list(tab)) );
}

int
#ifndef _NO_PROTO
_XiGetTabIndex(Widget tab, int row, int column)
#else
_XiGetTabIndex(tab, row, column)
    XmTabBoxWidget tab;
    int            row, column;
#endif
{
    if( !XmIsTabBox(tab) ) return( -1 );

    return( GetTabIndex((XmTabBoxWidget)tab, row, column) );
}

int
#ifndef _NO_PROTO
_XmTabBoxGetTabWidth(Widget widget, int idx)
#else
_XmTabBoxGetTabWidth(widget, idx)
    Widget widget;
    int    idx;
#endif
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    if( !XmIsTabBox(widget) || idx < 0 ||
        idx > _XmTabbedStackListCount(XmTabBox_tab_list(tab)) ) return( -1 );

    return( XmTabBox__actual(tab)[idx].width );
}

int
#ifndef _NO_PROTO
_XmTabBoxGetTabHeight(Widget widget, int idx)
#else
_XmTabBoxGetTabHeight(widget, idx)
    Widget widget;
    int    idx;
#endif
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    if( !XmIsTabBox(widget) || idx < 0 ||
        idx > _XmTabbedStackListCount(XmTabBox_tab_list(tab)) ) return( -1 );

    return( XmTabBox__actual(tab)[idx].height );
}

static Widget
#ifndef _NO_PROTO
XiGCParent(XmTabBoxWidget tab)
#else
XiGCParent(tab)
    XmTabBoxWidget tab;
#endif
{
    Widget parent = XtParent(tab);

    if( XmIsTabStack(parent) )
    {
	return( XtParent(parent) );
    }
    return( parent );
}

int
#ifndef _NO_PROTO
XmTabBoxGetTabRow(Widget widget, int idx)
#else
XmTabBoxGetTabRow(widget, idx)
    Widget widget;
    int    idx;
#endif
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    if( !XmIsTabBox(widget) || idx < 0 ||
        idx > _XmTabbedStackListCount(XmTabBox_tab_list(tab)) ) return( -1 );

    return( XmTabBox__actual(tab)[idx].row );
}

static void
#ifndef _NO_PROTO
ResetImageCache(XmTabBoxWidget tab)
#else
ResetImageCache(tab)
    XmTabBoxWidget tab;
#endif
{
    int i, cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab));
    /*
     * First thing we will do is clear any existing cache.
     */
    if( XmTabBox__cache_size(tab) > 0 )
    {
	for( i = 0; i < XmTabBox__cache_size(tab); ++i )
	{
	    if( XmTabBox__cache(tab)[i].pixmap != NULL )
	    {
		XDestroyImage(XmTabBox__cache(tab)[i].pixmap);
	    }
	    if( XmTabBox__cache(tab)[i].label != NULL )
	    {
		XDestroyImage(XmTabBox__cache(tab)[i].label);
	    }
	}
    }

    /*
     * If we have no tabs then we will free the cache.
     */
    if( XmTabBox_tab_list(tab) == NULL || cnt == 0 )
    {
	XtFree((XtPointer) XmTabBox__cache(tab));
	XmTabBox__cache(tab) = NULL;
	XmTabBox__cache_size(tab) = 0;
	return;
    }

    /*
     * If we got here that means that we actually have some items so lets
     * size our cache to the correct size.
     */
    if( cnt != XmTabBox__cache_size(tab) )
    {
	XmTabBox__cache_size(tab) = cnt;
	XmTabBox__cache(tab) = (XiCache*)
	    XtRealloc((XtPointer)XmTabBox__cache(tab), 
		      sizeof(XiCache) * cnt);
    }

    /*
     * Then lets zero the cache out.
     */
    for( i = 0; i < cnt; ++i )
    {
	XmTabBox__cache(tab)[i].pixmap = NULL;
	XmTabBox__cache(tab)[i].label = NULL;
	XmTabBox__cache(tab)[i].sensitive = False;
    }
}

static void
#ifndef _NO_PROTO
FreeImageCache(XmTabBoxWidget tab)
#else
FreeImageCache(tab)
    XmTabBoxWidget tab;
#endif
{
    int i;

    /*
     * First thing we will do is clear any existing cache.
     */
    if( XmTabBox__cache_size(tab) > 0 )
    {
	for( i = 0; i < XmTabBox__cache_size(tab); ++i )
	{
	    if( XmTabBox__cache(tab)[i].pixmap != NULL )
	    {
		XDestroyImage(XmTabBox__cache(tab)[i].pixmap);
	    }
	    if( XmTabBox__cache(tab)[i].label != NULL )
	    {
		XDestroyImage(XmTabBox__cache(tab)[i].label);
	    }
	}
    }

    XtFree((XtPointer) XmTabBox__cache(tab));
    XmTabBox__cache(tab) = NULL;
    XmTabBox__cache_size(tab) = 0;
}

static int
#ifndef _NO_PROTO
InfoToIndex(XmTabBoxWidget tab, XmTabAttributes info)
#else
InfoToIndex(tab, info)
    XmTabBoxWidget  tab;
    XmTabAttributes info;
#endif
{
    return( (int)(info - _XmTabbedStackListArray(XmTabBox_tab_list(tab))) );
}

Widget
#ifndef _NO_PROTO
_XmTabBoxCanvas(Widget widget)
#else
_XmTabBoxCanvas(widget)
    Widget widget;
#endif
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;

    if( !XmIsTabBox(widget) ) return( NULL );

    return( XmTabBox__canvas(tab) );
}

int
_XmTabBoxGetMaxTabWidth(Widget widget)
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;
    int            i, max = 0, cnt;
    XRectangle     *wanted;

    if( !XmIsTabBox(widget) ) return( 0 );

    cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab));
    wanted = XmTabBox__wanted(tab);

    for( i = 0; i < cnt; ++i )
    {
	AssignMax(max, (int)wanted[i].width);
    }

    return( max );
}

int
_XmTabBoxGetMaxTabHeight(Widget widget)
{
    XmTabBoxWidget tab = (XmTabBoxWidget) widget;
    int            i, max = 0, cnt;
    XRectangle     *wanted;

    if( !XmIsTabBox(widget) ) return( 0 );

    cnt = _XmTabbedStackListCount(XmTabBox_tab_list(tab));
    wanted = XmTabBox__wanted(tab);

    for( i = 0; i < cnt; ++i )
    {
	AssignMax(max, (int)wanted[i].height);
    }

    return( max );
}

int
#ifndef _NO_PROTO
XmTabBoxXYToIndex(Widget widget, int x, int y)
#else
XmTabBoxXYToIndex(widget, x, y)
    Widget widget;
    int    x, y;
#endif
{
    if( !XmIsTabBox(widget) ) return( -1 );

    return( XiXYtoTab((XmTabBoxWidget)widget, x, y) );
}

static Visual*
GetShellVisual(Widget widget)
{
    Visual *visual;

    if( widget == NULL )
    {
	return( NULL );
    }
    if( XtIsShell(widget) )
    {

	XtVaGetValues(widget,
		      XmNvisual, &visual,
		      NULL);

	return( visual );
    }

    visual = GetShellVisual(XtParent(widget));

    if( visual == NULL )
    {
	return( DefaultVisualOfScreen(XtScreen(widget)) );
    }
    return( visual );
}

/*
 * XmRCallProc routine for checking font_list 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 offs, XrmValue *value)
{
  XmTabBoxWidget tb = (XmTabBoxWidget)wid;

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

}

Widget
XmCreateTabBox(Widget parent, String name, ArgList arg_list,
		 Cardinal arg_cnt)
{
    return( XtCreateWidget(name, xmTabBoxWidgetClass, parent, arg_list,
			   arg_cnt) );
}
