/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Microline Widget Library, originally made available under the NPL by Neuron Data <http://www.neurondata.com>.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * In addition, as a special exception to the GNU GPL, the copyright holders
 * give permission to link the code of this program with the Motif and Open
 * Motif libraries (or with modified versions of these that use the same
 * license), and distribute linked combinations including the two. You
 * must obey the GNU General Public License in all respects for all of
 * the code used other than linking with Motif/Open Motif. If you modify
 * this file, you may extend this exception to your version of the file,
 * but you are not obligated to do so. If you do not wish to do so,
 * delete this exception statement from your version.
 *
 * ***** END LICENSE BLOCK ***** */

#include "FolderP.h"
#include <X11/StringDefs.h>
#include <Xm/DrawnB.h>
#include <Xm/Label.h>
#include <Xm/Form.h>

#include <stdio.h>
#include <stdlib.h>

#ifdef SUNOS4
int fprintf(FILE *, char *, ...);
#endif

/* Create and Destroy */
static void ClassInitialize();
static void Initialize(Widget req, Widget newW, 
	ArgList args, Cardinal *nargs);
static void Destroy(Widget w);

/* Geometry, Drawing, Entry and Picking */
static void Realize(Widget w, XtValueMask *valueMask,
	XSetWindowAttributes *attr);
static void Redisplay(Widget w, XExposeEvent *event, Region region);
static void Layout(XmLFolderWidget f, int resizeIfNeeded);
static void LayoutTopBottom(XmLFolderWidget f, int resizeIfNeeded);
static void LayoutLeftRight(XmLFolderWidget f, int resizeIfNeeded);
static void Resize(Widget w);
static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request,
	XtWidgetGeometry *);
static void ChangeManaged(Widget w);
static void ConstraintInitialize(Widget, Widget w,
	ArgList args, Cardinal *nargs);
static void ConstraintDestroy(Widget w);
static void SetActiveTab(XmLFolderWidget f, Widget w, XEvent *event,
	Boolean notify);
static void DrawTabPixmap(XmLFolderWidget f, Widget tab, int active);
static void DrawManagerShadowLeftRight(XmLFolderWidget f, XRectangle *rect);
static void DrawManagerShadowTopBottom(XmLFolderWidget f, XRectangle *rect);
static void DrawTabHighlight(XmLFolderWidget f, Widget w);
static void SetTabPlacement(XmLFolderWidget f, Widget tab);
static void GetTabRect(XmLFolderWidget f, Widget tab, XRectangle *rect,
	int includeShadow);
static void DrawTabShadowArcTopBottom(XmLFolderWidget f, Widget w);
static void DrawTabShadowArcLeftRight(XmLFolderWidget f, Widget w);
static void DrawTabShadowLineTopBottom(XmLFolderWidget f, Widget w);
static void DrawTabShadowLineLeftRight(XmLFolderWidget f, Widget w);
static void DrawTabShadowNoneTopBottom(XmLFolderWidget f, Widget w);
static void DrawTabShadowNoneLeftRight(XmLFolderWidget f, Widget w);
static void SetGC(XmLFolderWidget f, int type);

/* Getting and Setting Values */
static Boolean SetValues(Widget curW, Widget reqW, Widget newW, 
	ArgList args, Cardinal *nargs);
static Boolean ConstraintSetValues(Widget curW, Widget, Widget newW,
	ArgList, Cardinal *); 
static void CopyRenderTable(XmLFolderWidget f);
static Boolean CvtStringToCornerStyle(Display *dpy, XrmValuePtr args,
	Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal,
	XtPointer *data);
static Boolean CvtStringToFolderResizePolicy(Display *dpy, XrmValuePtr args,
	Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal,
	XtPointer *data);
static Boolean CvtStringToTabPlacement(Display *dpy, XrmValuePtr args,
	Cardinal *numArgs, XrmValuePtr fromVal, XrmValuePtr toVal,
	XtPointer *data);

/* Utility */
static void GetCoreBackground(Widget w, int, XrmValue *value);
static void GetDefaultTabWidgetClass(Widget w, int, XrmValue *value);
static void GetManagerForeground(Widget w, int, XrmValue *value);
static Boolean ServerDrawsArcsLarge(Display *dpy, int debug);
static void CheckSetRenderTable(Widget wid,
    int offset,
    XrmValue *value);

/* Actions, Callbacks and Handlers */
static void Activate(Widget w, XEvent *event, String *, Cardinal *);
static void PrimActivate(Widget w, XtPointer, XtPointer);
static void PrimFocusIn(Widget w, XEvent *event, String *, Cardinal *);
static void PrimFocusOut(Widget w, XEvent *event, String *, Cardinal *);

static XtActionsRec actions[] =
	{
	{ "XmLFolderActivate",      Activate     },
	{ "XmLFolderPrimFocusIn",   PrimFocusIn  },
	{ "XmLFolderPrimFocusOut",  PrimFocusOut },
	};

#define MAX_TAB_ROWS 64

#define GC_SHADOWBOT  0
#define GC_SHADOWTOP  1
#define GC_BLANK      2
#define GC_UNSET      3

/* Folder Translations */

static char translations[] =
"<Btn1Down>: XmLFolderActivate()\n\
<EnterWindow>:   ManagerEnter()\n\
<LeaveWindow>:   ManagerLeave()\n\
<FocusOut>:      ManagerFocusOut()\n\
<FocusIn>:       ManagerFocusIn()";

/* Primitive Child Translations */

static char primTranslations[] =
"<FocusIn>: XmLFolderPrimFocusIn() PrimitiveFocusIn()\n\
<FocusOut>: XmLFolderPrimFocusOut() PrimitiveFocusOut()";

static XtResource resources[] =
	{
		/* Folder Resources */
		{
		XmNtabWidgetClass, XmCTabWidgetClass,
		XmRWidgetClass, sizeof(WidgetClass),
		XtOffset(XmLFolderWidget, folder.tabWidgetClass),
		XmRCallProc, (XtPointer)GetDefaultTabWidgetClass,
		},
		{
		XmNactivateCallback, XmCCallback,
		XmRCallback, sizeof(XtCallbackList),
		XtOffset(XmLFolderWidget, folder.activateCallback),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNactiveTab, XmCActiveTab,
		XmRInt, sizeof(int),
		XtOffset(XmLFolderWidget, folder.activeTab),
		XmRImmediate, (XtPointer)-1,
		},
		{
		XmNautoSelect, XmCAutoSelect,
		XmRBoolean, sizeof(Boolean),
		XtOffset(XmLFolderWidget, folder.autoSelect),
		XmRImmediate, (XtPointer)True,
		},
		{
		XmNblankBackground, XmCBlankBackground,
		XmRPixel, sizeof(Pixel),
		XtOffset(XmLFolderWidget, folder.blankBg),
		XmRCallProc, (XtPointer)GetCoreBackground,
		},
		{
		XmNblankBackgroundPixmap, XmCBlankBackgroundPixmap,
		XmRManForegroundPixmap, sizeof(Pixmap),
		XtOffset(XmLFolderWidget, folder.blankPix),
		XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP,
		},
		{
		XmNcornerDimension, XmCCornerDimension,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.cornerDimension),
		XmRImmediate, (XtPointer)2,
		},
		{
		XmNcornerStyle, XmCCornerStyle,
		XmRCornerStyle, sizeof(unsigned char),
		XtOffset(XmLFolderWidget, folder.cornerStyle),
		XmRImmediate, (XtPointer)XmCORNER_ARC,
		},
        {
        "pri.vate","Pri.vate",XmRBoolean,
        sizeof(Boolean), XtOffset(XmLFolderWidget, folder.check_set_render_table),
        XmRImmediate, (XtPointer) False
        },
		{
		XmNfontList, XmCFontList,
		XmRFontList, sizeof(XmFontList),
		XtOffset(XmLFolderWidget, folder.renderTable),
		XmRCallProc, (XtPointer)CheckSetRenderTable,
		},
		{
		XmNrenderTable, XmCRenderTable,
		XmRRenderTable, sizeof(XmRenderTable),
		XtOffset(XmLFolderWidget, folder.renderTable),
		XmRCallProc, (XtPointer)CheckSetRenderTable,
		},
		{
		XmNhighlightThickness, XmCHighlightThickness,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.highlightThickness),
		XmRImmediate, (XtPointer)2,
		},
		{
		XmNinactiveBackground, XmCInactiveBackground,
		XmRPixel, sizeof(Pixel),
		XtOffset(XmLFolderWidget, folder.inactiveBg),
		XmRCallProc, (XtPointer)GetCoreBackground,
		},
		{
		XmNinactiveForeground, XmCInactiveForeground,
		XmRPixel, sizeof(Pixel),
		XtOffset(XmLFolderWidget, folder.inactiveFg),
		XmRCallProc, (XtPointer)GetManagerForeground,
		},
		{
		XmNmarginHeight, XmCMarginHeight,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.marginHeight),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNmarginWidth, XmCMarginWidth,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.marginWidth),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNminTabWidth, XmCminTabWidth,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.minTabWidth),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNmaxTabWidth, XmCmaxTabWidth,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.maxTabWidth),
		XmRImmediate, (XtPointer)100,
		},
		{
		XmNpixmapMargin, XmCPixmapMargin,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.pixmapMargin),
		XmRImmediate, (XtPointer)2,
		},
		{
		XmNresizePolicy, XmCFolderResizePolicy,
		XmRFolderResizePolicy, sizeof(unsigned char),
		XtOffset(XmLFolderWidget, folder.resizePolicy),
		XmRImmediate, (XtPointer)XmRESIZE_STATIC,
		},
		{
		XmNrotateWhenLeftRight, XmCRotateWhenLeftRight,
		XmRBoolean, sizeof(Boolean),
		XtOffset(XmLFolderWidget, folder.allowRotate),
		XmRImmediate, (XtPointer)True,
		},
		{
		XmNspacing, XmCSpacing,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.spacing),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNtabBarHeight, XmCTabBarHeight,
		XmRDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, folder.tabBarHeight),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNtabCount, XmCTabCount,
		XmRInt, sizeof(int),
		XtOffset(XmLFolderWidget, folder.tabCount),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNtabPlacement, XmCTabPlacement,
		XmRTabPlacement, sizeof(unsigned char),
		XtOffset(XmLFolderWidget, folder.tabPlacement),
		XmRImmediate, (XtPointer)XmFOLDER_TOP,
		},
		{
		XmNtabsPerRow, XmCTabsPerRow,
		XmRInt, sizeof(int),
		XtOffset(XmLFolderWidget, folder.tabsPerRow),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNtabWidgetList, XmCReadOnly,
		XmRPointer, sizeof(XtPointer),
		XtOffset(XmLFolderWidget, folder.tabs),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNtabTranslations, XmCTranslations,
		XmRTranslationTable, sizeof(XtTranslations),
		XtOffset(XmLFolderWidget, folder.primTrans),
		XmRString, (XtPointer)primTranslations,
		},
		{
		XmNdebugLevel, XmCDebugLevel,
		XmRInt, sizeof(int),
		XtOffset(XmLFolderWidget, folder.debugLevel),
		XmRImmediate, (XtPointer)0,
		},
		/* Overridden inherited resources */
		{
		XmNshadowThickness, XmCShadowThickness,
		XmRHorizontalDimension, sizeof(Dimension),
		XtOffset(XmLFolderWidget, manager.shadow_thickness),
		XmRImmediate, (XtPointer)2,
		},
    };

static XtResource constraint_resources[] =
	{
		/* Folder Constraint Resources */
		{
		XmNtabFreePixmaps, XmCTabFreePixmaps,
		XmRBoolean, sizeof(Boolean),
		XtOffset(XmLFolderConstraintPtr, folder.freePix),
		XmRImmediate, (XtPointer)False,
		},
		{
		XmNtabInactivePixmap, XmCTabInactivePixmap,
		XmRPrimForegroundPixmap, sizeof(Pixmap),
		XtOffset(XmLFolderConstraintPtr, folder.inactPix),
		XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP,
		},
		{
		XmNtabManagedName, XmCTabManagedName,
		XmRString, sizeof(char *),
		XtOffset(XmLFolderConstraintPtr, folder.managedName),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNtabManagedWidget, XmCTabManagedWidget,
		XmRWidget, sizeof(Widget),
		XtOffset(XmLFolderConstraintPtr, folder.managedW),
		XmRImmediate, (XtPointer)0,
		},
		{
		XmNtabPixmap, XmCTabPixmap,
		XmRPrimForegroundPixmap, sizeof(Pixmap),
		XtOffset(XmLFolderConstraintPtr, folder.pix),
		XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP,
		},
	};

XmLFolderClassRec xmlFolderClassRec =
	{
		{ /* core_class */
		(WidgetClass)&xmManagerClassRec,          /* superclass         */
		"XmLFolder",                              /* class_name         */
		sizeof(XmLFolderRec),                     /* widget_size        */
		ClassInitialize,                          /* class_init         */
		0,                                        /* class_part_init    */
		FALSE,                                    /* class_inited       */
		(XtInitProc)Initialize,                   /* initialize         */
		0,                                        /* initialize_hook    */
		(XtRealizeProc)Realize,                   /* realize            */
		(XtActionList)actions,                    /* actions            */
		(Cardinal)XtNumber(actions),              /* num_actions        */
		(XtResource *)resources,				  /* resources          */
		XtNumber(resources),                      /* num_resources      */
		NULLQUARK,                                /* xrm_class          */
		TRUE,                                     /* compress_motion    */
		XtExposeCompressMultiple,                 /* compress_exposure  */
		TRUE,                                     /* compress_enterlv   */
		TRUE,                                     /* visible_interest   */
		(XtWidgetProc)Destroy,                    /* destroy            */
		(XtWidgetProc)Resize,                     /* resize             */
		(XtExposeProc)Redisplay,                  /* expose             */
		(XtSetValuesFunc)SetValues,               /* set_values         */
		0,                                        /* set_values_hook    */
		XtInheritSetValuesAlmost,                 /* set_values_almost  */
		0,                                        /* get_values_hook    */
		0,                                        /* accept_focus       */
		XtVersion,                                /* version            */
		0,                                        /* callback_private   */
		translations,                             /* tm_table           */
		0,                                        /* query_geometry     */
		0,                                        /* display_acceleratr */
		0,                                        /* extension          */
		},
		{ /* composite_class */
		(XtGeometryHandler)GeometryManager,       /* geometry_manager   */
		(XtWidgetProc)ChangeManaged,              /* change_managed     */
		XtInheritInsertChild,                     /* insert_child       */
		XtInheritDeleteChild,                     /* delete_child       */
		0,                                        /* extension          */
		},
		{ /* constraint_class */
		(XtResource *)constraint_resources,		  /* subresources       */
		XtNumber(constraint_resources),           /* subresource_count  */
		sizeof(XmLFolderConstraintRec),           /* constraint_size    */
		(XtInitProc)ConstraintInitialize,         /* initialize         */
		(XtWidgetProc)ConstraintDestroy,          /* destroy            */
		(XtSetValuesFunc)ConstraintSetValues,     /* set_values         */
		0,                                        /* extension          */
		},
		{ /* manager_class */
		XtInheritTranslations,                    /* translations       */
		0,                                        /* syn resources      */
		0,                                        /* num syn_resources  */
		0,                                        /* get_cont_resources */
		0,                                        /* num_get_cont_resrc */
		XmInheritParentProcess,                   /* parent_process     */
		0,                                        /* extension          */
		},
		{ /* folder_class */
		0,                                        /* unused             */
		}
	};

