17a84e134Smrg/*
27a84e134SmrgCopyright 1989, 1994, 1998  The Open Group
37a84e134Smrg
47a84e134SmrgPermission to use, copy, modify, distribute, and sell this software and its
57a84e134Smrgdocumentation for any purpose is hereby granted without fee, provided that
67a84e134Smrgthe above copyright notice appear in all copies and that both that
77a84e134Smrgcopyright notice and this permission notice appear in supporting
87a84e134Smrgdocumentation.
97a84e134Smrg
107a84e134SmrgThe above copyright notice and this permission notice shall be included in
117a84e134Smrgall copies or substantial portions of the Software.
127a84e134Smrg
137a84e134SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
147a84e134SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
157a84e134SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
167a84e134SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
177a84e134SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
187a84e134SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
197a84e134Smrg
207a84e134SmrgExcept as contained in this notice, the name of The Open Group shall not be
217a84e134Smrgused in advertising or otherwise to promote the sale, use or other dealings
227a84e134Smrgin this Software without prior written authorization from The Open Group.
237a84e134Smrg*/
247a84e134Smrg
257a84e134Smrg/*
267a84e134Smrg * List.c - List widget
277a84e134Smrg *
287a84e134Smrg * This is a List widget.  It allows the user to select an item in a list and
297a84e134Smrg * notifies the application through a callback function.
307a84e134Smrg *
31421c997bSmrg *	Created:	8/13/88
327a84e134Smrg *	By:		Chris D. Peterson
337a84e134Smrg *                      MIT X Consortium
347a84e134Smrg */
357a84e134Smrg
367a84e134Smrg#ifdef HAVE_CONFIG_H
377a84e134Smrg#include <config.h>
387a84e134Smrg#endif
397a84e134Smrg#include <stdio.h>
407a84e134Smrg#include <ctype.h>
417a84e134Smrg#include <X11/IntrinsicP.h>
427a84e134Smrg#include <X11/StringDefs.h>
437a84e134Smrg#include <X11/Xmu/Drawing.h>
447a84e134Smrg#include <X11/Xaw/ListP.h>
457a84e134Smrg#include <X11/Xaw/XawInit.h>
467a84e134Smrg#include "Private.h"
477a84e134Smrg
487a84e134Smrg#define HeightLock  1
497a84e134Smrg#define WidthLock   2
507a84e134Smrg#define LongestLock 4
517a84e134Smrg
527a84e134Smrg#define HeightFree(w)	!(((ListWidget)(w))->list.freedoms & HeightLock)
537a84e134Smrg#define WidthFree(w)	!(((ListWidget)(w))->list.freedoms & WidthLock)
547a84e134Smrg#define LongestFree(w)	!(((ListWidget)(w))->list.freedoms & LongestLock)
557a84e134Smrg
567a84e134Smrg#define MaxSize 32767
577a84e134Smrg
587a84e134Smrg/*
597a84e134Smrg * Class Methods
607a84e134Smrg */
617a84e134Smrgstatic void XawListDestroy(Widget);
627a84e134Smrgstatic void XawListInitialize(Widget, Widget, ArgList, Cardinal*);
637a84e134Smrgstatic XtGeometryResult XawListQueryGeometry(Widget, XtWidgetGeometry*,
647a84e134Smrg					     XtWidgetGeometry*);
657a84e134Smrgstatic void XawListRedisplay(Widget, XEvent*, Region);
667a84e134Smrgstatic void XawListResize(Widget);
677a84e134Smrgstatic Boolean XawListSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
687a84e134Smrg
697a84e134Smrg/*
707a84e134Smrg * Prototypes
717a84e134Smrg */
727a84e134Smrgstatic void CalculatedValues(Widget);
737a84e134Smrgstatic void ChangeSize(Widget, unsigned int, unsigned int);
747a84e134Smrgstatic void ClipToShadowInteriorAndLongest(ListWidget, GC*, unsigned int);
757a84e134Smrgstatic int CvtToItem(Widget, int, int, int*);
767a84e134Smrgstatic void FindCornerItems(Widget, XEvent*, int*, int*);
777a84e134Smrgstatic void GetGCs(Widget);
787a84e134Smrgstatic void HighlightBackground(Widget, int, int, GC);
797a84e134Smrgstatic Bool ItemInRectangle(Widget, int, int, int);
807a84e134Smrgstatic Bool Layout(Widget, Bool, Bool, Dimension*, Dimension*);
817a84e134Smrgstatic void PaintItemName(Widget, int);
827a84e134Smrgstatic void ResetList(Widget, Bool, Bool);
837a84e134Smrg
84421c997bSmrg/*
857a84e134Smrg * Actions
867a84e134Smrg */
877a84e134Smrgstatic void Notify(Widget, XEvent*, String*, Cardinal*);
887a84e134Smrgstatic void Set(Widget, XEvent*, String*, Cardinal*);
897a84e134Smrgstatic void Unset(Widget, XEvent*, String*, Cardinal*);
907a84e134Smrg
917a84e134Smrg/*
927a84e134Smrg * Initialization
937a84e134Smrg */
94421c997bSmrgstatic char defaultTranslations[] =
957a84e134Smrg"<Btn1Down>:"	"Set()\n"
967a84e134Smrg"<Btn1Up>:"	"Notify()\n"
977a84e134Smrg;
987a84e134Smrg
997a84e134Smrg#define offset(field) XtOffsetOf(ListRec, field)
1007a84e134Smrgstatic XtResource resources[] = {
1017a84e134Smrg  {
1027a84e134Smrg    XtNforeground,
1037a84e134Smrg    XtCForeground,
1047a84e134Smrg    XtRPixel,
1057a84e134Smrg    sizeof(Pixel),
1067a84e134Smrg    offset(list.foreground),
1077a84e134Smrg    XtRString,
1085ec34c4cSmrg    (XtPointer)XtDefaultForeground
1097a84e134Smrg  },
1107a84e134Smrg  {
1117a84e134Smrg    XtNcursor,
1127a84e134Smrg    XtCCursor,
1137a84e134Smrg    XtRCursor,
1147a84e134Smrg    sizeof(Cursor),
1157a84e134Smrg    offset(simple.cursor),
1167a84e134Smrg    XtRString,
1175ec34c4cSmrg    (XtPointer)"left_ptr"
1187a84e134Smrg  },
1197a84e134Smrg  {
1207a84e134Smrg    XtNfont,
1217a84e134Smrg    XtCFont,
1227a84e134Smrg    XtRFontStruct,
1237a84e134Smrg    sizeof(XFontStruct*),
1247a84e134Smrg    offset(list.font),
1257a84e134Smrg    XtRString,
1265ec34c4cSmrg    (XtPointer)XtDefaultFont
1277a84e134Smrg  },
1287a84e134Smrg  {
1297a84e134Smrg    XtNfontSet,
1307a84e134Smrg    XtCFontSet,
1317a84e134Smrg    XtRFontSet,
1327a84e134Smrg    sizeof(XFontSet),
1337a84e134Smrg    offset(list.fontset),
1347a84e134Smrg    XtRString,
1355ec34c4cSmrg    (XtPointer)XtDefaultFontSet
1367a84e134Smrg  },
1377a84e134Smrg  {
1387a84e134Smrg    XtNlist,
1397a84e134Smrg    XtCList,
1407a84e134Smrg    XtRPointer,
1417a84e134Smrg    sizeof(char**),
1427a84e134Smrg    offset(list.list),
1437a84e134Smrg#ifdef notyet
1447a84e134Smrg    XtRStringArray,
1457a84e134Smrg#else
1467a84e134Smrg    XtRString,
1477a84e134Smrg#endif
1487a84e134Smrg    NULL
1497a84e134Smrg  },
1507a84e134Smrg  {
1517a84e134Smrg    XtNdefaultColumns,
1527a84e134Smrg    XtCColumns,
1537a84e134Smrg    XtRInt,
1547a84e134Smrg    sizeof(int),
1557a84e134Smrg    offset(list.default_cols),
1567a84e134Smrg    XtRImmediate,
1577a84e134Smrg    (XtPointer)2
1587a84e134Smrg  },
1597a84e134Smrg  {
1607a84e134Smrg    XtNlongest,
1617a84e134Smrg    XtCLongest,
1627a84e134Smrg    XtRInt,
1637a84e134Smrg    sizeof(int),
1647a84e134Smrg    offset(list.longest),
1657a84e134Smrg    XtRImmediate,
1667a84e134Smrg    (XtPointer)0
1677a84e134Smrg  },
1687a84e134Smrg  {
1697a84e134Smrg    XtNnumberStrings,
1707a84e134Smrg    XtCNumberStrings,
1717a84e134Smrg    XtRInt,
1727a84e134Smrg    sizeof(int),
1737a84e134Smrg    offset(list.nitems),
1747a84e134Smrg    XtRImmediate,
1757a84e134Smrg    (XtPointer)0
1767a84e134Smrg  },
1777a84e134Smrg  {
1787a84e134Smrg    XtNpasteBuffer,
1797a84e134Smrg    XtCBoolean,
1807a84e134Smrg    XtRBoolean,
1817a84e134Smrg    sizeof(Boolean),
1827a84e134Smrg    offset(list.paste),
1837a84e134Smrg    XtRImmediate,
1847a84e134Smrg    (XtPointer)False
1857a84e134Smrg  },
1867a84e134Smrg  {
1877a84e134Smrg    XtNforceColumns,
1887a84e134Smrg    XtCColumns,
1897a84e134Smrg    XtRBoolean,
1907a84e134Smrg    sizeof(Boolean),
1917a84e134Smrg    offset(list.force_cols),
1927a84e134Smrg    XtRImmediate,
1937a84e134Smrg    (XtPointer)False
1947a84e134Smrg  },
1957a84e134Smrg  {
1967a84e134Smrg    XtNverticalList,
1977a84e134Smrg    XtCBoolean,
1987a84e134Smrg    XtRBoolean,
1997a84e134Smrg    sizeof(Boolean),
2007a84e134Smrg    offset(list.vertical_cols),
2017a84e134Smrg    XtRImmediate,
2027a84e134Smrg    (XtPointer)False
2037a84e134Smrg  },
2047a84e134Smrg  {
2057a84e134Smrg    XtNinternalWidth,
2067a84e134Smrg    XtCWidth,
2077a84e134Smrg    XtRDimension,
2087a84e134Smrg    sizeof(Dimension),
2097a84e134Smrg    offset(list.internal_width),
2107a84e134Smrg    XtRImmediate,
2117a84e134Smrg    (XtPointer)2
2127a84e134Smrg  },
2137a84e134Smrg  {
2147a84e134Smrg    XtNinternalHeight,
2157a84e134Smrg    XtCHeight,
2167a84e134Smrg    XtRDimension,
2177a84e134Smrg    sizeof(Dimension),
2187a84e134Smrg    offset(list.internal_height),
2197a84e134Smrg    XtRImmediate,
2207a84e134Smrg    (XtPointer)2
2217a84e134Smrg  },
2227a84e134Smrg  {
2237a84e134Smrg    XtNcolumnSpacing,
2247a84e134Smrg    XtCSpacing,
2257a84e134Smrg    XtRDimension,
2267a84e134Smrg    sizeof(Dimension),
2277a84e134Smrg    offset(list.column_space),
2287a84e134Smrg    XtRImmediate,
2297a84e134Smrg    (XtPointer)6
2307a84e134Smrg  },
2317a84e134Smrg  {
2327a84e134Smrg    XtNrowSpacing,
2337a84e134Smrg    XtCSpacing,
2347a84e134Smrg    XtRDimension,
2357a84e134Smrg    sizeof(Dimension),
2367a84e134Smrg    offset(list.row_space),
2377a84e134Smrg    XtRImmediate,
2387a84e134Smrg    (XtPointer)2
2397a84e134Smrg  },
2407a84e134Smrg  {
2417a84e134Smrg    XtNcallback,
2427a84e134Smrg    XtCCallback,
2437a84e134Smrg    XtRCallback,
2447a84e134Smrg    sizeof(XtPointer),
2457a84e134Smrg    offset(list.callback),
2467a84e134Smrg    XtRCallback,
2477a84e134Smrg    NULL
2487a84e134Smrg  },
2497a84e134Smrg#ifndef OLDXAW
2507a84e134Smrg  {
2517a84e134Smrg    XtNshowCurrent,
2527a84e134Smrg    XtCBoolean,
2537a84e134Smrg    XtRBoolean,
2547a84e134Smrg    sizeof(Boolean),
2557a84e134Smrg    offset(list.show_current),
2567a84e134Smrg    XtRImmediate,
2577a84e134Smrg    (XtPointer)False
2587a84e134Smrg  },
2597a84e134Smrg#endif
2607a84e134Smrg};
2617a84e134Smrg#undef offset
2627a84e134Smrg
2637a84e134Smrgstatic XtActionsRec actions[] = {
2647a84e134Smrg      {"Notify",	Notify},
2657a84e134Smrg      {"Set",		Set},
2667a84e134Smrg      {"Unset",		Unset},
2677a84e134Smrg};
2687a84e134Smrg
2697a84e134Smrg#define Superclass (&simpleClassRec)
2707a84e134SmrgListClassRec listClassRec = {
2717a84e134Smrg  /* core */
2727a84e134Smrg  {
2737a84e134Smrg    (WidgetClass)Superclass,		/* superclass */
2747a84e134Smrg    "List",				/* class_name */
2757a84e134Smrg    sizeof(ListRec),			/* widget_size */
2767a84e134Smrg    XawInitializeWidgetSet,		/* class_initialize */
2777a84e134Smrg    NULL,				/* class_part_initialize */
2787a84e134Smrg    False,				/* class_inited */
2797a84e134Smrg    XawListInitialize,			/* initialize */
2807a84e134Smrg    NULL,				/* initialize_hook */
2817a84e134Smrg    XtInheritRealize,			/* realize */
2827a84e134Smrg    actions,				/* actions */
2837a84e134Smrg    XtNumber(actions),			/* num_actions */
2847a84e134Smrg    resources,				/* resources */
2857a84e134Smrg    XtNumber(resources),		/* num_resources */
2867a84e134Smrg    NULLQUARK,				/* xrm_class */
2877a84e134Smrg    True,				/* compress_motion */
2887a84e134Smrg    False,				/* compress_exposure */
2897a84e134Smrg    True,				/* compress_enterleave */
2907a84e134Smrg    False,				/* visible_interest */
2917a84e134Smrg    XawListDestroy,			/* destroy */
2927a84e134Smrg    XawListResize,			/* resize */
2937a84e134Smrg    XawListRedisplay,			/* expose */
2947a84e134Smrg    XawListSetValues,			/* set_values */
2957a84e134Smrg    NULL,				/* set_values_hook */
2967a84e134Smrg    XtInheritSetValuesAlmost,		/* set_values_almost */
2977a84e134Smrg    NULL,				/* get_values_hook */
2987a84e134Smrg    NULL,				/* accept_focus */
2997a84e134Smrg    XtVersion,				/* version */
3007a84e134Smrg    NULL,				/* callback_private */
3017a84e134Smrg    defaultTranslations,		/* tm_table */
3027a84e134Smrg    XawListQueryGeometry,		/* query_geometry */
303efbcb2bfSmrg    NULL,				/* display_accelerator */
304efbcb2bfSmrg    NULL,				/* extension */
3057a84e134Smrg  },
3067a84e134Smrg  /* simple */
3077a84e134Smrg  {
3087a84e134Smrg    XtInheritChangeSensitive,		/* change_sensitive */
309efbcb2bfSmrg#ifndef OLDXAW
310efbcb2bfSmrg    NULL,
311efbcb2bfSmrg#endif
3127a84e134Smrg  },
3137a84e134Smrg  /* list */
3147a84e134Smrg  {
3157a84e134Smrg    NULL,				/* extension */
3167a84e134Smrg  },
3177a84e134Smrg};
3187a84e134Smrg
3197a84e134SmrgWidgetClass listWidgetClass = (WidgetClass)&listClassRec;
3207a84e134Smrg
3217a84e134Smrg/*
3227a84e134Smrg * Implementation
3237a84e134Smrg */
3247a84e134Smrgstatic void
3257a84e134SmrgGetGCs(Widget w)
3267a84e134Smrg{
3277a84e134Smrg    ListWidget lw = (ListWidget)w;
328efbcb2bfSmrg    XGCValues	values = {
329efbcb2bfSmrg	.foreground	= lw->list.foreground,
330efbcb2bfSmrg	.font		= lw->list.font->fid
331efbcb2bfSmrg    };
3327a84e134Smrg
3337a84e134Smrg    if (lw->simple.international == True)
3347a84e134Smrg	lw->list.normgc = XtAllocateGC(w, 0, GCForeground, &values, GCFont, 0);
3357a84e134Smrg    else
3367a84e134Smrg	lw->list.normgc = XtGetGC(w, GCForeground | GCFont, &values);
3377a84e134Smrg
3387a84e134Smrg    values.foreground	= lw->core.background_pixel;
3397a84e134Smrg
3407a84e134Smrg    if (lw->simple.international == True)
3417a84e134Smrg	lw->list.revgc = XtAllocateGC(w, 0, GCForeground, &values, GCFont, 0);
3427a84e134Smrg    else
3437a84e134Smrg	lw->list.revgc = XtGetGC(w, GCForeground | GCFont, &values);
3447a84e134Smrg
345421c997bSmrg    values.tile       = XmuCreateStippledPixmap(XtScreen(w),
3467a84e134Smrg						lw->list.foreground,
3477a84e134Smrg						lw->core.background_pixel,
3487a84e134Smrg						lw->core.depth);
3497a84e134Smrg    values.fill_style = FillTiled;
3507a84e134Smrg
3517a84e134Smrg    if (lw->simple.international == True)
3527a84e134Smrg	lw->list.graygc = XtAllocateGC(w, 0, GCTile | GCFillStyle,
3537a84e134Smrg				       &values, GCFont, 0);
3547a84e134Smrg    else
3557a84e134Smrg	lw->list.graygc = XtGetGC(w, GCFont | GCTile | GCFillStyle, &values);
3567a84e134Smrg}
3577a84e134Smrg
3587a84e134Smrgstatic void
3597a84e134SmrgCalculatedValues(Widget w)
3607a84e134Smrg{
3617a84e134Smrg    ListWidget lw = (ListWidget)w;
3627a84e134Smrg
3637a84e134Smrg    /* If list is NULL then the list will just be the name of the widget */
3647a84e134Smrg    if (lw->list.list == NULL) {
3657a84e134Smrg	lw->list.list = &lw->core.name;
3667a84e134Smrg	lw->list.nitems = 1;
3677a84e134Smrg    }
3687a84e134Smrg
3697a84e134Smrg    /* Get number of items */
3707a84e134Smrg    if (lw->list.nitems == 0)
3717a84e134Smrg	for (; lw->list.list[lw->list.nitems] != NULL ; lw->list.nitems++)
3727a84e134Smrg	    ;
3737a84e134Smrg
3747a84e134Smrg    /* Get column width */
3757a84e134Smrg    if (LongestFree(lw)) {
376efbcb2bfSmrg        int i;
377efbcb2bfSmrg
3787a84e134Smrg	lw->list.longest = 0; /* so it will accumulate real longest below */
3797a84e134Smrg
3807a84e134Smrg	for (i = 0 ; i < lw->list.nitems; i++) {
381efbcb2bfSmrg	    int len;
382efbcb2bfSmrg
3837a84e134Smrg	    if (lw->simple.international == True)
3847a84e134Smrg		len = XmbTextEscapement(lw->list.fontset, lw->list.list[i],
3855ec34c4cSmrg					(int)strlen(lw->list.list[i]));
3867a84e134Smrg	    else
3877a84e134Smrg		len = XTextWidth(lw->list.font, lw->list.list[i],
3885ec34c4cSmrg				 (int)strlen(lw->list.list[i]));
3897a84e134Smrg	    if (len > lw->list.longest)
3907a84e134Smrg		lw->list.longest = len;
3917a84e134Smrg	}
3927a84e134Smrg    }
3937a84e134Smrg
3947a84e134Smrg    lw->list.col_width = lw->list.longest + lw->list.column_space;
3957a84e134Smrg}
3967a84e134Smrg
3977a84e134Smrg/*
3987a84e134Smrg * Function:
3997a84e134Smrg *	ResetList
4007a84e134Smrg *
4017a84e134Smrg * Parameters:
4027a84e134Smrg *	w	- list widget
4037a84e134Smrg *	changex - allow the height or width to change?
4047a84e134Smrg *	changey - ""
4057a84e134Smrg *
4067a84e134Smrg * Description:
4077a84e134Smrg *	Resets the new list when important things change.
4087a84e134Smrg *
4097a84e134Smrg * Returns:
4107a84e134Smrg *	True if width or height have been changed
4117a84e134Smrg */
4127a84e134Smrgstatic void
4137a84e134SmrgResetList(Widget w, Bool changex, Bool changey)
4147a84e134Smrg{
4157a84e134Smrg    Dimension width = XtWidth(w);
4167a84e134Smrg    Dimension height = XtHeight(w);
4177a84e134Smrg
4187a84e134Smrg    CalculatedValues(w);
4197a84e134Smrg
4207a84e134Smrg    if (Layout(w, changex, changey, &width, &height)) {
4217a84e134Smrg	if (XtIsComposite(XtParent(w)))
4227a84e134Smrg	    ChangeSize(w, width, height);
4237a84e134Smrg	else {
4247a84e134Smrg	    XtWidth(w) = width;
4257a84e134Smrg	    XtHeight(w) = height;
4267a84e134Smrg	}
4277a84e134Smrg    }
4287a84e134Smrg}
4297a84e134Smrg
4307a84e134Smrg/*
4317a84e134Smrg * Function:
4327a84e134Smrg *	ChangeSize
4337a84e134Smrg *
4347a84e134Smrg * Parameters:
4357a84e134Smrg *	w - widget to try change the size of
4367a84e134Smrg *
4377a84e134Smrg * Description:
4387a84e134Smrg *	Laysout the widget.
4397a84e134Smrg */
4407a84e134Smrgstatic void
4417a84e134SmrgChangeSize(Widget w, unsigned int width, unsigned int height)
4427a84e134Smrg{
443efbcb2bfSmrg    XtWidgetGeometry request = {
444efbcb2bfSmrg	.request_mode = CWWidth | CWHeight,
445efbcb2bfSmrg	.width = (Dimension)width,
446efbcb2bfSmrg	.height = (Dimension)height
447efbcb2bfSmrg    };
448efbcb2bfSmrg    XtWidgetGeometry reply;
4497a84e134Smrg
4507a84e134Smrg    switch (XtMakeGeometryRequest(w, &request, &reply)) {
4517a84e134Smrg	case XtGeometryYes:
4527a84e134Smrg	case XtGeometryNo:
4537a84e134Smrg	    break;
4547a84e134Smrg	case XtGeometryAlmost:
4557a84e134Smrg	    Layout(w, request.height != reply.height,
4567a84e134Smrg		   request.width != reply.width, &reply.width, &reply.height);
4577a84e134Smrg	    request = reply;
4587a84e134Smrg	    switch (XtMakeGeometryRequest(w, &request, &reply)) {
4597a84e134Smrg		case XtGeometryYes:
4607a84e134Smrg		case XtGeometryNo:
4617a84e134Smrg		    break;
4627a84e134Smrg		case XtGeometryAlmost:
4637a84e134Smrg		    request = reply;
4647a84e134Smrg		    Layout(w, False, False, &request.width, &request.height);
4657a84e134Smrg		    request.request_mode = CWWidth | CWHeight;
4667a84e134Smrg		    XtMakeGeometryRequest(w, &request, &reply);
4675b16253fSmrg		    /*FALLTHROUGH*/
4687a84e134Smrg		default:
4697a84e134Smrg		    break;
4707a84e134Smrg	}
4715b16253fSmrg	/*FALLTHROUGH*/
4727a84e134Smrg	default:
4737a84e134Smrg	    break;
4747a84e134Smrg    }
4757a84e134Smrg}
4767a84e134Smrg
4777a84e134Smrg/*ARGSUSED*/
478421c997bSmrgstatic void
4795ec34c4cSmrgXawListInitialize(Widget temp1 _X_UNUSED, Widget cnew, ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
4807a84e134Smrg{
4817a84e134Smrg    ListWidget lw = (ListWidget)cnew;
4827a84e134Smrg
4837a84e134Smrg    if (!lw->list.font) XtError("Aborting: no font found\n");
484421c997bSmrg    if (lw->simple.international && !lw->list.fontset)
4857a84e134Smrg	XtError("Aborting: no fontset found\n");
486421c997bSmrg
4877a84e134Smrg    /*
4887a84e134Smrg     * Initialize all private resources
4897a84e134Smrg     */
4907a84e134Smrg    /* record for posterity if we are free */
4917a84e134Smrg    lw->list.freedoms = ((XtWidth(lw) != 0) * WidthLock +
4927a84e134Smrg			 (XtHeight(lw) != 0) * HeightLock +
4937a84e134Smrg			 (lw->list.longest != 0) * LongestLock);
4947a84e134Smrg
4957a84e134Smrg    GetGCs(cnew);
4967a84e134Smrg
4977a84e134Smrg    /* Set row height, based on font or fontset */
4987a84e134Smrg    if (lw->simple.international == True)
4997a84e134Smrg	lw->list.row_height =
5007a84e134Smrg		XExtentsOfFontSet(lw->list.fontset)->max_ink_extent.height +
5017a84e134Smrg				  lw->list.row_space;
5027a84e134Smrg    else
5037a84e134Smrg	lw->list.row_height = lw->list.font->max_bounds.ascent +
5047a84e134Smrg			      lw->list.font->max_bounds.descent +
5057a84e134Smrg			      lw->list.row_space;
5067a84e134Smrg
5077a84e134Smrg    ResetList(cnew, WidthFree(lw), HeightFree(lw));
5087a84e134Smrg
5097a84e134Smrg    lw->list.highlight = lw->list.is_highlighted = NO_HIGHLIGHT;
5107a84e134Smrg}
5117a84e134Smrg
5127a84e134Smrg/*
5137a84e134Smrg * Function:
5147a84e134Smrg *	CvtToItem
5157a84e134Smrg *
5167a84e134Smrg * Parameters:
5177a84e134Smrg *	w    - list widget
5187a84e134Smrg *	xloc - x location
5197a84e134Smrg *	yloc - y location
5207a84e134Smrg *
5217a84e134Smrg * Description:
5227a84e134Smrg *	Converts Xcoord to item number of item containing that point.
5237a84e134Smrg *
5247a84e134Smrg * Returns:
5257a84e134Smrg *	Item number
5267a84e134Smrg */
5277a84e134Smrgstatic int
5287a84e134SmrgCvtToItem(Widget w, int xloc, int yloc, int *item)
5297a84e134Smrg{
5307a84e134Smrg    int one, another;
5317a84e134Smrg    ListWidget lw = (ListWidget)w;
5327a84e134Smrg    int ret_val = OKAY;
5337a84e134Smrg
5347a84e134Smrg    if (lw->list.vertical_cols) {
5357a84e134Smrg	one = lw->list.nrows * ((xloc - (int)lw->list.internal_width)
5367a84e134Smrg			        / lw->list.col_width);
5377a84e134Smrg	another = (yloc - (int)lw->list.internal_height) / lw->list.row_height;
5387a84e134Smrg	/* If out of range, return minimum possible value */
5397a84e134Smrg	if (another >= lw->list.nrows) {
5407a84e134Smrg	    another = lw->list.nrows - 1;
5417a84e134Smrg	    ret_val = OUT_OF_RANGE;
5427a84e134Smrg	}
5437a84e134Smrg    }
5447a84e134Smrg    else {
5457a84e134Smrg	one = (lw->list.ncols * ((yloc - (int)lw->list.internal_height)
5467a84e134Smrg				 / lw->list.row_height));
5477a84e134Smrg	/* If in right margin handle things right */
5487a84e134Smrg	another = (xloc - (int)lw->list.internal_width) / lw->list.col_width;
5497a84e134Smrg	if (another >= lw->list.ncols) {
550421c997bSmrg	    another = lw->list.ncols - 1;
5517a84e134Smrg	    ret_val = OUT_OF_RANGE;
5527a84e134Smrg	}
553421c997bSmrg    }
5547a84e134Smrg    if (xloc < 0 || yloc < 0)
5557a84e134Smrg	ret_val = OUT_OF_RANGE;
5567a84e134Smrg    if (one < 0)
5577a84e134Smrg	one = 0;
5587a84e134Smrg    if (another < 0)
5597a84e134Smrg	another = 0;
5607a84e134Smrg    *item = one + another;
5617a84e134Smrg    if (*item >= lw->list.nitems)
5627a84e134Smrg	return (OUT_OF_RANGE);
5637a84e134Smrg
5647a84e134Smrg  return (ret_val);
5657a84e134Smrg}
5667a84e134Smrg
5677a84e134Smrg/*
5687a84e134Smrg * Function:
5697a84e134Smrg *	FindCornerItems
5707a84e134Smrg *
5717a84e134Smrg * Arguments:
5727a84e134Smrg *	w      - list widget
5737a84e134Smrg *	event  - event structure that has the rectangle it it
5747a84e134Smrg *	ul_ret - the corners (return)
5757a84e134Smrg *	lr_ret - ""
5767a84e134Smrg *
5777a84e134Smrg * Description:
5787a84e134Smrg *	Find the corners of the rectangle in item space.
5797a84e134Smrg */
5807a84e134Smrgstatic void
5817a84e134SmrgFindCornerItems(Widget w, XEvent *event, int *ul_ret, int *lr_ret)
5827a84e134Smrg{
5837a84e134Smrg    int xloc, yloc;
5847a84e134Smrg
5857a84e134Smrg    xloc = event->xexpose.x;
5867a84e134Smrg    yloc = event->xexpose.y;
5877a84e134Smrg    CvtToItem(w, xloc, yloc, ul_ret);
5887a84e134Smrg    xloc += event->xexpose.width;
5897a84e134Smrg    yloc += event->xexpose.height;
5907a84e134Smrg    CvtToItem(w, xloc, yloc, lr_ret);
5917a84e134Smrg}
5927a84e134Smrg
5937a84e134Smrg/*
5947a84e134Smrg * Function:
5957a84e134Smrg *	ItemInRectangle
5967a84e134Smrg *
5977a84e134Smrg * Parameters:
5987a84e134Smrg *	w    - list widget
5997a84e134Smrg *	ul   - corners of the rectangle in item space
6007a84e134Smrg *	lr   - ""
6017a84e134Smrg *	item - item to check
6027a84e134Smrg *
6037a84e134Smrg * Returns:
6047a84e134Smrg *	True if the item passed is in the given rectangle
6057a84e134Smrg */
6067a84e134Smrgstatic Bool
6077a84e134SmrgItemInRectangle(Widget w, int ul, int lr, int item)
6087a84e134Smrg{
6097a84e134Smrg    ListWidget lw = (ListWidget)w;
6107a84e134Smrg    int mod_item;
6117a84e134Smrg    int things;
612421c997bSmrg
613421c997bSmrg    if (item < ul || item > lr)
6147a84e134Smrg      return (False);
6157a84e134Smrg    if (lw->list.vertical_cols)
6167a84e134Smrg	things = lw->list.nrows;
6177a84e134Smrg    else
6187a84e134Smrg	things = lw->list.ncols;
6197a84e134Smrg
6207a84e134Smrg    mod_item = item % things;
6217a84e134Smrg    if ((mod_item >= ul % things) && (mod_item <= lr % things))
6227a84e134Smrg      return (True);
6237a84e134Smrg
6247a84e134Smrg    return (False);
6257a84e134Smrg}
6267a84e134Smrg
6277a84e134Smrg/* HighlightBackground()
6287a84e134Smrg *
6297a84e134Smrg * Paints the color of the background for the given item.  It performs
6307a84e134Smrg * clipping to the interior of internal_width/height by hand, as its a
6317a84e134Smrg * simple calculation and probably much faster than using Xlib and a clip mask.
6327a84e134Smrg *
6337a84e134Smrg *  x, y - ul corner of the area item occupies.
6347a84e134Smrg *  gc - the gc to use to paint this rectangle
6357a84e134Smrg */
6367a84e134Smrgstatic void
6377a84e134SmrgHighlightBackground(Widget w, int x, int y, GC gc)
6387a84e134Smrg{
6397a84e134Smrg    ListWidget lw = (ListWidget)w;
6405ec34c4cSmrg    Dimension width = (Dimension)lw->list.col_width;
6415ec34c4cSmrg    Dimension height = (Dimension)lw->list.row_height;
6425ec34c4cSmrg    Dimension frame_limited_width = (Dimension)(XtWidth(w) - lw->list.internal_width - x);
6435ec34c4cSmrg    Dimension frame_limited_height= (Dimension)(XtHeight(w) - lw->list.internal_height - y);
6447a84e134Smrg
6457a84e134Smrg    /* Clip the rectangle width and height to the edge of the drawable area */
6467a84e134Smrg    if  (width > frame_limited_width)
6477a84e134Smrg	width = frame_limited_width;
6487a84e134Smrg    if  (height > frame_limited_height)
6497a84e134Smrg	height = frame_limited_height;
6507a84e134Smrg
6517a84e134Smrg    /* Clip the rectangle x and y to the edge of the drawable area */
6527a84e134Smrg    if (x < lw->list.internal_width) {
6535ec34c4cSmrg	width = (Dimension)(width - (lw->list.internal_width - x));
6547a84e134Smrg	x = lw->list.internal_width;
6557a84e134Smrg    }
6567a84e134Smrg    if (y < lw->list.internal_height) {
6575ec34c4cSmrg      height = (Dimension)(height - (lw->list.internal_height - y));
6587a84e134Smrg	y = lw->list.internal_height;
6597a84e134Smrg    }
6607a84e134Smrg
6617a84e134Smrg    if (gc == lw->list.revgc && lw->core.background_pixmap != XtUnspecifiedPixmap)
6627a84e134Smrg	XClearArea(XtDisplay(w), XtWindow(w), x, y, width, height, False);
6637a84e134Smrg    else
6647a84e134Smrg	XFillRectangle(XtDisplay(w), XtWindow(w), gc, x, y, width, height);
6657a84e134Smrg}
6667a84e134Smrg
6677a84e134Smrg
6687a84e134Smrg/* ClipToShadowInteriorAndLongest()
6697a84e134Smrg *
6707a84e134Smrg * Converts the passed gc so that any drawing done with that GC will not
6717a84e134Smrg * write in the empty margin (specified by internal_width/height) (which also
6727a84e134Smrg * prevents erasing the shadow.  It also clips against the value longest.
6737a84e134Smrg * If the user doesn't set longest, this has no effect (as longest is the
6747a84e134Smrg * maximum of all item lengths).  If the user does specify, say, 80 pixel
6757a84e134Smrg * columns, though, this prevents items from overwriting other items.
6767a84e134Smrg */
6777a84e134Smrgstatic void
6787a84e134SmrgClipToShadowInteriorAndLongest(ListWidget lw, GC *gc_p, unsigned int x)
6797a84e134Smrg{
680efbcb2bfSmrg    XRectangle rect = {
681efbcb2bfSmrg	.x = (short)x,
682efbcb2bfSmrg	.y = (short)lw->list.internal_height,
683efbcb2bfSmrg	.height = (unsigned short)
684efbcb2bfSmrg			(XtHeight(lw) - (lw->list.internal_height << 1)),
685efbcb2bfSmrg	.width = (unsigned short)
686efbcb2bfSmrg			(XtWidth(lw) - (unsigned)lw->list.internal_width - x),
687efbcb2bfSmrg    };
6887a84e134Smrg
6897a84e134Smrg    if (rect.width > lw->list.longest)
6905ec34c4cSmrg	rect.width = (unsigned short)lw->list.longest;
6917a84e134Smrg
6927a84e134Smrg    XSetClipRectangles(XtDisplay((Widget)lw), *gc_p, 0, 0, &rect, 1, YXBanded);
6937a84e134Smrg}
6947a84e134Smrg
6957a84e134Smrgstatic void
6967a84e134SmrgPaintItemName(Widget w, int item)
6977a84e134Smrg{
6985ec34c4cSmrg    _Xconst char *str;
6997a84e134Smrg    GC gc;
7007a84e134Smrg    int x, y, str_y;
7017a84e134Smrg    ListWidget lw = (ListWidget)w;
7027a84e134Smrg    XFontSetExtents *ext  = XExtentsOfFontSet(lw->list.fontset);
7037a84e134Smrg
7047a84e134Smrg    if (!XtIsRealized(w) || item > lw->list.nitems)
7057a84e134Smrg      return;
7067a84e134Smrg
7077a84e134Smrg    if (lw->list.vertical_cols) {
7087a84e134Smrg	x = lw->list.col_width * (item / lw->list.nrows)
7097a84e134Smrg	  + lw->list.internal_width;
7107a84e134Smrg	y = lw->list.row_height * (item % lw->list.nrows)
7117a84e134Smrg	  + lw->list.internal_height;
7127a84e134Smrg    }
7137a84e134Smrg    else {
7147a84e134Smrg	x = lw->list.col_width * (item % lw->list.ncols)
7157a84e134Smrg	  + lw->list.internal_width;
7167a84e134Smrg	y = lw->list.row_height * (item / lw->list.ncols)
7177a84e134Smrg	  + lw->list.internal_height;
7187a84e134Smrg    }
7197a84e134Smrg
7207a84e134Smrg    if ( lw->simple.international == True )
7217a84e134Smrg	str_y = y + XawAbs(ext->max_ink_extent.y);
7227a84e134Smrg    else
7237a84e134Smrg	str_y = y + lw->list.font->max_bounds.ascent;
7247a84e134Smrg
7257a84e134Smrg    if (item == lw->list.is_highlighted) {
7267a84e134Smrg	if (item == lw->list.highlight) {
7277a84e134Smrg	    gc = lw->list.revgc;
7287a84e134Smrg	    HighlightBackground(w, x, y, lw->list.normgc);
7297a84e134Smrg	}
7307a84e134Smrg	else {
731421c997bSmrg	    if (XtIsSensitive(w))
7327a84e134Smrg		gc = lw->list.normgc;
7337a84e134Smrg	    else
7347a84e134Smrg		gc = lw->list.graygc;
7357a84e134Smrg	    HighlightBackground(w, x, y, lw->list.revgc);
7367a84e134Smrg	    lw->list.is_highlighted = NO_HIGHLIGHT;
7377a84e134Smrg	}
7387a84e134Smrg    }
7397a84e134Smrg    else {
7407a84e134Smrg	if (item == lw->list.highlight) {
7417a84e134Smrg	    gc = lw->list.revgc;
7427a84e134Smrg	    HighlightBackground(w, x, y, lw->list.normgc);
7437a84e134Smrg	    lw->list.is_highlighted = item;
7447a84e134Smrg	}
7457a84e134Smrg	else {
746421c997bSmrg	    if (XtIsSensitive(w))
7477a84e134Smrg		gc = lw->list.normgc;
7487a84e134Smrg	    else
7497a84e134Smrg		gc = lw->list.graygc;
7507a84e134Smrg	}
7517a84e134Smrg    }
7527a84e134Smrg
7537a84e134Smrg    /* List's overall width contains the same number of inter-column
7547a84e134Smrg       column_space's as columns.  There should thus be a half
7557a84e134Smrg       column_width margin on each side of each column.
7567a84e134Smrg       The row case is symmetric */
7577a84e134Smrg
7587a84e134Smrg    x += lw->list.column_space >> 1;
7597a84e134Smrg    str_y += lw->list.row_space >> 1;
7607a84e134Smrg
7617a84e134Smrg    str =  lw->list.list[item];	/* draw it */
7627a84e134Smrg
7635ec34c4cSmrg    ClipToShadowInteriorAndLongest(lw, &gc, (unsigned)x);
7647a84e134Smrg
7657a84e134Smrg    if (lw->simple.international == True)
7667a84e134Smrg	XmbDrawString(XtDisplay(w), XtWindow(w), lw->list.fontset,
7675ec34c4cSmrg		      gc, x, str_y, str, (int)strlen(str));
7687a84e134Smrg    else
7695ec34c4cSmrg	XDrawString(XtDisplay(w), XtWindow(w), gc, x, str_y, str, (int)strlen(str));
7707a84e134Smrg
7717a84e134Smrg    XSetClipMask(XtDisplay(w), gc, None);
7727a84e134Smrg}
7737a84e134Smrg
774421c997bSmrgstatic void
7757a84e134SmrgXawListRedisplay(Widget w, XEvent *event, Region region)
7767a84e134Smrg{
7777a84e134Smrg    int item;			/* an item to work with */
7787a84e134Smrg    int ul_item, lr_item;	/* corners of items we need to paint */
7797a84e134Smrg    ListWidget lw = (ListWidget)w;
7807a84e134Smrg
7817a84e134Smrg    if (event == NULL) {
7827a84e134Smrg	ul_item = 0;
7837a84e134Smrg	lr_item = lw->list.nrows * lw->list.ncols - 1;
7847a84e134Smrg	XClearWindow(XtDisplay(w), XtWindow(w));
7857a84e134Smrg    }
7867a84e134Smrg    else
7877a84e134Smrg	FindCornerItems(w, event, &ul_item, &lr_item);
7887a84e134Smrg
7897a84e134Smrg    if (Superclass->core_class.expose)
7907a84e134Smrg    (Superclass->core_class.expose)(w, event, region);
791421c997bSmrg
7927a84e134Smrg    for (item = ul_item; item <= lr_item && item < lw->list.nitems; item++)
7937a84e134Smrg	if (ItemInRectangle(w, ul_item, lr_item, item))
7947a84e134Smrg	    PaintItemName(w, item);
7957a84e134Smrg}
7967a84e134Smrg
7977a84e134Smrg/* XawListQueryGeometry()
7987a84e134Smrg *
7997a84e134Smrg * This tells the parent what size we would like to be
8007a84e134Smrg * given certain constraints.
8017a84e134Smrg * w - the widget.
8027a84e134Smrg * intended - what the parent intends to do with us.
8037a84e134Smrg * requested - what we want to happen */
804421c997bSmrgstatic XtGeometryResult
8057a84e134SmrgXawListQueryGeometry(Widget w, XtWidgetGeometry *intended,
8067a84e134Smrg		     XtWidgetGeometry *requested)
8077a84e134Smrg{
8087a84e134Smrg    Dimension new_width, new_height;
8097a84e134Smrg    Bool change, width_req, height_req;
810421c997bSmrg
8117a84e134Smrg    width_req = intended->request_mode & CWWidth;
8127a84e134Smrg    height_req = intended->request_mode & CWHeight;
8137a84e134Smrg
8147a84e134Smrg    if (width_req)
8157a84e134Smrg	new_width = intended->width;
8167a84e134Smrg    else
8177a84e134Smrg	new_width = XtWidth(w);
8187a84e134Smrg
8197a84e134Smrg    if (height_req)
8207a84e134Smrg	new_height = intended->height;
8217a84e134Smrg    else
8227a84e134Smrg	new_height = XtHeight(w);
8237a84e134Smrg
8247a84e134Smrg    requested->request_mode = 0;
825421c997bSmrg
8267a84e134Smrg   /*
8277a84e134Smrg    * We only care about our height and width
8287a84e134Smrg    */
8297a84e134Smrg    if (!width_req && !height_req)
8307a84e134Smrg	return (XtGeometryYes);
831421c997bSmrg
8327a84e134Smrg    change = Layout(w, !width_req, !height_req, &new_width, &new_height);
8337a84e134Smrg
8347a84e134Smrg    requested->request_mode |= CWWidth;
8357a84e134Smrg    requested->width = new_width;
8367a84e134Smrg    requested->request_mode |= CWHeight;
8377a84e134Smrg    requested->height = new_height;
8387a84e134Smrg
8397a84e134Smrg    if (change)
8407a84e134Smrg	return (XtGeometryAlmost);
8417a84e134Smrg
8427a84e134Smrg    return (XtGeometryYes);
8437a84e134Smrg}
8447a84e134Smrg
8457a84e134Smrgstatic void
8467a84e134SmrgXawListResize(Widget w)
8477a84e134Smrg{
8487a84e134Smrg    Dimension width, height;
8497a84e134Smrg
8507a84e134Smrg    width = XtWidth(w);
8517a84e134Smrg    height = XtHeight(w);
8527a84e134Smrg
8537a84e134Smrg    if (Layout(w, False, False, &width, &height))
8547a84e134Smrg	XtAppWarning(XtWidgetToApplicationContext(w),
8557a84e134Smrg		     "List Widget: Size changed when it shouldn't "
8567a84e134Smrg		     "have when resising.");
8577a84e134Smrg}
8587a84e134Smrg
8597a84e134Smrg/* Layout()
8607a84e134Smrg *
8617a84e134Smrg * lays out the item in the list.
8627a84e134Smrg * w - the widget.
8637a84e134Smrg * xfree, yfree - True if we are free to resize the widget in
8647a84e134Smrg *		this direction.
8657a84e134Smrg * width, height- the is the current width and height that we are going
8667a84e134Smrg *		we are going to layout the list widget to,
8677a84e134Smrg *		depending on xfree and yfree of course.
868421c997bSmrg *
8697a84e134Smrg * Return:
8707a84e134Smrg *	True if width or height have been changed */
8717a84e134Smrgstatic Bool
8727a84e134SmrgLayout(Widget w, Bool xfree, Bool yfree, Dimension *width, Dimension *height)
8737a84e134Smrg{
8747a84e134Smrg    ListWidget lw = (ListWidget)w;
8757a84e134Smrg    Bool change = False;
8767a84e134Smrg    unsigned long width2 = 0, height2 = 0;
8777a84e134Smrg
8787a84e134Smrg    /*
8797a84e134Smrg     * If force columns is set then always use number of columns specified
8807a84e134Smrg     * by default_cols
8817a84e134Smrg     */
8827a84e134Smrg    if (lw->list.force_cols) {
8837a84e134Smrg	lw->list.ncols = lw->list.default_cols;
8847a84e134Smrg	if (lw->list.ncols <= 0)
8857a84e134Smrg	    lw->list.ncols = 1;
8867a84e134Smrg	lw->list.nrows = ((lw->list.nitems - 1) / lw->list.ncols) + 1;
8877a84e134Smrg	if (xfree) {
8887a84e134Smrg	    /* this counts the same number
8897a84e134Smrg	       of inter-column column_space 's as columns.  There should thus
8907a84e134Smrg	       be a half column_space margin on each side of each column...*/
8915ec34c4cSmrg	    width2 = (unsigned long)(lw->list.ncols * lw->list.col_width +
8925ec34c4cSmrg		     (lw->list.internal_width << 1));
8937a84e134Smrg	    change = True;
8947a84e134Smrg	}
8957a84e134Smrg	if (yfree) {
8965ec34c4cSmrg	    height2 = (unsigned long)(lw->list.nrows * lw->list.row_height +
8975ec34c4cSmrg		      (lw->list.internal_height << 1));
8987a84e134Smrg	    change = True;
8997a84e134Smrg	}
9007a84e134Smrg    }
9017a84e134Smrg
9027a84e134Smrg    /*
9037a84e134Smrg     * If both width and height are free to change the use default_cols
9047a84e134Smrg     * to determine the number columns and set new width and height to
9057a84e134Smrg     * just fit the window
9067a84e134Smrg     */
9077a84e134Smrg    else if (xfree && yfree) {
9087a84e134Smrg	lw->list.ncols = lw->list.default_cols;
9097a84e134Smrg	if (lw->list.ncols <= 0) {
9107a84e134Smrg	    int wid = (int)XtWidth(lw) - (int)(lw->list.internal_width << 1)
9117a84e134Smrg	      + (int)lw->list.column_space;
9127a84e134Smrg
9137a84e134Smrg	    if (wid <= 0 || lw->list.col_width <= 0
9147a84e134Smrg		|| (lw->list.ncols = wid / lw->list.col_width) <= 0)
9157a84e134Smrg		lw->list.ncols = 1;
9167a84e134Smrg	}
9175ec34c4cSmrg	width2 = (unsigned long)((lw->list.ncols * lw->list.col_width)
9185ec34c4cSmrg		  + (lw->list.internal_width << 1));
9195ec34c4cSmrg	height2 = (unsigned long)((lw->list.nrows * lw->list.row_height)
9205ec34c4cSmrg		   + (lw->list.internal_height << 1));
9217a84e134Smrg	change = True;
9227a84e134Smrg    }
9237a84e134Smrg
9247a84e134Smrg    /*
9257a84e134Smrg     * If the width is fixed then use it to determine the number of columns.
9267a84e134Smrg     * If the height is free to move (width still fixed) then resize the height
9277a84e134Smrg     * of the widget to fit the current list exactly
9287a84e134Smrg     */
9297a84e134Smrg    else if (!xfree) {
9307a84e134Smrg	lw->list.ncols = ((int)(*width - (lw->list.internal_width << 1))
9317a84e134Smrg			  / (int)lw->list.col_width);
9327a84e134Smrg	if (lw->list.ncols <= 0)
9337a84e134Smrg	    lw->list.ncols = 1;
9347a84e134Smrg	lw->list.nrows = ((lw->list.nitems - 1) / lw->list.ncols) + 1;
9357a84e134Smrg	if (yfree) {
9365ec34c4cSmrg	    height2 = (unsigned long)((lw->list.nrows * lw->list.row_height) +
9375ec34c4cSmrg		      (lw->list.internal_height << 1));
9387a84e134Smrg	    change = True;
9397a84e134Smrg	}
9407a84e134Smrg    }
9417a84e134Smrg
9427a84e134Smrg    /*
9437a84e134Smrg     * The last case is xfree and !yfree we use the height to determine
9447a84e134Smrg     * the number of rows and then set the width to just fit the resulting
9457a84e134Smrg     * number of columns
9467a84e134Smrg     */
9477a84e134Smrg    else if (!yfree) {
9487a84e134Smrg	lw->list.nrows = ((int)(*height - (lw->list.internal_height << 1))
9497a84e134Smrg			  / (int)lw->list.row_height);
9507a84e134Smrg	if (lw->list.nrows <= 0)
9517a84e134Smrg	    lw->list.nrows = 1;
9527a84e134Smrg	lw->list.ncols = ((lw->list.nitems - 1) / lw->list.nrows) + 1;
9535ec34c4cSmrg	width2 = (unsigned long)((lw->list.ncols * lw->list.col_width) +
9545ec34c4cSmrg		 (lw->list.internal_width << 1));
9557a84e134Smrg	change = True;
9567a84e134Smrg    }
9577a84e134Smrg
9587a84e134Smrg    if (!lw->list.force_cols && lw->list.nrows) {
9597a84e134Smrg	/*CONSTCOND*/
9607a84e134Smrg	while (1) {
9617a84e134Smrg	    lw->list.nrows = ((lw->list.nitems - 1) / lw->list.ncols) + 1;
9625ec34c4cSmrg	    width2 = (unsigned long)((lw->list.ncols * lw->list.col_width) +
9635ec34c4cSmrg		     (lw->list.internal_width << 1));
9645ec34c4cSmrg	    height2 = (unsigned long)((lw->list.nrows * lw->list.row_height) +
9655ec34c4cSmrg		      (lw->list.internal_height << 1));
9667a84e134Smrg	    if (width2 >= MaxSize && height2 >= MaxSize)
9677a84e134Smrg		break;
9687a84e134Smrg	    if (height2 > MaxSize)
9697a84e134Smrg		++lw->list.ncols;
9707a84e134Smrg	    else if (width2 > MaxSize && lw->list.ncols > 1)
9717a84e134Smrg		--lw->list.ncols;
9727a84e134Smrg	    else
9737a84e134Smrg		break;
9747a84e134Smrg	}
9757a84e134Smrg    }
9767a84e134Smrg    if (width2)
9775ec34c4cSmrg	*width = (Dimension)width2;
9787a84e134Smrg    if (height2)
9795ec34c4cSmrg	*height = (Dimension)height2;
9807a84e134Smrg
9817a84e134Smrg    return (change);
9827a84e134Smrg}
9837a84e134Smrg
9847a84e134Smrg/* Notify() - Action
9857a84e134Smrg *
9867a84e134Smrg * Notifies the user that a button has been pressed, and
9877a84e134Smrg * calls the callback; if the XtNpasteBuffer resource is true
9887a84e134Smrg * then the name of the item is also put in CUT_BUFFER0 */
9897a84e134Smrg/*ARGSUSED*/
9907a84e134Smrgstatic void
9915ec34c4cSmrgNotify(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
9927a84e134Smrg{
9937a84e134Smrg    ListWidget lw = (ListWidget)w;
9947a84e134Smrg    int item, item_len;
9957a84e134Smrg
9967a84e134Smrg    /*
9977a84e134Smrg     * Find item and if out of range then unhighlight and return
998421c997bSmrg     *
9997a84e134Smrg     * If the current item is unhighlighted then the user has aborted the
10007a84e134Smrg     * notify, so unhighlight and return
10017a84e134Smrg     */
10027a84e134Smrg    if ((CvtToItem(w, event->xbutton.x, event->xbutton.y, &item) == OUT_OF_RANGE)
10037a84e134Smrg	|| lw->list.highlight != item) {
10047a84e134Smrg#ifndef OLDXAW
10057a84e134Smrg	if (!lw->list.show_current || lw->list.selected == NO_HIGHLIGHT)
10067a84e134Smrg	    XawListUnhighlight(w);
10077a84e134Smrg	else
10087a84e134Smrg	    XawListHighlight(w, lw->list.selected);
10097a84e134Smrg#else
10107a84e134Smrg	XawListUnhighlight(w);
10117a84e134Smrg#endif
10127a84e134Smrg	return;
10137a84e134Smrg    }
10147a84e134Smrg
10155ec34c4cSmrg    item_len = (int)strlen(lw->list.list[item]);
10167a84e134Smrg
10177a84e134Smrg    if (lw->list.paste)		/* if XtNpasteBuffer set then paste it */
10187a84e134Smrg	XStoreBytes(XtDisplay(w), lw->list.list[item], item_len);
10197a84e134Smrg
10207a84e134Smrg#ifndef OLDXAW
10217a84e134Smrg    lw->list.selected = item;
10227a84e134Smrg#endif
10237a84e134Smrg    /*
10247a84e134Smrg     * Call Callback function
10257a84e134Smrg     */
1026efbcb2bfSmrg    {
1027efbcb2bfSmrg	XawListReturnStruct ret_value = {
1028efbcb2bfSmrg	    .string = lw->list.list[item],
1029efbcb2bfSmrg	    .list_index = item
1030efbcb2bfSmrg	};
1031421c997bSmrg
1032efbcb2bfSmrg	XtCallCallbacks(w, XtNcallback, (XtPointer)&ret_value);
1033efbcb2bfSmrg    }
10347a84e134Smrg}
10357a84e134Smrg
10367a84e134Smrg/* Unset() - Action
10377a84e134Smrg *
10387a84e134Smrg * unhighlights the current element */
10397a84e134Smrg/*ARGSUSED*/
10407a84e134Smrgstatic void
10415ec34c4cSmrgUnset(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
10427a84e134Smrg{
10437a84e134Smrg    XawListUnhighlight(w);
10447a84e134Smrg}
10457a84e134Smrg
10467a84e134Smrg/* Set() - Action
10477a84e134Smrg *
10487a84e134Smrg * Highlights the current element */
10497a84e134Smrg/*ARGSUSED*/
10507a84e134Smrgstatic void
10515ec34c4cSmrgSet(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
10527a84e134Smrg{
10537a84e134Smrg    int item;
10547a84e134Smrg    ListWidget lw = (ListWidget)w;
10557a84e134Smrg
10567a84e134Smrg#ifndef OLDXAW
10577a84e134Smrg    lw->list.selected = lw->list.highlight;
10587a84e134Smrg#endif
10597a84e134Smrg    if (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item) == OUT_OF_RANGE)
10607a84e134Smrg	XawListUnhighlight(w);			/* Unhighlight current item */
10617a84e134Smrg    else if (lw->list.is_highlighted != item)	/* If this item is not */
10627a84e134Smrg	XawListHighlight(w, item);		/* highlighted then do it */
10637a84e134Smrg}
10647a84e134Smrg
10657a84e134Smrg/*
10667a84e134Smrg * Set specified arguments into widget
10677a84e134Smrg */
10687a84e134Smrg/*ARGSUSED*/
1069421c997bSmrgstatic Boolean
10707a84e134SmrgXawListSetValues(Widget current, Widget request, Widget cnew,
10715ec34c4cSmrg		 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
10727a84e134Smrg{
10737a84e134Smrg    ListWidget cl = (ListWidget)current;
10747a84e134Smrg    ListWidget rl = (ListWidget)request;
10757a84e134Smrg    ListWidget nl = (ListWidget)cnew;
10767a84e134Smrg    Bool redraw = False;
10777a84e134Smrg    XFontSetExtents *ext = XExtentsOfFontSet(nl->list.fontset);
10787a84e134Smrg
10797a84e134Smrg    /* If the request height/width is different, lock it.  Unless its 0. If
10807a84e134Smrg       neither new nor 0, leave it as it was.  Not in R5 */
10817a84e134Smrg    if (XtWidth(nl) != XtWidth(cl))
10827a84e134Smrg	nl->list.freedoms |= WidthLock;
10837a84e134Smrg    if (XtWidth(nl) == 0)
10847a84e134Smrg	nl->list.freedoms &= ~WidthLock;
10857a84e134Smrg
10867a84e134Smrg    if (XtHeight(nl) != XtHeight(cl))
10877a84e134Smrg	nl->list.freedoms |= HeightLock;
10887a84e134Smrg    if (XtHeight(nl) == 0)
10897a84e134Smrg	nl->list.freedoms &= ~HeightLock;
10907a84e134Smrg
10917a84e134Smrg    if (nl->list.longest != cl->list.longest)
10927a84e134Smrg	nl->list.freedoms |= LongestLock;
10937a84e134Smrg    if (nl->list.longest == 0)
10947a84e134Smrg	nl->list.freedoms &= ~LongestLock;
10957a84e134Smrg
10967a84e134Smrg    if (cl->list.foreground != nl->list.foreground ||
10977a84e134Smrg	cl->core.background_pixel != nl->core.background_pixel ||
10987a84e134Smrg	cl->list.font != nl->list.font) {
10997a84e134Smrg	XGCValues values;
11007a84e134Smrg
11017a84e134Smrg	XGetGCValues(XtDisplay(current), cl->list.graygc, GCTile, &values);
11027a84e134Smrg	XmuReleaseStippledPixmap(XtScreen(current), values.tile);
11037a84e134Smrg	XtReleaseGC(current, cl->list.graygc);
11047a84e134Smrg	XtReleaseGC(current, cl->list.revgc);
11057a84e134Smrg	XtReleaseGC(current, cl->list.normgc);
11067a84e134Smrg	GetGCs(cnew);
11077a84e134Smrg	redraw = True;
11087a84e134Smrg    }
11097a84e134Smrg
11107a84e134Smrg    if (cl->list.font != nl->list.font && cl->simple.international == False)
11117a84e134Smrg	nl->list.row_height = nl->list.font->max_bounds.ascent
11127a84e134Smrg			    + nl->list.font->max_bounds.descent
11137a84e134Smrg			    + nl->list.row_space;
11147a84e134Smrg    else if (cl->list.fontset != nl->list.fontset
11157a84e134Smrg	&& cl->simple.international == True)
11167a84e134Smrg	nl->list.row_height = ext->max_ink_extent.height + nl->list.row_space;
11177a84e134Smrg
11187a84e134Smrg    /* ...If the above two font(set) change checkers above both failed, check
11197a84e134Smrg       if row_space was altered.  If one of the above passed, row_height will
11207a84e134Smrg       already have been re-calculated */
11217a84e134Smrg    else if (cl->list.row_space != nl->list.row_space) {
11227a84e134Smrg	if (cl->simple.international == True)
11237a84e134Smrg	    nl->list.row_height = ext->max_ink_extent.height + nl->list.row_space;
11247a84e134Smrg	else
11257a84e134Smrg	    nl->list.row_height = nl->list.font->max_bounds.ascent
11267a84e134Smrg				+ nl->list.font->max_bounds.descent
11277a84e134Smrg				+ nl->list.row_space;
11287a84e134Smrg    }
11297a84e134Smrg
11307a84e134Smrg    if (XtWidth(cl) != XtWidth(nl) || XtHeight(cl) != XtHeight(nl)
11317a84e134Smrg	|| cl->list.internal_width != nl->list.internal_width
11327a84e134Smrg	|| cl->list.internal_height != nl->list.internal_height
11337a84e134Smrg	|| cl->list.column_space != nl->list.column_space
11347a84e134Smrg	|| cl->list.row_space != nl->list.row_space
11357a84e134Smrg	|| cl->list.default_cols != nl->list.default_cols
11367a84e134Smrg	|| (cl->list.force_cols != nl->list.force_cols
11377a84e134Smrg	    && rl->list.force_cols != nl->list.ncols)
11387a84e134Smrg	|| cl->list.vertical_cols != nl->list.vertical_cols
11397a84e134Smrg	|| cl->list.longest != nl->list.longest
11407a84e134Smrg	|| cl->list.nitems != nl->list.nitems
11417a84e134Smrg	|| cl->list.font != nl->list.font
11427a84e134Smrg	/* Equiv. fontsets might have different values, but the same fonts,
11437a84e134Smrg	   so the next comparison is sloppy but not dangerous  */
11447a84e134Smrg	|| cl->list.fontset != nl->list.fontset
11457a84e134Smrg	|| cl->list.list != nl->list.list) {
11467a84e134Smrg	CalculatedValues(cnew);
11477a84e134Smrg	Layout(cnew, WidthFree(nl), HeightFree(nl),
11487a84e134Smrg	       &nl->core.width, &nl->core.height);
11497a84e134Smrg	redraw = True;
11507a84e134Smrg    }
11517a84e134Smrg
11527a84e134Smrg    if (cl->list.list != nl->list.list || cl->list.nitems != nl->list.nitems)
11537a84e134Smrg	nl->list.is_highlighted = nl->list.highlight = NO_HIGHLIGHT;
11547a84e134Smrg
11557a84e134Smrg    if (cl->core.sensitive != nl->core.sensitive
11567a84e134Smrg	|| cl->core.ancestor_sensitive != nl->core.ancestor_sensitive) {
11577a84e134Smrg	nl->list.highlight = NO_HIGHLIGHT;
11587a84e134Smrg	redraw = True;
11597a84e134Smrg    }
1160421c997bSmrg
11615ec34c4cSmrg    return (Boolean)(redraw);
11627a84e134Smrg}
11637a84e134Smrg
11647a84e134Smrgstatic void
11657a84e134SmrgXawListDestroy(Widget w)
11667a84e134Smrg{
11677a84e134Smrg    ListWidget lw = (ListWidget)w;
11687a84e134Smrg    XGCValues values;
1169421c997bSmrg
11707a84e134Smrg    XGetGCValues(XtDisplay(w), lw->list.graygc, GCTile, &values);
11717a84e134Smrg    XmuReleaseStippledPixmap(XtScreen(w), values.tile);
11727a84e134Smrg    XtReleaseGC(w, lw->list.graygc);
11737a84e134Smrg    XtReleaseGC(w, lw->list.revgc);
11747a84e134Smrg    XtReleaseGC(w, lw->list.normgc);
11757a84e134Smrg}
11767a84e134Smrg
11777a84e134Smrg/*
11787a84e134Smrg * Function:
11797a84e134Smrg *	XawListChange
11807a84e134Smrg *
11817a84e134Smrg * Parameters:
11827a84e134Smrg *	w - list widget
11837a84e134Smrg *	list - new list
11847a84e134Smrg *	nitems - number of items in the list
11857a84e134Smrg *	longest - length (in Pixels) of the longest element in the list
11867a84e134Smrg *	resize - if True the the list widget will try to resize itself
11877a84e134Smrg *
11887a84e134Smrg * Description:
11897a84e134Smrg *	Changes the list being used and shown.
11907a84e134Smrg *
11917a84e134Smrg * Note:
11927a84e134Smrg *	If nitems of longest are <= 0 then they will be calculated
11937a84e134Smrg *	If nitems is <= 0 then the list needs to be NULL terminated
11947a84e134Smrg */
11957a84e134Smrgvoid
1196efbcb2bfSmrgXawListChange(Widget w, String *list, int nitems, int longest,
11977a84e134Smrg#if NeedWidePrototypes
11987a84e134Smrg	int resize_it
11997a84e134Smrg#else
12007a84e134Smrg	Boolean resize_it
12017a84e134Smrg#endif
12027a84e134Smrg)
12037a84e134Smrg{
12047a84e134Smrg    ListWidget lw = (ListWidget)w;
12057a84e134Smrg    Dimension new_width = XtWidth(w);
12067a84e134Smrg    Dimension new_height = XtHeight(w);
12077a84e134Smrg
12087a84e134Smrg    lw->list.list = list;
12097a84e134Smrg
12107a84e134Smrg    if (nitems <= 0)
12117a84e134Smrg	nitems = 0;
12127a84e134Smrg    lw->list.nitems = nitems;
12137a84e134Smrg    if (longest <= 0)
12147a84e134Smrg	longest = 0;
12157a84e134Smrg
12167a84e134Smrg    /* If the user passes 0 meaning "calculate it", it must be free */
12177a84e134Smrg    if (longest != 0)
12187a84e134Smrg	lw->list.freedoms |= LongestLock;
12197a84e134Smrg    else
12207a84e134Smrg	lw->list.freedoms &= ~LongestLock;
12217a84e134Smrg
12227a84e134Smrg    if (resize_it)
12237a84e134Smrg	lw->list.freedoms &= ~WidthLock & ~HeightLock;
12247a84e134Smrg
12257a84e134Smrg    lw->list.longest = longest;
12267a84e134Smrg
12277a84e134Smrg    CalculatedValues(w);
12287a84e134Smrg
12297a84e134Smrg    if (Layout(w, WidthFree(w), HeightFree(w), &new_width, &new_height))
12307a84e134Smrg	ChangeSize(w, new_width, new_height);
12317a84e134Smrg
12327a84e134Smrg    lw->list.is_highlighted = lw->list.highlight = NO_HIGHLIGHT;
12337a84e134Smrg    if (XtIsRealized(w))
12347a84e134Smrg	XawListRedisplay(w, NULL, NULL);
12357a84e134Smrg}
12367a84e134Smrg
12377a84e134Smrgvoid
12387a84e134SmrgXawListUnhighlight(Widget w)
12397a84e134Smrg{
12407a84e134Smrg    ListWidget lw = (ListWidget)w;
12417a84e134Smrg
12427a84e134Smrg    lw->list.highlight = NO_HIGHLIGHT;
12437a84e134Smrg    if (lw->list.is_highlighted != NO_HIGHLIGHT)
12447a84e134Smrg    PaintItemName(w, lw->list.is_highlighted);
12457a84e134Smrg}
12467a84e134Smrg
12477a84e134Smrgvoid
12487a84e134SmrgXawListHighlight(Widget w, int item)
12497a84e134Smrg{
12507a84e134Smrg    ListWidget lw = (ListWidget)w;
1251421c997bSmrg
12527a84e134Smrg    if (XtIsSensitive(w)) {
12537a84e134Smrg	lw->list.highlight = item;
12547a84e134Smrg	if (lw->list.is_highlighted != NO_HIGHLIGHT)
12557a84e134Smrg	PaintItemName(w, lw->list.is_highlighted);
12567a84e134Smrg	PaintItemName(w, item);
12577a84e134Smrg    }
12587a84e134Smrg}
12597a84e134Smrg
12607a84e134Smrg/*
12617a84e134Smrg * Function:
12627a84e134Smrg *	XawListShowCurrent
12637a84e134Smrg *
12647a84e134Smrg * Parameters:
12657a84e134Smrg *	w - list widget
12667a84e134Smrg *
12677a84e134Smrg * Returns:
12687a84e134Smrg *	Info about the currently highlighted object
12697a84e134Smrg */
12707a84e134SmrgXawListReturnStruct *
12717a84e134SmrgXawListShowCurrent(Widget w)
12727a84e134Smrg{
12737a84e134Smrg    ListWidget lw = (ListWidget)w;
12747a84e134Smrg    XawListReturnStruct *ret_val;
12757a84e134Smrg
12767a84e134Smrg    ret_val = (XawListReturnStruct *)XtMalloc(sizeof(XawListReturnStruct));
1277421c997bSmrg
12787a84e134Smrg    ret_val->list_index = lw->list.highlight;
12797a84e134Smrg    if (ret_val->list_index == XAW_LIST_NONE)
12807a84e134Smrg	ret_val->string = "";
12817a84e134Smrg    else
12827a84e134Smrg	ret_val->string = lw->list.list[ret_val->list_index];
12837a84e134Smrg
12847a84e134Smrg    return (ret_val);
12857a84e134Smrg}
1286