WidgetClass xmlFolderWidgetClass = (WidgetClass)&xmlFolderClassRec;



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

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

}
/*
   Create and Destroy
*/

static void 
ClassInitialize(void)
{
  XmLInitialize();
  
  XtSetTypeConverter(XmRString, XmRCornerStyle,
		     CvtStringToCornerStyle, 0, 0, XtCacheNone, 0);
  XtSetTypeConverter(XmRString, XmRFolderResizePolicy,
		     CvtStringToFolderResizePolicy, 0, 0, XtCacheNone, 0);
  XtSetTypeConverter(XmRString, XmRTabPlacement,
		     CvtStringToTabPlacement, 0, 0, XtCacheNone, 0);
}

static void 
Initialize(Widget req, 
	   Widget newW, 
	   ArgList args, 
	   Cardinal *narg) 
{
  Display *dpy;
  /*  Window root;*/
  XmLFolderWidget f;
  
  f = (XmLFolderWidget)newW;
  dpy = XtDisplay((Widget)f);
  
  if (f->core.width == 0) 
    f->core.width = 100;
  if (f->core.height == 0) 
    f->core.height = 100;
  
  f->folder.gc = 0;
  
  f->folder.tabAllocCount = 32;
  f->folder.tabs = (Widget *)malloc(sizeof(Widget) * 32);
  f->folder.tabHeight = 0;
  f->folder.tabWidth = 0;
  f->folder.activeW = 0;
  f->folder.focusW = 0;
  f->folder.allowLayout = 1;
  f->folder.activeRow = -1;
  CopyRenderTable(f);
  
  if (f->folder.tabBarHeight)
    {
      XmLWarning((Widget)f, "Initialize() - can't set tabBarHeight");
      f->folder.tabBarHeight = 0;
    }
  if (f->folder.tabCount)
    {
      XmLWarning((Widget)f, "Initialize() - can't set tabCount");
      f->folder.tabCount = 0;
    }
  if (f->folder.activeTab != -1)
    {
      XmLWarning((Widget)f, "Initialize() - can't set activeTab");
      f->folder.activeTab = -1;
    }
  if (f->folder.cornerDimension < 1)
    {
      XmLWarning((Widget)f, "Initialize() - cornerDimension can't be < 1");
      f->folder.cornerDimension = 1;
    }
  f->folder.serverDrawsArcsLarge = ServerDrawsArcsLarge(dpy,
							f->folder.debugLevel);
  if (f->folder.minTabWidth <= 0)
    {
      /* a quick hack to determine the minimum tab width - enough
	 to show at least one character of the tab string */
      XmString st = XmStringCreateSimple("W");
      f->folder.minTabWidth = XmStringWidth(f->folder.renderTable, st);
      XmStringFree(st);
    }
}

static void 
Destroy(Widget w)
{
  XmLFolderWidget f;
  Display *dpy;
  
  f = (XmLFolderWidget)w;
  dpy = XtDisplay(w);
  if (f->folder.debugLevel)
    fprintf(stderr, "Folder destroy: \n");
  if (f->folder.tabs)
    free((char *)f->folder.tabs);
  if (f->folder.gc)
    XFreeGC(dpy, f->folder.gc);
  XmRenderTableFree(f->folder.renderTable);
}

/*
  Geometry, Drawing, Entry and Picking
  */

static void 
Realize(Widget w, 
	XtValueMask *valueMask, 
	XSetWindowAttributes *attr)
{
  XmLFolderWidget f;
  Display *dpy;
  WidgetClass superClass;
  XtRealizeProc realize;
  XGCValues values;
  XtGCMask mask;
  
  f = (XmLFolderWidget)w;
  dpy = XtDisplay(f);
  superClass = xmlFolderWidgetClass->core_class.superclass;
  realize = superClass->core_class.realize;
  (*realize)(w, valueMask, attr);
  
  if (!f->folder.gc)
    {
      values.foreground = f->manager.foreground;
      mask = GCForeground;
      f->folder.gc = XCreateGC(dpy, XtWindow(f), mask, &values);
      if (f->folder.autoSelect == True && f->folder.tabCount)
	XmLFolderSetActiveTab(w, 0, False);
    }
}

static void 
Redisplay(Widget w, 
	  XExposeEvent *event, 
	  Region region)
{
  Display *dpy;
  Window win;
  XmLFolderWidget f;
  XmLFolderConstraintRec *fc;
  XRectangle eRect, rRect, rect;
  /* XSegment *topSeg, *botSeg; */
  /*  int tCount, bCount; */
  Widget tab;
  int i;
  
  f = (XmLFolderWidget)w;
  if (!XtIsRealized(w))
    return;
  if (!f->core.visible)
    return;
  dpy = XtDisplay(f);
  win = XtWindow(f);
  
  if (event)
    {
      eRect.x = event->x;
      eRect.y = event->y;
      eRect.width = event->width;
      eRect.height = event->height;
      if (f->folder.debugLevel > 1)
	fprintf(stderr, "XmLFolder: Redisplay x %d y %d w %d h %d\n",
		event->x, event->y, event->width, event->height);
    }
  else
    {
      eRect.x = 0;
      eRect.y = 0;
      eRect.width = f->core.width;
      eRect.height = f->core.height;
    }
  if (!eRect.width || !eRect.height)
    return;
  
  if (f->folder.tabPlacement == XmFOLDER_TOP)
    {
      rRect.x = 0;
      rRect.y = f->folder.tabHeight;
      rRect.width = f->core.width;
      rRect.height = f->core.height - f->folder.tabHeight;
    }
  else if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    {
      rRect.x = 0;
      rRect.y = 0;
      rRect.width = f->core.width;
      rRect.height = f->core.height - f->folder.tabHeight;
    }
  if (f->folder.tabPlacement == XmFOLDER_LEFT)
    {
      rRect.x = f->folder.tabWidth;
      rRect.y = 0;
      rRect.width = f->core.width - f->folder.tabWidth;
      rRect.height = f->core.height;
    }
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    {
      rRect.x = 0;
      rRect.y = 0;
      rRect.width = f->core.width - f->folder.tabWidth;
      rRect.height = f->core.height;
    }
  if (XmLRectIntersect(&eRect, &rRect) != XmLRectOutside)
    {
      if (f->folder.tabPlacement == XmFOLDER_TOP ||
	  f->folder.tabPlacement == XmFOLDER_BOTTOM)
	DrawManagerShadowTopBottom(f, &rRect);
      else
	DrawManagerShadowLeftRight(f, &rRect);
    }

  if (!f->folder.tabCount)
    return;

  rRect.x = 0;
  rRect.y = 0;
  rRect.width = 0;
  rRect.height = 0;

	/* Draw tabs */
  for (i = 0; i < f->folder.tabCount; i++)
    {
      tab = f->folder.tabs[i];
      if (!XtIsManaged(tab))
	continue;
      fc = (XmLFolderConstraintRec *)(tab->core.constraints);
      GetTabRect(f, tab, &rRect, 0);

      /* include spacing in intersect test */
      rect = rRect;
      if (f->folder.tabPlacement == XmFOLDER_TOP ||
	  f->folder.tabPlacement == XmFOLDER_BOTTOM)
	rect.width += f->folder.spacing;
      else
	rect.height += f->folder.spacing;

      /* include indent in intersect test */
      if (f->folder.tabsPerRow)
	{
	  if (rRect.x == 2)
	    rect.x = 0;
	  if (rRect.y == 2)
	    rect.y = 0;
	  if (rRect.x + rRect.width == f->core.width - 2)
	    rect.width += 2;
	  if (rRect.y + rRect.height == f->core.height - 2)
	    rect.height += 2;
	}

      if (XmLRectIntersect(&eRect, &rect) == XmLRectOutside)
	continue;
      if (event && XRectInRegion(region, rect.x, rect.y,
				 rect.width, rect.height) == RectangleOut)
	continue;

      if (f->folder.debugLevel > 1)
	fprintf(stderr, "XmLFolder: Redisplay tab for widget %d\n", i);
      if (tab == f->folder.activeW)
	{
	  XtVaSetValues(tab,
			XmNbackground, f->core.background_pixel,
			XmNforeground, f->manager.foreground,
			NULL);
	}
      else
	{
	  XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
	  XFillRectangle(dpy, win, f->folder.gc,
			 rRect.x, rRect.y, rRect.width, rRect.height);
	  XtVaSetValues(tab,
			XmNbackground, f->folder.inactiveBg,
			XmNforeground, f->folder.inactiveFg,
			NULL);
	}

      if (f->folder.tabPlacement == XmFOLDER_TOP ||
	  f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  if (f->folder.cornerStyle == XmCORNER_LINE)
	    DrawTabShadowLineTopBottom(f, tab);
	  else if (f->folder.cornerStyle == XmCORNER_ARC)
	    DrawTabShadowArcTopBottom(f, tab);
	  else
	    DrawTabShadowNoneTopBottom(f, tab);
	}
      else
	{
	  if (f->folder.cornerStyle == XmCORNER_LINE)
	    DrawTabShadowLineLeftRight(f, tab);
	  else if (f->folder.cornerStyle == XmCORNER_ARC)
	    DrawTabShadowArcLeftRight(f, tab);
	  else
	    DrawTabShadowNoneLeftRight(f, tab);
	}

      if (f->folder.focusW == tab)
	DrawTabHighlight(f, tab);

      if (tab == f->folder.activeW &&
	  fc->folder.pix != XmUNSPECIFIED_PIXMAP &&
	  (fc->folder.maxPixWidth || fc->folder.maxPixHeight))
	DrawTabPixmap(f, tab, 1);
      else if (tab != f->folder.activeW &&
	       fc->folder.inactPix != XmUNSPECIFIED_PIXMAP &&
	       (fc->folder.maxPixWidth || fc->folder.maxPixHeight))
	DrawTabPixmap(f, tab, 0);

      SetGC(f, GC_BLANK);

      /* draw indent */
      if (f->folder.tabsPerRow)
	{
	  if (rRect.x == 2)
	    {
	      rect = rRect;
	      rect.x = 0;
	      rect.width = 2;
	      XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y,
			     rect.width, rect.height);
	    }
	  if (rRect.y == 2)
	    {
	      rect = rRect;
	      rect.y = 0;
	      rect.height = 2;
	      XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y,
			     rect.width, rect.height);
	    }
	  if (rRect.x + rRect.width == f->core.width - 2)
	    {
	      rect = rRect;
	      rect.x = f->core.width - 2;
	      rect.width = 2;
	      XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y,
			     rect.width, rect.height);
	    }
	  if (rRect.y + rRect.height == f->core.height - 2)
	    {
	      rect = rRect;
	      rect.y = f->core.height - 2;
	      rect.height = 2;
	      XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y,
			     rect.width, rect.height);
	    }
	}

      if (f->folder.spacing)
	{
	  if (f->folder.tabPlacement == XmFOLDER_TOP ||
	      f->folder.tabPlacement == XmFOLDER_BOTTOM)
	    XFillRectangle(dpy, win, f->folder.gc, rRect.x + rRect.width,
			   rRect.y, f->folder.spacing, rRect.height);
	  else
	    XFillRectangle(dpy, win, f->folder.gc, rRect.x,
			   rRect.y + rRect.height, rRect.width, f->folder.spacing);
	}

      SetGC(f, GC_UNSET);
    }

  /* Draw empty area */
  if (!f->folder.tabsPerRow)
    {
      if (f->folder.tabPlacement == XmFOLDER_TOP ||
	  f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  rRect.x += rRect.width + f->folder.spacing;
	  if ((int)f->core.width > rRect.x)
	    {
	      if (f->folder.tabPlacement == XmFOLDER_TOP)
		rRect.y = 0;
	      else
		rRect.y = f->core.height - f->folder.tabHeight;
	      rRect.width = f->core.width - rRect.x;
	      rRect.height = f->folder.tabHeight;
	      SetGC(f, GC_BLANK);
	      XFillRectangle(dpy, win, f->folder.gc,
			     rRect.x, rRect.y, rRect.width, rRect.height);
	      SetGC(f, GC_UNSET);
	    }
	}
      else
	{
	  rRect.y += rRect.height + f->folder.spacing;
	  if ((int)f->core.height > rRect.y)
	    {
	      if (f->folder.tabPlacement == XmFOLDER_LEFT)
		rRect.x = 0;
	      else
		rRect.x = f->core.width - f->folder.tabWidth;
	      rRect.width = f->folder.tabWidth;
	      rRect.height = f->core.height - rRect.y;
	      SetGC(f, GC_BLANK);
	      XFillRectangle(dpy, win, f->folder.gc,
			     rRect.x, rRect.y, rRect.width, rRect.height);
	      SetGC(f, GC_UNSET);
	    }
	}
    }
}

static void 
Layout(XmLFolderWidget f, 
       int resizeIfNeeded)
{
  /*  Window win;*/

  if (!f->folder.allowLayout)
    return;
  f->folder.allowLayout = 0;
  if (f->folder.tabPlacement == XmFOLDER_LEFT ||
      f->folder.tabPlacement == XmFOLDER_RIGHT)
    LayoutLeftRight(f, resizeIfNeeded);
  else
    LayoutTopBottom(f, resizeIfNeeded);
  if (XtIsRealized((Widget)f) && f->core.visible)
    XClearArea(XtDisplay(f), XtWindow(f), 0, 0, 0, 0, True);
  f->folder.allowLayout = 1;
}

static void 
LayoutTopBottom(XmLFolderWidget f, 
		int resizeIfNeeded)
{
  Display *dpy;
  Window root;
  int i, tabNum, x, y, w, h, pad1, pad2;
  int rowNum, numRows, rowHeight, rowX, rowY;
  WidgetList children;
  Widget tab, child;
  XmLFolderConstraintRec *fc;
  XtGeometryResult result;
  unsigned int inactPixHeight, pixHeight;
  unsigned int inactPixWidth, pixWidth;
  unsigned int pixBW, pixDepth;
  Dimension height, minHeight;
  Dimension width, minWidth, borderWidth;
  Dimension co;
  int st, ht;
  int tabFit = 0, tgtTabWidth = 0;
  int tabPaddingWidth, tailSpace = 0;
  Boolean map, isManaged;
  struct
  {
    int width, height, numTabs, y;
  } rows[MAX_TAB_ROWS];

  dpy = XtDisplay(f);
  children = f->composite.children;
  st = f->manager.shadow_thickness;
  ht = f->folder.highlightThickness;

  /* calculate corner offset */
  if (f->folder.cornerStyle == XmCORNER_LINE)
    co = (Dimension)((double)f->folder.cornerDimension * .5 + .99);
  else if (f->folder.cornerStyle == XmCORNER_ARC)
    co = (Dimension)((double)f->folder.cornerDimension * .3 + .99);
  else
    co = 0;

  /* caculate tabHeight, minWidth, minHeight, row y positions, */
  /* row heights and tab pixmap dimensions */
  rowX = 0;
  rowY = 0;
  rowHeight = 0;
  rowNum = 0;
  tabNum = 0;
  minWidth = 0;

  if (f->folder.tabCount && f->folder.resizePolicy == XmRESIZE_PACK)
    {
      int maxTabWidth = f->folder.maxTabWidth;
      int tabEffCount = 0;

      for (i = 0; i < f->folder.tabCount; i++)
	{
	  tab = f->folder.tabs[i];
	  if (!XtIsManaged(tab))
            continue;
	  tabEffCount++;
	}
	
      tabPaddingWidth = (st + co + f->folder.marginWidth + ht +
	      f->folder.tabs[0]->core.border_width) * 2;
      if (maxTabWidth * tabEffCount > f->core.width)
        {
      	  tgtTabWidth = f->core.width/tabEffCount - tabPaddingWidth;
	  tailSpace = f->core.width % tabEffCount;
	  tabFit = 1;
	  
	  /* if tabs get too small */
	  if (tgtTabWidth < f->folder.minTabWidth) {
	    tgtTabWidth = f->folder.minTabWidth;
	    tabFit = 0;
	  }
	}
      else
        {
      	  tgtTabWidth = maxTabWidth - tabPaddingWidth;
	  tabFit = 0;
	}
    }
  
  for (i = 0; i < f->folder.tabCount; i++)
    {
      tab = f->folder.tabs[i];
      if (!XtIsManaged(tab))
	continue;

      if (f->folder.resizePolicy == XmRESIZE_PACK)
        {
	  if (tabFit)
            {
	      XtVaSetValues(tab, XmNwidth,
      		      tailSpace? tgtTabWidth+1: tgtTabWidth, NULL);
	      if (tailSpace)
	      	 tailSpace--;
            }
	  else 
	    {
	       XtVaSetValues(tab, XmNwidth, tgtTabWidth, NULL);
	    }
	}

      fc = (XmLFolderConstraintRec *)(tab->core.constraints);
      
      /* check for start of a new row */
      fc->folder.firstInRow = False;
      if (!tabNum)
	fc->folder.firstInRow = True;
      if (f->folder.tabsPerRow && tabNum == f->folder.tabsPerRow)
	{
	  fc->folder.firstInRow = True;

	  /* store prev row values and start next row */
	  if (rowX)
	    rowX -= f->folder.spacing;
	  rows[rowNum].y = rowY;
	  rows[rowNum].width = rowX;
	  rows[rowNum].height = rowHeight;
	  rows[rowNum].numTabs = tabNum;
	  if (f->folder.debugLevel)
	    {
	      fprintf(stderr, "XmLFolder: Layout: ");
	      fprintf(stderr, "row %d: y %d w %d h %d numTabs %d\n",
		      rowNum, rowY, rowX, rowHeight, tabNum);
	    }
	  rowY += rowHeight;
	  rowHeight = 0;
	  if (rowX > (int)minWidth)
	    minWidth = rowX;
	  rowX = 0;
	  tabNum = 0;
	  rowNum++;
	  if (rowNum == MAX_TAB_ROWS - 1)
	    {
	      XmLWarning((Widget)f, "Layout ERROR - too many rows\n");
	      return;
	    }
	}

      /* make sure row height > maximum tab height */
      height = co + st + tab->core.height + tab->core.border_width * 2 +
	f->folder.marginHeight * 2 + ht * 2;
      if ((int)height > rowHeight)
	rowHeight = height;

      /* calc pixmap dimensions/maximum pixmap height */
      fc->folder.pixWidth = 0;
      fc->folder.pixHeight = 0;
      fc->folder.inactPixWidth = 0;
      fc->folder.inactPixHeight = 0;
      fc->folder.maxPixWidth = 0;
      fc->folder.maxPixHeight = 0;
      if (fc->folder.pix != XmUNSPECIFIED_PIXMAP)
	{
	  XGetGeometry(dpy, fc->folder.pix, &root,
		       &x, &y, &pixWidth, &pixHeight, &pixBW, &pixDepth);
	  fc->folder.pixWidth = pixWidth;
	  fc->folder.maxPixWidth = pixWidth;
	  fc->folder.pixHeight = pixHeight;
	  fc->folder.maxPixHeight = pixHeight;
	  height = co + st + pixHeight + f->folder.marginHeight * 2 + ht * 2;
	  if ((int)height > rowHeight)
	    rowHeight = height;
	}
      if (fc->folder.inactPix != XmUNSPECIFIED_PIXMAP)
	{
	  XGetGeometry(dpy, fc->folder.inactPix, &root, &x, &y,
		       &inactPixWidth, &inactPixHeight, &pixBW, &pixDepth);
	  fc->folder.inactPixWidth = inactPixWidth;
	  if (inactPixWidth > fc->folder.maxPixWidth)
	    fc->folder.maxPixWidth = inactPixWidth;
	  fc->folder.inactPixHeight = inactPixHeight;
	  if (inactPixHeight > fc->folder.maxPixHeight)
	    fc->folder.maxPixHeight = inactPixHeight;
	  height = co + st + inactPixHeight +
	    f->folder.marginHeight * 2 + ht * 2;
	  if ((int)height > rowHeight)
	    rowHeight = height;
	}

      /* increment rowX to move on to the next tab */
      rowX += st * 2 + co * 2 + f->folder.marginWidth * 2 + ht * 2 +
	XtWidth(tab) + tab->core.border_width * 2;
      if (fc->folder.maxPixWidth)
	rowX += fc->folder.maxPixWidth + f->folder.pixmapMargin;
      rowX += f->folder.spacing;

      tabNum++;
      fc->folder.row = rowNum;
    }

  /* complete calcuations for last row */
  if (rowX)
    rowX -= f->folder.spacing;
  rows[rowNum].y = rowY;
  rows[rowNum].width = rowX;
  rows[rowNum].height = rowHeight;
  rows[rowNum].numTabs = tabNum;
  numRows = rowNum + 1;
  if (f->folder.debugLevel)
    {
      fprintf(stderr, "XmLFolder: Layout: ");
      fprintf(stderr, "row %d: y %d w %d h %d numTabs %d\n",
	      rowNum, rowY, rowX, rowHeight, tabNum);
    }
  f->folder.tabHeight = rowY + rowHeight;
  f->folder.tabBarHeight = f->folder.tabHeight;
  minHeight = f->folder.tabHeight;
  if ((int)minWidth < rowX)
    minWidth = rowX;

  /* add space for indent of upper rows */
  if (f->folder.tabsPerRow && minWidth)
    minWidth += 4;

  if (f->folder.debugLevel)
    {
      fprintf(stderr, "XmLFolder: Layout: ");
      fprintf(stderr, "tab bar minimum w %d h %d\n",
	      (int)minWidth, (int)minHeight);
    }

  /* calculate width and height of non-tab children ensure */
  /* minWidth > width and minHeight > height */
  for (i = 0; i < f->composite.num_children; i++)
    {
      child = children[i];
      if (XtIsSubclass(child, xmPrimitiveWidgetClass))
	continue;

      height = XtHeight(child) + f->folder.tabHeight + st * 2;
      if (XtIsWidget(child))
	height += child->core.border_width * 2;
      if (height > minHeight)
	minHeight = height;

      width = XtWidth(child) + st * 2;
      if (XtIsWidget(child))
	width += child->core.border_width * 2;
      if (width > minWidth)
	minWidth = width;
    }

  if (f->folder.debugLevel)
    {
      fprintf(stderr, "XmLFolder: Layout: ");
      fprintf(stderr, "with non-tabs minimum w %d h %d\n",
	      (int)minWidth, (int)minHeight);
    }

  /* Resize folder if needed */
  if (resizeIfNeeded && f->folder.resizePolicy != XmRESIZE_NONE)
    {
      if (minWidth <= 0)
	minWidth = 1;
      if (minHeight <= 0)
	minHeight = 1;
      result = XtMakeResizeRequest((Widget)f, minWidth, minHeight,
				   &width, &height);
      if (result == XtGeometryAlmost)
	XtMakeResizeRequest((Widget)f, width, height, NULL, NULL);
    }

  /* move active row to bottom */
  tab = f->folder.activeW;
  if (tab)
    {
      fc = (XmLFolderConstraintRec *)(tab->core.constraints);
      rowNum = fc->folder.row;
      f->folder.activeRow = rowNum;
      rows[rowNum].y = f->folder.tabHeight - rows[rowNum].height;
      for (i = rowNum + 1; i < numRows; i++)
	rows[i].y -= rows[rowNum].height;
    }
  else
    f->folder.activeRow = -1;

  /* configure tab children */
  for (i = 0; i < f->folder.tabCount; i++)
    {
      tab = f->folder.tabs[i];
      if (!XtIsManaged(tab))
	continue;
      fc = (XmLFolderConstraintRec *)(tab->core.constraints);
      rowNum = fc->folder.row;

      /* calculate tab x */
      if (fc->folder.firstInRow == True)
	{
	  if (f->folder.tabsPerRow && rowNum != f->folder.activeRow)
	    x = 2;
	  else
	    x = 0;
	}
      fc->folder.x = x;
      x += st + co + f->folder.marginWidth + ht;
      if (fc->folder.maxPixWidth)
	x += fc->folder.maxPixWidth + f->folder.pixmapMargin;

      /* calculate tab y and tab height */
      fc->folder.height = rows[rowNum].height;
      if (f->folder.tabPlacement == XmFOLDER_TOP)
	{
	  fc->folder.y = rows[rowNum].y;
	  y = fc->folder.y + fc->folder.height - f->folder.marginHeight -
	    ht - XtHeight(tab) - tab->core.border_width * 2;
	}
      else
	{
	  fc->folder.y = f->core.height - rows[rowNum].y -
	    rows[rowNum].height;
	  y = fc->folder.y + f->folder.marginHeight + ht;
	}

      /* calculate tab padding */
      pad1 = 0;
      pad2 = 0;
      w = f->core.width - rows[rowNum].width;
      if (rowNum != f->folder.activeRow)
	w -= 4;
      if (f->folder.tabsPerRow && w > 0)
	{
	  pad1 = w / (rows[rowNum].numTabs * 2);
	  pad2 = pad1;
	  if (fc->folder.firstInRow == True)
	    pad2 += w - (pad1 * rows[rowNum].numTabs * 2);
	}
      x += pad1;

      /* move tab widget into place */
      XtMoveWidget(tab, x, y);

      /* calculate tab width and move to next tab */
      x += pad2 + XtWidth(tab) + tab->core.border_width * 2 + ht +
	f->folder.marginWidth + co + st;
      fc->folder.width = x - fc->folder.x; 
      x += f->folder.spacing;
    }

  /* configure non-tab children */
  for (i = 0; i < f->composite.num_children; i++)
    {
      child = children[i];
      if (XtIsSubclass(child, xmPrimitiveWidgetClass))
	continue;
      if (f->folder.resizePolicy == XmRESIZE_NONE)
	continue;

      w = (int)f->core.width - st * 2;
      h = (int)f->core.height - (int)f->folder.tabHeight - st * 2;
      if (h <= 0 || w <= 0)
	continue;
      /* manager widgets will not configure correctly unless they */
      /* are managed, so manage then unmapped if they are unmanaged */
      isManaged = True;
      if (!XtIsManaged(child))
	{
	  XtVaGetValues(child,
			XmNmappedWhenManaged, &map,
			NULL);
	  XtVaSetValues(child,
			XmNmappedWhenManaged, False,
			NULL);
	  XtManageChild(child);
	  isManaged = False;
	}
      x = st;
      if (f->folder.tabPlacement == XmFOLDER_TOP)
	y = f->folder.tabHeight + st;
      else
	y = st;
      width = w;
      height = h;
      borderWidth = 0;
      if (XtIsWidget(child))
	borderWidth = child->core.border_width;
      XtConfigureWidget(child, x, y, width, height, borderWidth);
      if (isManaged == False)
	{
	  XtUnmanageChild(child);
	  XtVaSetValues(child, XmNmappedWhenManaged, map, NULL);
	}
    }
}

static void 
LayoutLeftRight(XmLFolderWidget f, 
		int resizeIfNeeded)
{
  Display *dpy;
  Window root;
  int i, tabNum, x, y, w, h, pad1, pad2;
  int rowNum, numRows, rowWidth, rowX, rowY;
  WidgetList children;
  Widget tab, child;
  XmLFolderConstraintRec *fc;
  XtGeometryResult result;
  unsigned int inactPixHeight, pixHeight;
  unsigned int inactPixWidth, pixWidth;
  unsigned int pixBW, pixDepth;
  Dimension height, minHeight;
  Dimension width, minWidth, borderWidth;
  Dimension co;
  int st, ht;
  Boolean map, isManaged;
  struct
  {
    int width, height, numTabs, x;
  } rows[MAX_TAB_ROWS];

  dpy = XtDisplay(f);
  children = f->composite.children;
  st = f->manager.shadow_thickness;
  ht = f->folder.highlightThickness;

  /* calculate corner offset */
  if (f->folder.cornerStyle == XmCORNER_LINE)
    co = (Dimension)((double)f->folder.cornerDimension * .5 + .99);
  else if (f->folder.cornerStyle == XmCORNER_ARC)
    co = (Dimension)((double)f->folder.cornerDimension * .3 + .99);
  else
    co = 0;

  /* caculate tabWidth, minWidth, minHeight, row x positions, */
  /* row widths and tab pixmap dimensions */
  rowX = 0;
  rowY = 0;
  rowWidth = 0;
  rowNum = 0;
  tabNum = 0;
  minHeight = 0;
  for (i = 0; i < f->folder.tabCount; i++)
    {
      tab = f->folder.tabs[i];
      if (!XtIsManaged(tab))
	continue;
      fc = (XmLFolderConstraintRec *)(tab->core.constraints);

      /* check for start of a new row */
      fc->folder.firstInRow = False;
      if (!tabNum)
	fc->folder.firstInRow = True;
      if (f->folder.tabsPerRow && tabNum == f->folder.tabsPerRow)
	{
	  fc->folder.firstInRow = True;

	  /* store prev row values and start next row */
	  if (rowY)
	    rowY -= f->folder.spacing;
	  rows[rowNum].x = rowX;
	  rows[rowNum].height = rowY;
	  rows[rowNum].width = rowWidth;
	  rows[rowNum].numTabs = tabNum;
	  if (f->folder.debugLevel)
	    {
	      fprintf(stderr, "XmLFolder: Layout: ");
	      fprintf(stderr, "row %d: x %d w %d h %d numTabs %d\n",
		      rowNum, rowX, rowWidth, rowY, tabNum);
	    }
	  rowX += rowWidth;
	  rowWidth = 0;
	  if (rowY > (int)minHeight)
	    minHeight = rowY;
	  rowY = 0;
	  tabNum = 0;
	  rowNum++;
	  if (rowNum == MAX_TAB_ROWS - 1)
	    {
	      XmLWarning((Widget)f, "Layout ERROR - too many rows\n");
	      return;
	    }
	}

      /* make sure row width > maximum tab width */
      width = co + st + tab->core.width + tab->core.border_width * 2 +
	f->folder.marginHeight * 2 + ht * 2;
      if ((int)width > rowWidth)
	rowWidth = width;

      /* calc pixmap dimensions/maximum pixmap width */
      pixWidth = 0;
      pixHeight = 0;
      fc->folder.pixWidth = 0;
      fc->folder.pixHeight = 0;
      fc->folder.inactPixWidth = 0;
      fc->folder.inactPixHeight = 0;
      fc->folder.maxPixWidth = 0;
      fc->folder.maxPixHeight = 0;
      if (fc->folder.pix != XmUNSPECIFIED_PIXMAP)
	{
	  XGetGeometry(dpy, fc->folder.pix, &root,
		       &x, &y, &pixWidth, &pixHeight, &pixBW, &pixDepth);
	  fc->folder.pixWidth = pixWidth;
	  fc->folder.maxPixWidth = pixWidth;
	  fc->folder.pixHeight = pixHeight;
	  fc->folder.maxPixHeight = pixHeight;
	  width = co + st + pixWidth + f->folder.marginHeight * 2 + ht * 2;
	  if ((int)width > rowWidth)
	    rowWidth = width;
	}
      if (fc->folder.inactPix != XmUNSPECIFIED_PIXMAP)
	{
	  XGetGeometry(dpy, fc->folder.inactPix, &root, &x, &y,
		       &inactPixWidth, &inactPixHeight, &pixBW, &pixDepth);
	  fc->folder.inactPixWidth = inactPixWidth;
	  if (inactPixWidth > fc->folder.maxPixWidth)
	    fc->folder.maxPixWidth = inactPixWidth;
	  fc->folder.inactPixHeight = inactPixHeight;
	  if (inactPixHeight > fc->folder.maxPixHeight)
	    fc->folder.maxPixHeight = inactPixHeight;
	  width = co + st + inactPixWidth + 
	    f->folder.marginHeight * 2 + ht * 2;
	  if ((int)width > rowWidth)
	    rowWidth = width;
	}

      /* increment rowY to move on to the next tab */
      rowY += st * 2 + co * 2 + f->folder.marginWidth * 2 + ht * 2 +
	XtHeight(tab) + tab->core.border_width * 2;

      if (fc->folder.maxPixHeight)
	rowY += fc->folder.maxPixHeight + f->folder.pixmapMargin;
      rowY += f->folder.spacing;

      tabNum++;
      fc->folder.row = rowNum;
    }

  /* complete calcuations for last row */
  if (rowY)
    rowY -= f->folder.spacing;
  rows[rowNum].x = rowX;
  rows[rowNum].height = rowY;
  rows[rowNum].width = rowWidth;
  rows[rowNum].numTabs = tabNum;
  numRows = rowNum + 1;
  if (f->folder.debugLevel)
    {
      fprintf(stderr, "XmLFolder: Layout: ");
      fprintf(stderr, "row %d: x %d w %d h %d numTabs %d\n",
	      rowNum, rowX, rowWidth, rowY, tabNum);
    }
  f->folder.tabWidth = rowX + rowWidth;
  f->folder.tabBarHeight = f->folder.tabWidth;
  minWidth = f->folder.tabWidth;
  if ((int)minHeight < rowY)
    minHeight = rowY;

  /* add space for indent of upper rows */
  if (f->folder.tabsPerRow && minHeight)
    minHeight += 4;

  if (f->folder.debugLevel)
    {
      fprintf(stderr, "XmLFolder: Layout: ");
      fprintf(stderr, "tab bar minimum w %d h %d\n",
	      (int)minWidth, (int)minHeight);
    }

  /* calculate width and height of non-tab children ensure */
  /* minWidth > width and minHeight > height */
  for (i = 0; i < f->composite.num_children; i++)
    {
      child = children[i];
      if (XtIsSubclass(child, xmPrimitiveWidgetClass))
	continue;

      height = XtHeight(child) + st * 2;
      if (XtIsWidget(child))
	height += f->core.border_width * 2;
      if (height > minHeight)
	minHeight = height;

      width = XtWidth(child) + f->folder.tabWidth + st * 2;
      if (XtIsWidget(child))
	width += f->core.border_width * 2;
      if (width > minWidth)
	minWidth = width;
    }

  if (f->folder.debugLevel)
    {
      fprintf(stderr, "XmLFolder: Layout: ");
      fprintf(stderr, "with non-tabs minimum w %d h %d\n",
	      (int)minWidth, (int)minHeight);
    }

  /* Resize folder if needed */
  if (resizeIfNeeded && f->folder.resizePolicy != XmRESIZE_NONE)
    {
      if (minWidth <= 0)
	minWidth = 1;
      if (minHeight <= 0)
	minHeight = 1;
      result = XtMakeResizeRequest((Widget)f, minWidth, minHeight,
				   &width, &height);
      if (result == XtGeometryAlmost)
	XtMakeResizeRequest((Widget)f, width, height, NULL, NULL);
    }
  /* move active row to bottom */
  tab = f->folder.activeW;
  if (tab)
    {
      fc = (XmLFolderConstraintRec *)(tab->core.constraints);
      rowNum = fc->folder.row;
      f->folder.activeRow = rowNum;
      rows[rowNum].x = f->folder.tabWidth - rows[rowNum].width;
      for (i = rowNum + 1; i < numRows; i++)
	rows[i].x -= rows[rowNum].width;
    }
  else
    f->folder.activeRow = -1;

  /* configure tab children */
  for (i = 0; i < f->folder.tabCount; i++)
    {
      tab = f->folder.tabs[i];
      if (!XtIsManaged(tab))
	continue;
      fc = (XmLFolderConstraintRec *)(tab->core.constraints);
      rowNum = fc->folder.row;

      /* calculate tab x */
      if (fc->folder.firstInRow == True)
	{
	  if (f->folder.tabsPerRow && rowNum != f->folder.activeRow)
	    y = 2;
	  else
	    y = 0;
	}
      fc->folder.y = y;
      y += st + co + f->folder.marginWidth + ht;
      if (fc->folder.maxPixHeight)
	y += fc->folder.maxPixHeight + f->folder.pixmapMargin;

      /* calculate tab x and tab width */
      fc->folder.width = rows[rowNum].width;
      if (f->folder.tabPlacement == XmFOLDER_LEFT)
	{
	  fc->folder.x = rows[rowNum].x;
	  x = fc->folder.x + fc->folder.width - f->folder.marginHeight -
	    ht - XtWidth(tab) - tab->core.border_width * 2;
	}
      else
	{
	  fc->folder.x = f->core.width - rows[rowNum].x -
	    rows[rowNum].width;
	  x = fc->folder.x + f->folder.marginHeight + ht;
	}

      /* calculate tab padding */
      pad1 = 0;
      pad2 = 0;
      h = f->core.height - rows[rowNum].height;
      if (rowNum != f->folder.activeRow)
	h -= 4;
      if (f->folder.tabsPerRow && h > 0)
	{
	  pad1 = h / (rows[rowNum].numTabs * 2);
	  pad2 = pad1;
	  if (fc->folder.firstInRow == True)
	    pad2 += h - (pad1 * rows[rowNum].numTabs * 2);
	}
      y += pad1;

      /* move tab widget into place */
      XtMoveWidget(tab, x, y);

      /* calculate tab height and move to next tab */
      y += pad2 + XtHeight(tab) + tab->core.border_width * 2 + ht +
	f->folder.marginWidth + co + st;
      fc->folder.height = y - fc->folder.y; 
      y += f->folder.spacing;
    }

  /* configure non-tab children */
  for (i = 0; i < f->composite.num_children; i++)
    {
      child = children[i];
      if (XtIsSubclass(child, xmPrimitiveWidgetClass))
	continue;
      if (f->folder.resizePolicy == XmRESIZE_NONE)
	continue;

      w = (int)f->core.width - (int)f->folder.tabWidth - st * 2;
      h = (int)f->core.height - st * 2;
      if (h <= 0 || w <= 0)
	continue;
      /* manager widgets will not configure correctly unless they */
      /* are managed, so manage then unmapped if they are unmanaged */
      isManaged = True;
      if (!XtIsManaged(child))
	{
	  XtVaGetValues(child,
			XmNmappedWhenManaged, &map,
			NULL);
	  XtVaSetValues(child,
			XmNmappedWhenManaged, False,
			NULL);
	  XtManageChild(child);
	  isManaged = False;
	}
      y = st;
      if (f->folder.tabPlacement == XmFOLDER_LEFT)
	x = f->folder.tabWidth + st;
      else
	x = st;
      width = w;
      height = h;
      borderWidth = 0;
      if (XtIsWidget(child))
	borderWidth = child->core.border_width;
      XtConfigureWidget(child, x, y, width, height, borderWidth);
      if (isManaged == False)
	{
	  XtUnmanageChild(child);
	  XtVaSetValues(child, XmNmappedWhenManaged, map, NULL);
	}
    }
}

static void 
Resize(Widget w)
{
  XmLFolderWidget f;

  f = (XmLFolderWidget)w;
  Layout(f, 0);
}

static XtGeometryResult 
GeometryManager(Widget w, 
		XtWidgetGeometry *request, 
		XtWidgetGeometry *allow)
{
  XmLFolderWidget f;

  f = (XmLFolderWidget)XtParent(w);
  if (f->folder.resizePolicy != XmRESIZE_STATIC ||
      XtIsSubclass(w, xmPrimitiveWidgetClass))
    {
      if (request->request_mode & CWWidth)
	w->core.width = request->width;
      if (request->request_mode & CWHeight)
	w->core.height = request->height;
      if (request->request_mode & CWX)
	w->core.x = request->x;
      if (request->request_mode & CWY)
	w->core.y = request->y;
      if (request->request_mode & CWBorderWidth)
	w->core.border_width = request->border_width;
      Layout(f, 1);
      return XtGeometryYes;
    }
  return XtGeometryNo;
}

static void 
ChangeManaged(Widget w)
{
  XmLFolderWidget f;

  f = (XmLFolderWidget)w;
  Layout(f, 1);
  _XmNavigChangeManaged(w);
}

static void 
ConstraintInitialize(Widget req, 
		     Widget w, 
		     ArgList args, 
		     Cardinal *narg)
{
  XmLFolderWidget f;
  XmLFolderConstraintRec *fc;

  if (!XtIsRectObj(w))
    return;
  f = (XmLFolderWidget)XtParent(w);
  if (f->folder.debugLevel)
    fprintf(stderr, "XmLFolder: Constraint Init\n");
  fc = (XmLFolderConstraintRec *)(w->core.constraints);
  fc->folder.x = 0;
  fc->folder.y = 0;
  fc->folder.width = 0;
  fc->folder.height = 0;
  fc->folder.maxPixWidth = 0;
  fc->folder.maxPixHeight = 0;
  fc->folder.row = -1;
  fc->folder.firstInRow = False;
  if (fc->folder.managedName)
    fc->folder.managedName = (char *)strdup(fc->folder.managedName);
  if (XtIsSubclass(w, xmPrimitiveWidgetClass))
    {
      XtOverrideTranslations(w, f->folder.primTrans);
      XtAddCallback(w, XmNactivateCallback, PrimActivate, 0);
      XtVaSetValues(w,
		    XmNhighlightThickness, 0,
		    XmNshadowThickness, 0,
		    NULL);
      if (XtIsSubclass(w, xmLabelWidgetClass))
	XtVaSetValues(w, XmNfillOnArm, False, NULL);

      /* add child to tabs list */
      if (f->folder.tabAllocCount < f->folder.tabCount + 1)
	{
	  f->folder.tabAllocCount *= 2;
	  f->folder.tabs = (Widget *)realloc((char *)f->folder.tabs,
					     sizeof(Widget) * f->folder.tabAllocCount);
	}
      f->folder.tabs[f->folder.tabCount++] = w;

    }
  if (XmIsDrawnButton(w))
    SetTabPlacement(f, w);

#ifdef XmLEVAL
  if (f->folder.tabCount > 6)
    {
      fprintf(stderr, "XmL: evaluation version only supports <= 6 tabs\n");
      exit(0);
    }
#endif
}

static void 
ConstraintDestroy(Widget w)
{
  XmLFolderWidget f;
  XmLFolderConstraintRec *fc;
  int i, j, activePos;
	
  if (!XtIsRectObj(w))
    return;
  f = (XmLFolderWidget)XtParent(w);
  if (f->folder.debugLevel)
    fprintf(stderr, "XmLFolder: Constraint Destroy\n");
  if (f->folder.focusW == w)
    f->folder.focusW = 0;
  fc = (XmLFolderConstraintRec *)(w->core.constraints);
  if (fc->folder.managedName)
    free((char *)fc->folder.managedName);
  if (fc->folder.freePix == True)
    {
      if (fc->folder.pix != XmUNSPECIFIED_PIXMAP)
	XFreePixmap(XtDisplay(w), fc->folder.pix);
      if (fc->folder.inactPix != XmUNSPECIFIED_PIXMAP)
	XFreePixmap(XtDisplay(w), fc->folder.inactPix);
    }
  if (XtIsSubclass(w, xmPrimitiveWidgetClass))
    {
      XtRemoveCallback(w, XmNactivateCallback, PrimActivate, 0);

      /* remove child from tabs list and calculate active pos */
      activePos = -1;
      j = 0;
      for (i = 0; i < f->folder.tabCount; i++)
	if (f->folder.tabs[i] != w)
	  {
	    if (f->folder.activeW == f->folder.tabs[i])
	      activePos = j;
	    f->folder.tabs[j++] = f->folder.tabs[i];
	  }
      if (j != f->folder.tabCount - 1)
	XmLWarning((Widget)f, "ConstraintDestroy() - bad child list");
      f->folder.tabCount = j;
      f->folder.activeTab = activePos;
      if (activePos == -1)
	f->folder.activeW = 0;
    }
}

static void 
DrawTabPixmap(XmLFolderWidget f, 
	      Widget tab, 
	      int active)
{
  Display *dpy;
  Window win;
  int x, y;
  Pixmap pixmap;
  Dimension pixWidth, pixHeight, ht; 
  XmLFolderConstraintRec *fc;

  x = 0;
  y = 0;
  dpy = XtDisplay(f);
  win = XtWindow(f);
  fc = (XmLFolderConstraintRec *)(tab->core.constraints);
  ht = f->folder.highlightThickness;
  if (active)
    {
      pixWidth = fc->folder.pixWidth;
      pixHeight = fc->folder.pixHeight;
      pixmap = fc->folder.pix;
    }
  else
    {
      pixWidth = fc->folder.inactPixWidth;
      pixHeight = fc->folder.inactPixHeight;
      pixmap = fc->folder.inactPix;
    }
  if (f->folder.tabPlacement == XmFOLDER_TOP)
    {
      x = tab->core.x - pixWidth - ht - f->folder.pixmapMargin;
      y = tab->core.y + tab->core.height - pixHeight; 
    }
  else if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    {
      x = tab->core.x - fc->folder.pixWidth - ht - f->folder.pixmapMargin;
      y = tab->core.y;
    }
  else if (f->folder.tabPlacement == XmFOLDER_LEFT)
    {
      x = tab->core.x + tab->core.width - pixWidth;
      y = tab->core.y - pixHeight - f->folder.pixmapMargin - ht;
    }
  else if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    {
      x = tab->core.x;
      y = tab->core.y - pixHeight - f->folder.pixmapMargin - ht;
    }
  XCopyArea(dpy, pixmap, win, f->folder.gc, 0, 0, pixWidth, pixHeight, x, y);
}

static void 
DrawManagerShadowTopBottom(XmLFolderWidget f, 
			   XRectangle *rect)
{
  Display *dpy;
  Window win;
  XmLFolderConstraintRec *fc;
  XSegment *topSeg, *botSeg;
  int i, bCount, tCount, st, botOff, isManaged;

  dpy = XtDisplay(f);
  win = XtWindow(f);
  st = f->manager.shadow_thickness;
  if (!st)
    return;
  botOff = f->core.height - f->folder.tabHeight - 1;

  topSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2);
  botSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2);

  /* top shadow */
  fc = 0;
  if (f->folder.activeW)
    fc = (XmLFolderConstraintRec *)(f->folder.activeW->core.constraints);
  tCount = 0;
  if (fc)
    for (i = 0; i < st; i++)
      {
	topSeg[tCount].x1 = rect->x + i;
	topSeg[tCount].y1 = rect->y + i;
	topSeg[tCount].x2 = fc->folder.x + i;
	topSeg[tCount].y2 = rect->y + i;
	if (rect->x != fc->folder.x)
	  tCount++;
	topSeg[tCount].x1 = rect->x + fc->folder.x +
	  fc->folder.width - i - 1;
	topSeg[tCount].y1 = rect->y + i;
	topSeg[tCount].x2 = rect->x + rect->width - i - 1;
	topSeg[tCount].y2 = rect->y + i;
	if (fc->folder.x + fc->folder.width != rect->width)
	  tCount++;
      }
  else
    for (i = 0; i < st; i++)
      {
	topSeg[tCount].x1 = rect->x + i;
	topSeg[tCount].y1 = rect->y + i;
	topSeg[tCount].x2 = rect->x + rect->width - i - 1;
	topSeg[tCount].y2 = rect->y + i;
	tCount++;
      }
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    for (i = 0 ; i < tCount; i++)
      {
	topSeg[i].y1 = botOff - topSeg[i].y1;
	topSeg[i].y2 = botOff - topSeg[i].y2;
      }
  if (tCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	SetGC(f, GC_SHADOWBOT);
      else	
	SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }

  /* see if there's any composite widgets in the folder */
  isManaged = 0;
  for (i = 0; i < f->composite.num_children; i++) 
    {
      Widget child = f->composite.children[i];
      if (!XtIsSubclass(child, xmPrimitiveWidgetClass) && XtIsManaged(child))
        {
	  isManaged = 1;
	  break;
	}
      	
    }

  /* no need to draw shadow for the manager area if
     there isn't any composite widgets in the folder */
  if (!isManaged)
    {
      free((char *)topSeg);
      free((char *)botSeg);
      return;
    }
    
  /* left shadow */
  tCount = 0;
  for (i = 0; i < st; i++)
    {
      topSeg[tCount].x1 = rect->x + i;
      topSeg[tCount].y1 = rect->y + i;
      topSeg[tCount].x2 = rect->x + i;
      topSeg[tCount].y2 = rect->y + rect->height - i - 1;
      tCount++;
    }
  if (tCount)
    {
      SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }

  /* right shadow */
  bCount = 0;
  for (i = 0; i < st; i++)
    {
      botSeg[bCount].x1 = rect->x + rect->width - i - 1;
      botSeg[bCount].y1 = rect->y + i;
      botSeg[bCount].x2 = rect->x + rect->width - i - 1;
      botSeg[bCount].y2 = rect->y + rect->height - i - 1;
      bCount++;
    }
  if (bCount)
    {
      SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }

  /* bottom shadow */
  bCount = 0;
  for (i = 0; i < st; i++)
    {
      botSeg[bCount].x1 = rect->x + i;
      botSeg[bCount].y1 = rect->y + rect->height - i - 1;
      botSeg[bCount].x2 = rect->x + rect->width - i - 1;
      botSeg[bCount].y2 = rect->y + rect->height - i - 1;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  botSeg[bCount].y1 = botOff - botSeg[bCount].y1;
	  botSeg[bCount].y2 = botOff - botSeg[bCount].y2;
	}
      bCount++;
    }
  if (bCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_TOP)
	SetGC(f, GC_SHADOWBOT);
      else	
	SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }
  free((char *)topSeg);
  free((char *)botSeg);
}

static void 
DrawManagerShadowLeftRight(XmLFolderWidget f, 
			   XRectangle *rect)
{
  Display *dpy;
  Window win;
  XmLFolderConstraintRec *fc;
  XSegment *topSeg, *botSeg;
  int i, bCount, tCount, st, rightOff;

  dpy = XtDisplay(f);
  win = XtWindow(f);
  st = f->manager.shadow_thickness;
  if (!st)
    return;
  rightOff = f->core.width - f->folder.tabWidth - 1;

  topSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2);
  botSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2);

  /* left shadow */
  fc = 0;
  if (f->folder.activeW)
    fc = (XmLFolderConstraintRec *)(f->folder.activeW->core.constraints);
  tCount = 0;
  if (fc)
    for (i = 0; i < st; i++)
      {
	topSeg[tCount].x1 = rect->x + i;
	topSeg[tCount].y1 = rect->y + i;
	topSeg[tCount].x2 = rect->x + i;
	topSeg[tCount].y2 = fc->folder.y + i;
	if (rect->y != fc->folder.y)
	  tCount++;
	topSeg[tCount].x1 = rect->x + i;
	topSeg[tCount].y1 = rect->y + fc->folder.y +
	  fc->folder.height - i - 1;
	topSeg[tCount].x2 = rect->x + i;
	topSeg[tCount].y2 = rect->y + rect->height - i - 1;
	if (fc->folder.y + fc->folder.height != rect->height)
	  tCount++;
      }
  else
    for (i = 0; i < st; i++)
      {
	topSeg[tCount].x1 = rect->x + i;
	topSeg[tCount].y1 = rect->y + i;
	topSeg[tCount].x2 = rect->x + i;
	topSeg[tCount].y2 = rect->y + rect->height - i - 1;
	tCount++;
      }
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    for (i = 0 ; i < tCount; i++)
      {
	topSeg[i].x1 = rightOff - topSeg[i].x1;
	topSeg[i].x2 = rightOff - topSeg[i].x2;
      }
  if (tCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	SetGC(f, GC_SHADOWBOT);
      else	
	SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }

  /* top shadow */
  tCount = 0;
  for (i = 0; i < st; i++)
    {
      topSeg[tCount].x1 = rect->x + i;
      topSeg[tCount].y1 = rect->y + i;
      topSeg[tCount].x2 = rect->x + rect->width - i - 1;
      topSeg[tCount].y2 = rect->y + i;
      tCount++;
    }
  if (tCount)
    {
      SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }

  /* bottom shadow */
  bCount = 0;
  for (i = 0; i < st; i++)
    {
      botSeg[bCount].x1 = rect->x + i;
      botSeg[bCount].y1 = rect->y + rect->height - i - 1;
      botSeg[bCount].x2 = rect->x + rect->width - i - 1;
      botSeg[bCount].y2 = rect->y + rect->height - i - 1;
      bCount++;
    }
  if (bCount)
    {
      SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }

  /* right shadow */
  bCount = 0;
  for (i = 0; i < st; i++)
    {
      botSeg[bCount].x1 = rect->x + rect->width - i - 1;
      botSeg[bCount].y1 = rect->y + i;
      botSeg[bCount].x2 = rect->x + rect->width - i - 1;
      botSeg[bCount].y2 = rect->y + rect->height - i - 1;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  botSeg[bCount].x1 = rightOff - botSeg[bCount].x1;
	  botSeg[bCount].x2 = rightOff - botSeg[bCount].x2;
	}
      bCount++;
    }
  if (bCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_LEFT)
	SetGC(f, GC_SHADOWBOT);
      else	
	SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }
  free((char *)topSeg);
  free((char *)botSeg);
}

static void 
DrawTabShadowArcTopBottom(XmLFolderWidget f,
			  Widget w)
{
  XmLFolderConstraintRec *fc;
  Display *dpy;
  Window win;
  XSegment *topSeg, *botSeg;
  XRectangle rect, rect2;
  XArc arc;
  int tCount, bCount;
  int i, st, cd, botOff;

  dpy = XtDisplay(f);
  win = XtWindow(f);
  fc = (XmLFolderConstraintRec *)(w->core.constraints);
  botOff = 2 * fc->folder.y + fc->folder.height - 1;
  st = f->manager.shadow_thickness;
  if (!st)
    return;
  cd = f->folder.cornerDimension;

  tCount = 0;
  bCount = 0;
  topSeg = (XSegment *)malloc(sizeof(XSegment) * st);
  botSeg = (XSegment *)malloc(sizeof(XSegment) * st);
  for (i = 0; i < st; i++)
    {
      /* left tab shadow */
      topSeg[tCount].x1 = fc->folder.x + i;
      topSeg[tCount].y1 = fc->folder.y + cd + st;
      topSeg[tCount].x2 = fc->folder.x + i;
      topSeg[tCount].y2 = fc->folder.y + fc->folder.height - 1;
      if (w == f->folder.activeW)
	topSeg[tCount].y2 += i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  topSeg[tCount].y1 = botOff - topSeg[tCount].y1;
	  topSeg[tCount].y2 = botOff - topSeg[tCount].y2;
	}
      tCount++;

      /* right tab shadow */
      botSeg[bCount].x1 = fc->folder.x + fc->folder.width - i - 1;
      botSeg[bCount].y1 = fc->folder.y + cd + st;
      botSeg[bCount].x2 = fc->folder.x + fc->folder.width - i - 1;
      botSeg[bCount].y2 = fc->folder.y + fc->folder.height - 1;
      if (w == f->folder.activeW)
	botSeg[bCount].y2 += i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  botSeg[bCount].y1 = botOff - botSeg[bCount].y1;
	  botSeg[bCount].y2 = botOff - botSeg[bCount].y2;
	}
      bCount++;
    }
  if (tCount)
    {
      SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  if (bCount)
    {
      SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }
  tCount = 0;
  for (i = 0; i < st; i++)
    {
      /* top tab shadow */
      topSeg[tCount].x1 = fc->folder.x + cd + st;
      topSeg[tCount].y1 = fc->folder.y + i;
      topSeg[tCount].x2 = fc->folder.x + fc->folder.width - cd - st - 1;
      topSeg[tCount].y2 = fc->folder.y + i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  topSeg[tCount].y1 = botOff - topSeg[tCount].y1;
	  topSeg[tCount].y2 = botOff - topSeg[tCount].y2;
	}
      tCount++;
    }
  if (tCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	SetGC(f, GC_SHADOWBOT);
      else
	SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  free((char *)topSeg);
  free((char *)botSeg);

  /* left corner blank background */
  rect.x = fc->folder.x;
  rect.y = fc->folder.y;
  rect.width = cd + st;
  rect.height = cd + st;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    rect.y = fc->folder.y + fc->folder.height - rect.height;
  SetGC(f, GC_BLANK);
  XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y,
		 rect.width, rect.height);
  SetGC(f, GC_UNSET);

  /* left arc */
  /* various X Servers have problems drawing arcs - so set clip rect */
  /* and draw two circles, one smaller than the other, for corner */
  XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect, 1, Unsorted);
  arc.x = rect.x;
  arc.y = rect.y;
  arc.width = rect.width * 2;
  arc.height = rect.height * 2;
  if (f->folder.serverDrawsArcsLarge == True)
    {
      arc.width -= 1;
      arc.height -= 1;
    }
  arc.angle1 = 0 * 64;
  arc.angle2 = 360 * 64;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    arc.y = fc->folder.y + fc->folder.height - arc.height;
  SetGC(f, GC_SHADOWTOP);
  XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  SetGC(f, GC_UNSET);

  rect2 = rect;
  rect2.x += st;
  rect2.width -= st;
  rect2.height -= st;
  if (f->folder.tabPlacement == XmFOLDER_TOP)
    rect2.y += st;
  XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect2, 1, Unsorted);
  if (w == f->folder.activeW)
    XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
  else
    XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
  arc.x += st;
  arc.y += st;
  arc.width -= st * 2;
  arc.height -= st * 2;
  XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XSetClipMask(dpy, f->folder.gc, None);

  /* right corner blank background */
  rect.x = fc->folder.x + fc->folder.width - cd - st;
  SetGC(f, GC_BLANK);
  XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y,
		 rect.width, rect.height);
  SetGC(f, GC_UNSET);

  /* right arc */
  XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect, 1, Unsorted);
  arc.x = rect.x - cd - st;
  arc.y = rect.y;
  arc.width = rect.width * 2;
  arc.height = rect.height * 2;
  if (f->folder.serverDrawsArcsLarge == True)
    {
      arc.width -= 1;
      arc.height -= 1;
    }
  arc.angle1 = 0 * 64;
  arc.angle2 = 360 * 64;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    arc.y = fc->folder.y + fc->folder.height - arc.height;
  SetGC(f, GC_SHADOWBOT);
  XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  SetGC(f, GC_UNSET);

  rect2 = rect;
  rect2.width -= st;
  rect2.height -= st;
  if (f->folder.tabPlacement == XmFOLDER_TOP)
    rect2.y += st;
  XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect2, 1, Unsorted);
  if (w == f->folder.activeW)
    XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
  else
    XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
  arc.x += st;
  arc.y += st;
  arc.width -= st * 2;
  arc.height -= st * 2;
  XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XSetClipMask(dpy, f->folder.gc, None);
}

static void 
DrawTabShadowArcLeftRight(XmLFolderWidget f,
			  Widget w)
{
  XmLFolderConstraintRec *fc;
  Display *dpy;
  Window win;
  XSegment *topSeg, *botSeg;
  XRectangle rect, rect2;
  XArc arc;
  int tCount, bCount;
  int i, st, cd, rightOff;

  dpy = XtDisplay(f);
  win = XtWindow(f);
  fc = (XmLFolderConstraintRec *)(w->core.constraints);
  rightOff = 2 * fc->folder.x + fc->folder.width - 1;
  st = f->manager.shadow_thickness;
  if (!st)
    return;
  cd = f->folder.cornerDimension;

  tCount = 0;
  bCount = 0;
  topSeg = (XSegment *)malloc(sizeof(XSegment) * st);
  botSeg = (XSegment *)malloc(sizeof(XSegment) * st);
  for (i = 0; i < st; i++)
    {
      /* top tab shadow */
      topSeg[tCount].x1 = fc->folder.x + cd + st;
      topSeg[tCount].y1 = fc->folder.y + i;
      topSeg[tCount].x2 = fc->folder.x + fc->folder.width - 1;
      if (w == f->folder.activeW)
	topSeg[tCount].x2 += i;
      topSeg[tCount].y2 = fc->folder.y + i;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  topSeg[tCount].x1 = rightOff - topSeg[tCount].x1;
	  topSeg[tCount].x2 = rightOff - topSeg[tCount].x2;
	}
      tCount++;

      /* bottom tab shadow */
      botSeg[bCount].x1 = fc->folder.x + cd + st;
      botSeg[bCount].y1 = fc->folder.y + fc->folder.height - i - 1;
      botSeg[bCount].x2 = fc->folder.x + fc->folder.width - 1;
      if (w == f->folder.activeW)
	botSeg[bCount].x2 += i;
      botSeg[bCount].y2 = fc->folder.y + fc->folder.height - i - 1;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  botSeg[bCount].x1 = rightOff - botSeg[bCount].x1;
	  botSeg[bCount].x2 = rightOff - botSeg[bCount].x2;
	}
      bCount++;
    }
  if (tCount)
    {
      SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  if (bCount)
    {
      SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }
  tCount = 0;
  for (i = 0; i < st; i++)
    {
      /* left tab shadow */
      topSeg[tCount].x1 = fc->folder.x + i;
      topSeg[tCount].y1 = fc->folder.y + cd + st;
      topSeg[tCount].x2 = fc->folder.x + i;
      topSeg[tCount].y2 = fc->folder.y + fc->folder.height - cd - st - 1;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  topSeg[tCount].x1 = rightOff - topSeg[tCount].x1;
	  topSeg[tCount].x2 = rightOff - topSeg[tCount].x2;
	}
      tCount++;
    }
  if (tCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	SetGC(f, GC_SHADOWBOT);
      else
	SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  free((char *)topSeg);
  free((char *)botSeg);

  /* top corner blank background */
  rect.x = fc->folder.x;
  rect.y = fc->folder.y;
  rect.width = cd + st;
  rect.height = cd + st;
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    rect.x = fc->folder.x + fc->folder.width - rect.width;
  SetGC(f, GC_BLANK);
  XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y,
		 rect.width, rect.height);
  SetGC(f, GC_UNSET);

  /* top arc */
  XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect, 1, Unsorted);
  arc.x = rect.x;
  arc.y = rect.y;
  arc.width = rect.width * 2;
  arc.height = rect.height * 2;
  if (f->folder.serverDrawsArcsLarge == True)
    {
      arc.width -= 1;
      arc.height -= 1;
    }
  arc.angle1 = 0 * 64;
  arc.angle2 = 360 * 64;
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    arc.x = fc->folder.x + fc->folder.width - arc.width;
  SetGC(f, GC_SHADOWTOP);
  XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  SetGC(f, GC_UNSET);

  rect2 = rect;
  rect2.width -= st;
  rect2.height -= st;
  rect2.y += st;
  if (f->folder.tabPlacement == XmFOLDER_LEFT)
    rect2.x += st;
  XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect2, 1, Unsorted);
  if (w == f->folder.activeW)
    XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
  else
    XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
  arc.x += st;
  arc.y += st;
  arc.width -= st * 2;
  arc.height -= st * 2;
  XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XSetClipMask(dpy, f->folder.gc, None);

  /* bottom corner blank background */
  rect.y = fc->folder.y + fc->folder.height - cd - st;
  SetGC(f, GC_BLANK);
  XFillRectangle(dpy, win, f->folder.gc, rect.x, rect.y,
		 rect.width, rect.height);
  SetGC(f, GC_UNSET);

  /* bottom arc */
  XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect, 1, Unsorted);
  arc.x = rect.x;
  arc.y = rect.y - cd - st;
  arc.width = rect.width * 2;
  arc.height = rect.height * 2;
  if (f->folder.serverDrawsArcsLarge == True)
    {
      arc.width -= 1;
      arc.height -= 1;
    }
  arc.angle1 = 0 * 64;
  arc.angle2 = 360 * 64;
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    arc.x = fc->folder.x + fc->folder.width - arc.width;
  SetGC(f, GC_SHADOWBOT);
  XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  SetGC(f, GC_UNSET);

  rect2 = rect;
  rect2.width -= st;
  rect2.height -= st;
  if (f->folder.tabPlacement == XmFOLDER_LEFT)
    rect2.x += st;
  XSetClipRectangles(dpy, f->folder.gc, 0, 0, &rect2, 1, Unsorted);
  if (w == f->folder.activeW)
    XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
  else
    XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
  arc.x += st;
  arc.y += st;
  arc.width -= st * 2;
  arc.height -= st * 2;
  XFillArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XDrawArc(dpy, win, f->folder.gc, arc.x, arc.y, arc.width, arc.height,
	   arc.angle1, arc.angle2);
  XSetClipMask(dpy, f->folder.gc, None);
}

static void 
DrawTabShadowLineTopBottom(XmLFolderWidget f,
			   Widget w)
{
  XmLFolderConstraintRec *fc;
  Display *dpy;
  Window win;
  XSegment *topSeg, *botSeg;
  XPoint points[4];
  int tCount, bCount, botOff, i, st, cd, y;

  dpy = XtDisplay(f);
  win = XtWindow(f);
  fc = (XmLFolderConstraintRec *)(w->core.constraints);
  botOff = 2 * fc->folder.y + fc->folder.height - 1;
  st = f->manager.shadow_thickness;
  if (!st)
    return;
  cd = f->folder.cornerDimension;

  tCount = 0;
  bCount = 0;
  topSeg = (XSegment *)malloc(sizeof(XSegment) * st);
  botSeg = (XSegment *)malloc(sizeof(XSegment) * st);
  for (i = 0; i < st; i++)
    {
      /* left tab shadow */
      topSeg[tCount].x1 = fc->folder.x + i;
      topSeg[tCount].y1 = fc->folder.y + cd + st;
      topSeg[tCount].x2 = fc->folder.x + i;
      topSeg[tCount].y2 = fc->folder.y + fc->folder.height - 1;
      if (w == f->folder.activeW)
	topSeg[tCount].y2 += i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  topSeg[tCount].y1 = botOff - topSeg[tCount].y1;
	  topSeg[tCount].y2 = botOff - topSeg[tCount].y2;
	}
      tCount++;
      /* right tab shadow */
      botSeg[bCount].x1 = fc->folder.x + fc->folder.width - i - 1;
      botSeg[bCount].y1 = fc->folder.y + cd + st;
      botSeg[bCount].x2 = fc->folder.x + fc->folder.width - i - 1;
      botSeg[bCount].y2 = fc->folder.y + fc->folder.height - 1;
      if (w == f->folder.activeW)
	botSeg[bCount].y2 += i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  botSeg[bCount].y1 = botOff - botSeg[bCount].y1;
	  botSeg[bCount].y2 = botOff - botSeg[bCount].y2;
	}
      bCount++;
    }
  if (tCount)
    {
      SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  if (bCount)
    {
      SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }
  tCount = 0;
  for (i = 0; i < st; i++)
    {
      /* top tab shadow */
      topSeg[tCount].x1 = fc->folder.x + cd + st;
      topSeg[tCount].y1 = fc->folder.y + i;
      topSeg[tCount].x2 = fc->folder.x + fc->folder.width - cd - st - 1;
      topSeg[tCount].y2 = fc->folder.y + i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  topSeg[tCount].y1 = botOff - topSeg[tCount].y1;
	  topSeg[tCount].y2 = botOff - topSeg[tCount].y2;
	}
      tCount++;
    }
  if (tCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_TOP)
	SetGC(f, GC_SHADOWTOP);
      else
	SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  free((char *)topSeg);
  free((char *)botSeg);

  /* left top line */
  points[0].x = fc->folder.x;
  points[0].y = fc->folder.y + cd + st - 1;
  points[1].x = fc->folder.x + cd + st - 1;
  points[1].y = fc->folder.y;
  points[2].x = fc->folder.x + cd + st - 1;
  points[2].y = fc->folder.y + cd + st - 1;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    {
      points[0].y = botOff - points[0].y;
      points[1].y = botOff - points[1].y;
      points[2].y = botOff - points[2].y;
    }
  y = fc->folder.y;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    y = fc->folder.y + fc->folder.height - cd - st;
  SetGC(f, GC_BLANK);
  XFillRectangle(dpy, win, f->folder.gc, fc->folder.x, y, cd + st, cd + st);
  SetGC(f, GC_UNSET);
  SetGC(f, GC_SHADOWTOP);
  XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex,
	       CoordModeOrigin);
  points[3].x = points[0].x;
  points[3].y = points[0].y;
  XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin);
  SetGC(f, GC_UNSET);
  if (w == f->folder.activeW)
    XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
  else
    XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
  points[0].x += st;
  points[1].y += st;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    points[1].y -= st * 2;
  XFillPolygon(dpy, win, f->folder.gc, points, 3,
	       Nonconvex, CoordModeOrigin);
  points[3].x = points[0].x;
  points[3].y = points[0].y;
  XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin);

  /* right top line */
  points[0].x = fc->folder.x + fc->folder.width - 1;
  points[0].y = fc->folder.y + cd + st - 1;
  points[1].x = fc->folder.x + fc->folder.width - cd - st;
  points[1].y = fc->folder.y;
  points[2].x = fc->folder.x + fc->folder.width - cd - st;
  points[2].y = fc->folder.y + cd + st - 1;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    {
      points[0].y = botOff - points[0].y;
      points[1].y = botOff - points[1].y;
      points[2].y = botOff - points[2].y;
    }
  y = fc->folder.y;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    y = fc->folder.y + fc->folder.height - cd - st;
  SetGC(f, GC_BLANK);
  XFillRectangle(dpy, win, f->folder.gc, fc->folder.x + fc->folder.width -
		 cd - st, y, cd + st, cd + st);
  SetGC(f, GC_UNSET);
  if (f->folder.tabPlacement == XmFOLDER_TOP)
    SetGC(f, GC_SHADOWTOP);
  else
    SetGC(f, GC_SHADOWBOT);
  XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex,
	       CoordModeOrigin);
  points[3].x = points[0].x;
  points[3].y = points[0].y;
  XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin);
  SetGC(f, GC_UNSET);
  if (w == f->folder.activeW)
    XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
  else
    XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
  points[0].x -= st;
  points[1].y += st;
  if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
    points[1].y -= st * 2;
  XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex,
	       CoordModeOrigin);
  points[3].x = points[0].x;
  points[3].y = points[0].y;
  XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin);
}

static void 
DrawTabShadowLineLeftRight(XmLFolderWidget f,
			   Widget w)
{
  XmLFolderConstraintRec *fc;
  Display *dpy;
  Window win;
  XSegment *topSeg, *botSeg;
  XPoint points[4];
  int tCount, bCount, rightOff, i, st, cd, x;

  dpy = XtDisplay(f);
  win = XtWindow(f);
  fc = (XmLFolderConstraintRec *)(w->core.constraints);
  rightOff = 2 * fc->folder.x + fc->folder.width - 1;
  st = f->manager.shadow_thickness;
  if (!st)
    return;
  cd = f->folder.cornerDimension;

  tCount = 0;
  bCount = 0;
  topSeg = (XSegment *)malloc(sizeof(XSegment) * st);
  botSeg = (XSegment *)malloc(sizeof(XSegment) * st);
  for (i = 0; i < st; i++)
    {
      /* top tab shadow */
      topSeg[tCount].x1 = fc->folder.x + cd + st;
      topSeg[tCount].y1 = fc->folder.y + i;
      topSeg[tCount].x2 = fc->folder.x + fc->folder.width - 1;
      if (w == f->folder.activeW)
	topSeg[tCount].x2 += i;
      topSeg[tCount].y2 = fc->folder.y + i;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  topSeg[tCount].x1 = rightOff - topSeg[tCount].x1;
	  topSeg[tCount].x2 = rightOff - topSeg[tCount].x2;
	}
      tCount++;
      /* bottom tab shadow */
      botSeg[bCount].x1 = fc->folder.x + cd + st;
      botSeg[bCount].y1 = fc->folder.y + fc->folder.height - i - 1;
      botSeg[bCount].x2 = fc->folder.x + fc->folder.width - 1;
      if (w == f->folder.activeW)
	botSeg[bCount].x2 += i;
      botSeg[bCount].y2 = fc->folder.y + fc->folder.height - i - 1;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  botSeg[bCount].x1 = rightOff - botSeg[bCount].x1;
	  botSeg[bCount].x2 = rightOff - botSeg[bCount].x2;
	}
      bCount++;
    }
  if (tCount)
    {
      SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  if (bCount)
    {
      SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }
  tCount = 0;
  for (i = 0; i < st; i++)
    {
      /* left tab shadow */
      topSeg[tCount].x1 = fc->folder.x + i;
      topSeg[tCount].y1 = fc->folder.y + cd + st;
      topSeg[tCount].x2 = fc->folder.x + i;
      topSeg[tCount].y2 = fc->folder.y + fc->folder.height - cd - st - 1;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  topSeg[tCount].x1 = rightOff - topSeg[tCount].x1;
	  topSeg[tCount].x2 = rightOff - topSeg[tCount].x2;
	}
      tCount++;
    }
  if (tCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_LEFT)
	SetGC(f, GC_SHADOWTOP);
      else
	SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  free((char *)topSeg);
  free((char *)botSeg);

  /* top line */
  points[0].x = fc->folder.x + cd + st - 1;
  points[0].y = fc->folder.y;
  points[1].x = fc->folder.x;
  points[1].y = fc->folder.y + cd + st - 1;
  points[2].x = fc->folder.x + cd + st - 1;
  points[2].y = fc->folder.y + cd + st - 1;
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    {
      points[0].x = rightOff - points[0].x;
      points[1].x = rightOff - points[1].x;
      points[2].x = rightOff - points[2].x;
    }
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    x = fc->folder.x + fc->folder.width - cd - st;
  else
    x = fc->folder.x;
  SetGC(f, GC_BLANK);
  XFillRectangle(dpy, win, f->folder.gc, x, fc->folder.y, cd + st, cd + st);
  SetGC(f, GC_UNSET);
  SetGC(f, GC_SHADOWTOP);
  XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex,
	       CoordModeOrigin);
  points[3].x = points[0].x;
  points[3].y = points[0].y;
  XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin);
  SetGC(f, GC_UNSET);
  if (w == f->folder.activeW)
    XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
  else
    XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
  points[0].y += st;
  points[1].x += st;
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    points[1].x -= st * 2;
  XFillPolygon(dpy, win, f->folder.gc, points, 3,
	       Nonconvex, CoordModeOrigin);
  points[3].x = points[0].x;
  points[3].y = points[0].y;
  XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin);

  /* bottom line */
  points[0].x = fc->folder.x + cd + st - 1;
  points[0].y = fc->folder.y + fc->folder.height - 1;
  points[1].x = fc->folder.x;
  points[1].y = fc->folder.y + fc->folder.height - cd - st;
  points[2].x = fc->folder.x + cd + st - 1;
  points[2].y = fc->folder.y + fc->folder.height - cd - st;
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    {
      points[0].x = rightOff - points[0].x;
      points[1].x = rightOff - points[1].x;
      points[2].x = rightOff - points[2].x;
    }
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    x = fc->folder.x + fc->folder.width - cd - st;
  else
    x = fc->folder.x;
  SetGC(f, GC_BLANK);
  XFillRectangle(dpy, win, f->folder.gc, x, fc->folder.y +
		 fc->folder.height - cd - st, cd + st, cd + st);
  SetGC(f, GC_UNSET);
  SetGC(f, GC_SHADOWBOT);
  XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex,
	       CoordModeOrigin);
  points[3].x = points[0].x;
  points[3].y = points[0].y;
  XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin);
  SetGC(f, GC_UNSET);
  if (w == f->folder.activeW)
    XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
  else
    XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
  points[0].y -= st;
  points[1].x += st;
  if (f->folder.tabPlacement == XmFOLDER_RIGHT)
    points[1].x -= st * 2;
  XFillPolygon(dpy, win, f->folder.gc, points, 3, Nonconvex,
	       CoordModeOrigin);
  points[3].x = points[0].x;
  points[3].y = points[0].y;
  XDrawLines(dpy, win, f->folder.gc, points, 4, CoordModeOrigin);
}

static void 
DrawTabShadowNoneTopBottom(XmLFolderWidget f,
			   Widget w)
{
  XmLFolderConstraintRec *fc;
  Display *dpy;
  Window win;
  XSegment *topSeg, *botSeg;
  int i, st, botOff, tCount, bCount;

  dpy = XtDisplay(f);
  win = XtWindow(f);
  fc = (XmLFolderConstraintRec *)(w->core.constraints);
  botOff = 2 * fc->folder.y + fc->folder.height - 1;
  st = f->manager.shadow_thickness;
  if (!st)
    return;

  tCount = 0;
  bCount = 0;
  topSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2);
  botSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2);
  for (i = 0; i < st; i++)
    {
      /* left tab shadow */
      topSeg[tCount].x1 = fc->folder.x + i;
      topSeg[tCount].y1 = fc->folder.y + i;
      topSeg[tCount].x2 = fc->folder.x + i;
      topSeg[tCount].y2 = fc->folder.y + fc->folder.height - 1;
      if (w == f->folder.activeW)
	topSeg[tCount].y2 += i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  topSeg[tCount].y1 = botOff - topSeg[tCount].y1;
	  topSeg[tCount].y2 = botOff - topSeg[tCount].y2;
	}
      tCount++;

      /* right tab shadow */
      botSeg[bCount].x1 = fc->folder.x + fc->folder.width - 1 - i;
      botSeg[bCount].y1 = fc->folder.y + i;
      botSeg[bCount].x2 = fc->folder.x + fc->folder.width - 1 - i;
      botSeg[bCount].y2 = fc->folder.y + fc->folder.height - 1;
      if (w == f->folder.activeW)
	botSeg[bCount].y2 += i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  botSeg[bCount].y1 = botOff - botSeg[bCount].y1;
	  botSeg[bCount].y2 = botOff - botSeg[bCount].y2;
	}
      bCount++;
    }
  if (tCount)
    {
      SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  if (bCount)
    {
      SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }

  tCount = 0;
  for (i = 0; i < st; i++)
    {
      /* top tab shadow */
      topSeg[tCount].x1 = fc->folder.x + i + 1;
      topSeg[tCount].y1 = fc->folder.y + i;
      topSeg[tCount].x2 = fc->folder.x + fc->folder.width - i - 1;
      topSeg[tCount].y2 = fc->folder.y + i;
      if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  topSeg[tCount].y1 = botOff - topSeg[tCount].y1;
	  topSeg[tCount].y2 = botOff - topSeg[tCount].y2;
	}
      tCount++;
    }
  if (tCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_TOP)
	SetGC(f, GC_SHADOWTOP);
      else
	SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  free((char *)topSeg);
  free((char *)botSeg);
}

static void 
DrawTabShadowNoneLeftRight(XmLFolderWidget f,
			   Widget w)
{
  XmLFolderConstraintRec *fc;
  Display *dpy;
  Window win;
  XSegment *topSeg, *botSeg;
  int i, st, rightOff, tCount, bCount;

  dpy = XtDisplay(f);
  win = XtWindow(f);
  fc = (XmLFolderConstraintRec *)(w->core.constraints);
  rightOff = 2 * fc->folder.x + fc->folder.width - 1;
  st = f->manager.shadow_thickness;
  if (!st)
    return;

  tCount = 0;
  bCount = 0;
  topSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2);
  botSeg = (XSegment *)malloc(sizeof(XSegment) * st * 2);
  for (i = 0; i < st; i++)
    {
      /* bottom tab shadow */
      topSeg[tCount].x1 = fc->folder.x + i;
      topSeg[tCount].y1 = fc->folder.y + i;
      topSeg[tCount].x2 = fc->folder.x + fc->folder.width - 1;
      if (w == f->folder.activeW)
	topSeg[tCount].x2 += i;
      topSeg[tCount].y2 = fc->folder.y + i;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  topSeg[tCount].x1 = rightOff - topSeg[tCount].x1;
	  topSeg[tCount].x2 = rightOff - topSeg[tCount].x2;
	}
      tCount++;

      /* top tab shadow */
      botSeg[bCount].x1 = fc->folder.x + i;
      botSeg[bCount].y1 = fc->folder.y + fc->folder.height - i - 1;
      botSeg[bCount].x2 = fc->folder.x + fc->folder.width - 1;
      if (w == f->folder.activeW)
	botSeg[bCount].x2 += i;
      botSeg[bCount].y2 = fc->folder.y + fc->folder.height - i - 1;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  botSeg[bCount].x1 = rightOff - botSeg[bCount].x1;
	  botSeg[bCount].x2 = rightOff - botSeg[bCount].x2;
	}
      bCount++;
    }
  if (tCount)
    {
      SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  if (bCount)
    {
      SetGC(f, GC_SHADOWBOT);
      XDrawSegments(dpy, win, f->folder.gc, botSeg, bCount);
      SetGC(f, GC_UNSET);
    }

  tCount = 0;
  for (i = 0; i < st; i++)
    {
      /* left tab shadow */
      topSeg[tCount].x1 = fc->folder.x + i;
      topSeg[tCount].y1 = fc->folder.y + i + 1;
      topSeg[tCount].x2 = fc->folder.x + i;
      topSeg[tCount].y2 = fc->folder.y + fc->folder.height - i - 1;
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	{
	  topSeg[tCount].x1 = rightOff - topSeg[tCount].x1;
	  topSeg[tCount].x2 = rightOff - topSeg[tCount].x2;
	}
      tCount++;
    }
  if (tCount)
    {
      if (f->folder.tabPlacement == XmFOLDER_RIGHT)
	SetGC(f, GC_SHADOWBOT);
      else
	SetGC(f, GC_SHADOWTOP);
      XDrawSegments(dpy, win, f->folder.gc, topSeg, tCount);
      SetGC(f, GC_UNSET);
    }
  free((char *)topSeg);
  free((char *)botSeg);
}

static void 
SetGC(XmLFolderWidget f,
      int type)
{
  Display *dpy;
  XGCValues values;
  XtGCMask mask;

  dpy = XtDisplay(f);
  if (type == GC_SHADOWBOT)
    {
      mask = GCForeground;
      values.foreground = f->manager.bottom_shadow_color;
      if (f->manager.bottom_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
	{
	  mask |= GCFillStyle | GCTile;
	  values.fill_style = FillTiled;
	  values.tile = f->manager.bottom_shadow_pixmap;
	}
      XChangeGC(dpy, f->folder.gc, mask, &values);
    }
  else if (type == GC_SHADOWTOP)
    {
      mask = GCForeground;
      values.foreground = f->manager.top_shadow_color;
      if (f->manager.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
	{
	  mask |= GCFillStyle | GCTile;
	  values.fill_style = FillTiled;
	  values.tile = f->manager.top_shadow_pixmap;
	}
      XChangeGC(dpy, f->folder.gc, mask, &values);
    }
  else if (type == GC_BLANK)
    {
      mask = GCForeground;
      values.foreground = f->folder.blankBg;
      if (f->folder.blankPix != XmUNSPECIFIED_PIXMAP)
	{
	  mask |= GCFillStyle | GCTile;
	  values.fill_style = FillTiled;
	  values.tile = f->folder.blankPix;
	}
      XChangeGC(dpy, f->folder.gc, mask, &values);
    }
  else
    {
      mask = GCFillStyle;
      values.fill_style = FillSolid;
      XChangeGC(dpy, f->folder.gc, mask, &values);
    }
}

static void 
DrawTabHighlight(XmLFolderWidget f,
		 Widget w)
{
  Display *dpy;
  Window win;
  int ht;

  if (!XtIsRealized(w))
    return;
  if (!f->core.visible)
    return;
  dpy = XtDisplay(f);
  win = XtWindow(f);
  ht = f->folder.highlightThickness;
  if (f->folder.focusW == w)
    XSetForeground(dpy, f->folder.gc, f->manager.highlight_color);
  else
    {
      if (f->folder.activeW == w)
	XSetForeground(dpy, f->folder.gc, f->core.background_pixel);
      else
	XSetForeground(dpy, f->folder.gc, f->folder.inactiveBg);
    }
  XFillRectangle(dpy, win, f->folder.gc,
		 w->core.x - ht, w->core.y - ht,
		 XtWidth(w) + w->core.border_width * 2 + ht * 2, 
		 XtHeight(w) + w->core.border_width * 2 + ht * 2);
}

static void 
SetTabPlacement(XmLFolderWidget f,
		Widget tab)
{
  if (!XmIsDrawnButton(tab))
    return;
  if (f->folder.allowRotate == True &&
      f->folder.tabPlacement == XmFOLDER_LEFT)
    XmLDrawnButtonSetType(tab, XmDRAWNB_STRING, XmDRAWNB_UP);
  else if (f->folder.allowRotate == True &&
	   f->folder.tabPlacement == XmFOLDER_RIGHT)
    XmLDrawnButtonSetType(tab, XmDRAWNB_STRING, XmDRAWNB_DOWN);
  else
    XmLDrawnButtonSetType(tab, XmDRAWNB_STRING, XmDRAWNB_RIGHT);
  if (XtIsRealized(tab))
    XClearArea(XtDisplay(tab), XtWindow(tab), 0, 0, 0, 0, True);
}

static void 
GetTabRect(XmLFolderWidget f,
	   Widget tab,
	   XRectangle *rect,
	   int includeShadow)
{
  XmLFolderConstraintRec *fc;
  int st;

  st = f->manager.shadow_thickness;
  fc = (XmLFolderConstraintRec *)(tab->core.constraints);
  rect->x = fc->folder.x;
  rect->y = fc->folder.y;
  rect->width = fc->folder.width;
  rect->height = fc->folder.height;
  if (includeShadow)
    {
      if (f->folder.tabPlacement == XmFOLDER_TOP)
	rect->height += st;
      else if (f->folder.tabPlacement == XmFOLDER_BOTTOM)
	{
	  rect->y -= st;
	  rect->height += st;
	}
      else if (f->folder.tabPlacement == XmFOLDER_LEFT)
	rect->width += st;
      else
	{
	  rect->x -= st;
	  rect->width += st;
	}
    }
}

static void 
SetActiveTab(XmLFolderWidget f,
	     Widget w,
	     XEvent *event,
	     Boolean notify)
{
  XmLFolderCallbackStruct cbs;
  XmLFolderConstraintRec *fc, *cfc;
  int i, j, pos;
  Display *dpy;
  Window win;
  Widget activeW, child, mw, managedW;
  WidgetList children;
  XRectangle rect;
  char *name, buf[256];

  win = (Window)NULL;

  if (f->folder.activeW == w)
    return;
  dpy = 0;
  if (XtIsRealized((Widget)f) && f->core.visible)
    {
      dpy = XtDisplay(f);
      win = XtWindow(f);
    }

  pos = -1;
  for (i = 0; i < f->folder.tabCount; i++)
    if (w == f->folder.tabs[i])
      pos = i;

  cbs.allowActivate = 1;
  cbs.layoutNeeded = 0;
  if (notify == True)
    {
      if (f->folder.debugLevel)
	fprintf(stderr, "XmLFolder: activated %d\n", pos);
      cbs.reason = XmCR_ACTIVATE;
      cbs.event = event;
      cbs.pos = pos;
      XtCallCallbackList((Widget)f, f->folder.activateCallback, &cbs);
    }
  if (!cbs.allowActivate)
    return;

  /* redraw current active tab */
  activeW = f->folder.activeW;
  if (activeW && dpy)
    {
      GetTabRect(f, activeW, &rect, 1);
      XClearArea(dpy, win, rect.x, rect.y, rect.width,
		 rect.height, True);
    }

  f->folder.activeTab = pos;
  f->folder.activeW = w;
  if (!w)
    return;

  /* Not sure this needs to be in the 3.0 (Microline) stuff */
  PrimFocusIn(w, NULL, NULL, NULL);

  /* if we selected a tab not in active row - move row into place */
  if (f->folder.tabsPerRow)
    {
      fc = (XmLFolderConstraintRec *)(w->core.constraints);
      if (fc->folder.row != f->folder.activeRow)
	Layout(f, False);
    }

  /* manage this tabs managed widget if it exists */
  children = f->composite.children;
  f->folder.allowLayout = 0;
  for (i = 0; i < f->composite.num_children; i++)
    {
      child = children[i];
      if (!XtIsSubclass(child, xmPrimitiveWidgetClass))
	continue;
      fc = (XmLFolderConstraintRec *)(child->core.constraints);
      managedW = 0;
      if (fc->folder.managedName)
	{
	  for (j = 0; j < f->composite.num_children; j++)
	    {
	      mw = children[j];
	      if (XtIsSubclass(mw, xmPrimitiveWidgetClass))
		continue;
	      name = XtName(mw);
	      if (name && !strcmp(name, fc->folder.managedName))
		managedW = mw;
	      cfc = (XmLFolderConstraintRec *)(mw->core.constraints);
	      name = cfc->folder.managedName;
	      if (name && !strcmp(name, fc->folder.managedName))
		managedW = mw;
	    }
	  if (!managedW)
	    {
	      sprintf(buf, "SetActiveTab() - managed widget named ");
	      strcat(buf, fc->folder.managedName);
	      strcat(buf, " not found");
	      XmLWarning(child, buf);
	    }
	}
      else
	managedW = fc->folder.managedW;
      if (managedW)
	{
	  if (w == child && !XtIsManaged(managedW))
	    XtManageChild(managedW);
	  if (w != child && XtIsManaged(managedW))
	    XtUnmanageChild(managedW);
	}
    }
  f->folder.allowLayout = 1;

  /* redraw new active tab */
  if (dpy)
    {
      GetTabRect(f, w, &rect, 1);
      XClearArea(dpy, win, rect.x, rect.y, rect.width, rect.height, True);
      XmProcessTraversal(w, XmTRAVERSE_CURRENT);
    }

  if (cbs.layoutNeeded)
	Layout(f, 0);
}

/*
   Utility
*/

static void 
GetCoreBackground(Widget w, 
		  int offset, 
		  XrmValue *value)
{
  value->addr = (caddr_t)&w->core.background_pixel;
}

static void 
GetDefaultTabWidgetClass(Widget w, 
		  int offset, 
		  XrmValue *value)
{
  value->addr = (caddr_t)&xmDrawnButtonWidgetClass;
}

static void 
GetManagerForeground(Widget w,
		     int offset,
		     XrmValue *value)
{
  XmLFolderWidget f;

  f = (XmLFolderWidget)w;
  value->addr = (caddr_t)&f->manager.foreground;
}

static Boolean 
ServerDrawsArcsLarge(Display *dpy,
		     int debug)
{
  Pixmap pixmap;
  XImage *image;
  Window root;
  long pixel;
  int x, y, width, height, result;
  GC gc;

  root = DefaultRootWindow(dpy);
  width = 5;
  height = 5;
  pixmap = XCreatePixmap(dpy, root, width, height, 1);
  gc = XCreateGC(dpy, pixmap, 0L, NULL);
  XSetForeground(dpy, gc, 0L);
  XFillRectangle(dpy, pixmap, gc, 0, 0, width, height);
  XSetForeground(dpy, gc, 1L);
  XDrawArc(dpy, pixmap, gc, 0, 0, width, height, 0, 360 * 64);
  image = XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
  if (debug)
    {
      fprintf(stderr, "Test X server drawn arc (%d by %d):\n",
	      width, height);
      for (y = 0; y < height; y++)
	{
	  fprintf(stderr, " ");
	  for (x = 0; x < width; x++)
	    {
	      pixel = XGetPixel(image, x, y);
	      if (pixel == 0L)
		fprintf(stderr, ".");
	      else
		fprintf(stderr, "X");
	    }
	  fprintf(stderr, "\n");
	}
    }
  if (XGetPixel(image, width - 1, height / 2) != 1L)
    {
      result = 1;
      if (debug)
	fprintf(stderr, "X Server Draws Arcs 1 Pixel Large\n");
    }
  else
    {
      result = 0;
      if (debug)
	fprintf(stderr, "X Server Draws Arcs Within Bounds\n");
    }
  XDestroyImage(image);
  XFreeGC(dpy, gc);
  XFreePixmap(dpy, pixmap);
  return result;
}

/*
   Getting and Setting Values
*/

static Boolean 
SetValues(Widget curW,
	  Widget reqW,
	  Widget newW,
	  ArgList args,
	  Cardinal *narg)
{
  XmLFolderWidget f;
  XmLFolderWidget cur;
  int i;
  Boolean needsLayout, needsRedisplay;
 
  f = (XmLFolderWidget)newW;
  cur = (XmLFolderWidget)curW;
  needsLayout = False;
  needsRedisplay = False;
#define NE(value) (f->value != cur->value)
  if (NE(folder.tabBarHeight))
    {
      XmLWarning((Widget)f, "SetValues() - can't set tabBarHeight");
      f->folder.tabBarHeight = cur->folder.tabBarHeight;
    }
  if (NE(folder.tabCount))
    {
      XmLWarning((Widget)f, "SetValues() - can't set tabCount");
      f->folder.tabCount = cur->folder.tabCount;
    }
  if (NE(folder.activeTab))
    {
      XmLWarning((Widget)f, "SetValues() - can't set activeTab");
      f->folder.activeTab = cur->folder.activeTab;
    }
  if (f->folder.cornerDimension < 1)
    {
      XmLWarning((Widget)f, "SetValues() - cornerDimension can't be < 1");
      f->folder.cornerDimension = cur->folder.cornerDimension;
    }
  if (NE(folder.tabPlacement) ||
      NE(folder.allowRotate))
    {
      f->folder.allowLayout = 0;
      for (i = 0; i < f->folder.tabCount; i++)
	SetTabPlacement(f, f->folder.tabs[i]);
      f->folder.allowLayout = 1;
      needsLayout = True;
    }
  if (NE(folder.inactiveBg) ||
      NE(folder.blankBg) ||
      NE(folder.blankPix) ||
      NE(folder.inactiveFg))
    needsRedisplay = True;
  if (NE(folder.cornerDimension) ||
      NE(folder.cornerStyle) ||
      NE(folder.highlightThickness) ||
      NE(folder.marginHeight) ||
      NE(folder.marginWidth) ||
      NE(folder.pixmapMargin) ||
      NE(manager.shadow_thickness) ||
      NE(folder.tabsPerRow) ||
      NE(folder.spacing))
    needsLayout = True;
  if (NE(folder.renderTable))
    {
      XmRenderTableFree(cur->folder.renderTable);
      CopyRenderTable(f);
    }
#undef NE
  if (needsLayout == True) 
    Layout(f, 1);
  return needsRedisplay;
}

static void 
CopyRenderTable(XmLFolderWidget f)
{
  if (!f->folder.renderTable)
    f->folder.renderTable = XmLRenderTableCopyDefault((Widget)f);
  else
    f->folder.renderTable = XmRenderTableCopy(f->folder.renderTable, NULL, 0);
  if (!f->folder.renderTable)
    XmLWarning((Widget)f, "- fatal error - font list NULL");
}

static Boolean 
ConstraintSetValues(Widget curW,
		    Widget reqW,
		    Widget newW,
		    ArgList args,
		    Cardinal *narg)
{
  XmLFolderConstraintRec *cons, *curCons;
  XmLFolderWidget f;
  int i, hasLabelChange;

  f = (XmLFolderWidget)XtParent(newW);
  if (!XtIsRectObj(newW))
    return False;
  cons = (XmLFolderConstraintRec *)newW->core.constraints;
  curCons = (XmLFolderConstraintRec *)curW->core.constraints;
#define NE(value) (cons->value != curCons->value)
  if (NE(folder.managedName))
    {
      if (curCons->folder.managedName)
	free((char *)curCons->folder.managedName);
      if (cons->folder.managedName)
	cons->folder.managedName = (char *)strdup(cons->folder.managedName);
    }
#undef NE
  hasLabelChange = 0;
  if (XtIsSubclass(newW, xmPrimitiveWidgetClass))
    {
      for (i = 0; i < *narg; i++)
	if (args[i].name && !strcmp(args[i].name, XmNlabelString))
	  hasLabelChange = 1;
      if (hasLabelChange &&
	  (f->folder.tabPlacement == XmFOLDER_LEFT ||
	   f->folder.tabPlacement == XmFOLDER_RIGHT))
	{
	  f->folder.allowLayout = 0;
	  for (i = 0; i < f->folder.tabCount; i++)
	    SetTabPlacement(f, f->folder.tabs[i]);
	  f->folder.allowLayout = 1;
	}
    }
  if (hasLabelChange ||
      curCons->folder.pix != cons->folder.pix ||
      curCons->folder.inactPix != cons->folder.inactPix)
    Layout((XmLFolderWidget)XtParent(curW), 1);
  return False;
}

static Boolean 
CvtStringToCornerStyle(Display *dpy,
		       XrmValuePtr args,
		       Cardinal *narg,
		       XrmValuePtr fromVal,
		       XrmValuePtr toVal,
		       XtPointer *data)
{
  static XmLStringToUCharMap map[] =
  {
    { "CORNER_NONE", XmCORNER_NONE },
    { "CORNER_LINE", XmCORNER_LINE },
    { "CORNER_ARC", XmCORNER_ARC },
    { 0, 0 },
  };

  return XmLCvtStringToUChar(dpy, "XmRCornerStyle", map, fromVal, toVal);
}

static Boolean 
CvtStringToFolderResizePolicy(Display *dpy,
			      XrmValuePtr args,
			      Cardinal *narg,
			      XrmValuePtr fromVal,
			      XrmValuePtr toVal,
			      XtPointer *data)
{
  static XmLStringToUCharMap map[] =
  {
    { "RESIZE_NONE", XmRESIZE_NONE },
    { "RESIZE_STATIC", XmRESIZE_STATIC },
    { "RESIZE_DYNAMIC", XmRESIZE_DYNAMIC },
    { "RESIZE_PACK", XmRESIZE_PACK },
    { 0, 0 },
  };

  return XmLCvtStringToUChar(dpy, "XmRFolderResizePolicy", map,
			     fromVal, toVal);
}

static Boolean 
CvtStringToTabPlacement(Display *dpy,
			XrmValuePtr args,
			Cardinal *narg,
			XrmValuePtr fromVal,
			XrmValuePtr toVal,
			XtPointer *data)
{
  static XmLStringToUCharMap map[] =
  {
    { "FOLDER_TOP", XmFOLDER_TOP },
    { "FOLDER_LEFT", XmFOLDER_LEFT },
    { "FOLDER_BOTTOM", XmFOLDER_BOTTOM },
    { "FOLDER_RIGHT", XmFOLDER_RIGHT },
    { 0, 0 },
  };

  return XmLCvtStringToUChar(dpy, "XmRTabPlacement", map, fromVal, toVal);
}

/*
   Actions, Callbacks and Handlers
*/

static void 
Activate(Widget w,
	 XEvent *event,
	 String *params,
	 Cardinal *nparam)
{
  XmLFolderWidget f;
  XButtonEvent *be;
  XRectangle rect;
  Widget tab;
  int i;

  f = (XmLFolderWidget)w;
  if (!event || event->type != ButtonPress)
    return;
  be = (XButtonEvent *)event;
  if (f->folder.debugLevel)
    fprintf(stderr, "XmLFolder: ButtonPress %d %d\n", be->x, be->y);
  for (i = 0; i < f->folder.tabCount; i++)
    {
      tab = f->folder.tabs[i];
      if (!XtIsManaged(tab) || !XtIsSensitive(tab))
	continue;
      GetTabRect(f, tab, &rect, 0); 
      if (be->x > rect.x && be->x < rect.x + (int)rect.width &&
	  be->y > rect.y && be->y < rect.y + (int)rect.height)
	{
	  if (f->folder.debugLevel)
	    fprintf(stderr, "XmLFolder: Pressed tab %d\n", i);
	  SetActiveTab(f, tab, event, True);
	  return;
	}
    }
}

static void 
PrimActivate(Widget w,
	     XtPointer clientData,
	     XtPointer callData)
{
  XmLFolderWidget f;
  XmAnyCallbackStruct *cbs;

  f = (XmLFolderWidget)XtParent(w);
  cbs = (XmAnyCallbackStruct *)callData;
  SetActiveTab(f, w, cbs->event, True);
}

static void 
PrimFocusIn(Widget w,
	    XEvent *event,
	    String *params,
	    Cardinal *nparam)
{
  XmLFolderWidget f;
  Widget prevW;

  f = (XmLFolderWidget)XtParent(w);
  prevW = f->folder.focusW;
  f->folder.focusW = w;
  DrawTabHighlight(f, w);
  if (prevW)
    DrawTabHighlight(f, prevW);
  XmProcessTraversal(w, XmTRAVERSE_CURRENT);
}

static void 
PrimFocusOut(Widget w,
	     XEvent *event,
	     String *params,
	     Cardinal *nparam)
{
  XmLFolderWidget f;
  Widget prevW;

  f = (XmLFolderWidget)XtParent(w);
  prevW = f->folder.focusW;
  f->folder.focusW = 0;
  if (prevW)
    DrawTabHighlight(f, prevW);
  DrawTabHighlight(f, w);
}

/*
   Public Functions
*/

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

Widget 
XmLFolderAddBitmapTab(Widget w,
		      XmString string,
		      char *bitmapBits,
		      int bitmapWidth,
		      int bitmapHeight)
{
  XmLFolderWidget f;
  Widget tab;
  Pixmap pix, inactPix;
  Window root;
  Display *dpy;
  int depth;
  char name[20];

  if (!XmLIsFolder(w))
    {
      XmLWarning(w, "AddBitmapTab() - widget not a XmLFolder");
      return 0;
    }
  f = (XmLFolderWidget)w;
  dpy = XtDisplay(w);
  root = DefaultRootWindow(dpy);
  depth = DefaultDepthOfScreen(XtScreen(w));
  pix = XCreatePixmapFromBitmapData(dpy, root, bitmapBits,
				    bitmapWidth, bitmapHeight, f->manager.foreground,
				    f->core.background_pixel, depth);
  inactPix = XCreatePixmapFromBitmapData(dpy, root, bitmapBits,
					 bitmapWidth, bitmapHeight, f->folder.inactiveFg,
					 f->folder.inactiveBg, depth);
  sprintf(name, "tab%d", f->folder.tabCount);
  tab = XtVaCreateManagedWidget(name,
				f->folder.tabWidgetClass, w,
				XmNrenderTable, f->folder.renderTable,
				XmNmarginWidth, 0,
				XmNmarginHeight, 0,
				XmNlabelString, string,
				XmNtabPixmap, pix,
				XmNtabInactivePixmap, inactPix,
				XmNtabFreePixmaps, True,
				NULL);
  return tab;
}

Widget 
XmLFolderAddBitmapTabForm(Widget w, 
			  XmString string, 
			  char *bitmapBits,
			  int bitmapWidth,
			  int bitmapHeight)
{
  Widget form, tab;
  XmLFolderWidget f;
  char name[20];

  if (!XmLIsFolder(w))
    {
      XmLWarning(w, "AddBitmapTabForm() - widget not a XmLFolder");
      return 0;
    }
  f = (XmLFolderWidget)w;
  tab = XmLFolderAddBitmapTab(w, string, bitmapBits,
			      bitmapWidth, bitmapHeight);
  sprintf(name, "form%d", f->folder.tabCount);
  form = XtVaCreateManagedWidget(name,
				 xmFormWidgetClass, w,
				 XmNbackground, f->core.background_pixel,
				 NULL);
  XtVaSetValues(tab, XmNtabManagedWidget, form, NULL);
  return form;
}

Widget 
XmLFolderAddTab(Widget w, 
		XmString string)
{
  Widget tab;
  XmLFolderWidget f;
  char name[20];

  if (!XmLIsFolder(w))
    {
      XmLWarning(w, "AddTab() - widget not a XmLFolder");
      return 0;
    }
  f = (XmLFolderWidget)w;
  sprintf(name, "tab%d", f->folder.tabCount);
  tab = XtVaCreateManagedWidget(name,
				f->folder.tabWidgetClass, w,
				XmNrenderTable, f->folder.renderTable,
				XmNmarginWidth, 0,
				XmNmarginHeight, 0,
				XmNlabelString, string,
				NULL);
  return tab;
}

Widget 
XmLFolderAddTabFromClass(Widget w, 
		XmString string)
{
  Widget tab;
  XmLFolderWidget f;
  char name[20];

  if (!XmLIsFolder(w))
    {
      XmLWarning(w, "AddTab() - widget not a XmLFolder");
      return 0;
    }
  f = (XmLFolderWidget)w;
  sprintf(name, "tab%d", f->folder.tabCount);

  tab = XtVaCreateManagedWidget(name,
								f->folder.tabWidgetClass,
/*  								xmDrawnButtonWidgetClass,  */
								w,
								XmNrenderTable, f->folder.renderTable,
/* 				XmNmarginWidth, 0, */
/* 				XmNmarginHeight, 0, */
								XmNlabelString, string,
								NULL);
  return tab;
}

Widget 
XmLFolderAddTabForm(Widget w, 
		    XmString string)
{
  Widget form, tab;
  XmLFolderWidget f;
  char name[20];

  if (!XmLIsFolder(w))
    {
      XmLWarning(w, "AddBitmapTabForm() - widget not a XmLFolder");
      return 0;
    }
  f = (XmLFolderWidget)w;
  tab = XmLFolderAddTab(w, string);
  sprintf(name, "form%d", f->folder.tabCount);
  form = XtVaCreateManagedWidget(name,
				 xmFormWidgetClass, w,
				 XmNbackground, f->core.background_pixel,
				 NULL);
  XtVaSetValues(tab, XmNtabManagedWidget, form, NULL);
  return form;
}

void 
XmLFolderSetActiveTab(Widget w,
		      int position,
		      Boolean notify)
{
  XmLFolderWidget f;

  if (!XmLIsFolder(w))
    {
      XmLWarning(w, "SetActiveTab() - widget not a XmLFolder");
      return;
    }
  f = (XmLFolderWidget)w;
  if (position < 0 || position >= f->folder.tabCount)
    {
      XmLWarning(w, "SetActiveTab() - invalid position");
      return;
    }
  SetActiveTab(f, f->folder.tabs[position], 0, notify);
}
