List.c revision 5b16253f
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 */
3037a84e134Smrg  },
3047a84e134Smrg  /* simple */
3057a84e134Smrg  {
3067a84e134Smrg    XtInheritChangeSensitive,		/* change_sensitive */
3077a84e134Smrg  },
3087a84e134Smrg  /* list */
3097a84e134Smrg  {
3107a84e134Smrg    NULL,				/* extension */
3117a84e134Smrg  },
3127a84e134Smrg};
3137a84e134Smrg
3147a84e134SmrgWidgetClass listWidgetClass = (WidgetClass)&listClassRec;
3157a84e134Smrg
3167a84e134Smrg/*
3177a84e134Smrg * Implementation
3187a84e134Smrg */
3197a84e134Smrgstatic void
3207a84e134SmrgGetGCs(Widget w)
3217a84e134Smrg{
3227a84e134Smrg    XGCValues	values;
3237a84e134Smrg    ListWidget lw = (ListWidget)w;
3247a84e134Smrg
3257a84e134Smrg    values.foreground	= lw->list.foreground;
3267a84e134Smrg    values.font		= lw->list.font->fid;
3277a84e134Smrg
3287a84e134Smrg    if (lw->simple.international == True)
3297a84e134Smrg	lw->list.normgc = XtAllocateGC(w, 0, GCForeground, &values, GCFont, 0);
3307a84e134Smrg    else
3317a84e134Smrg	lw->list.normgc = XtGetGC(w, GCForeground | GCFont, &values);
3327a84e134Smrg
3337a84e134Smrg    values.foreground	= lw->core.background_pixel;
3347a84e134Smrg
3357a84e134Smrg    if (lw->simple.international == True)
3367a84e134Smrg	lw->list.revgc = XtAllocateGC(w, 0, GCForeground, &values, GCFont, 0);
3377a84e134Smrg    else
3387a84e134Smrg	lw->list.revgc = XtGetGC(w, GCForeground | GCFont, &values);
3397a84e134Smrg
340421c997bSmrg    values.tile       = XmuCreateStippledPixmap(XtScreen(w),
3417a84e134Smrg						lw->list.foreground,
3427a84e134Smrg						lw->core.background_pixel,
3437a84e134Smrg						lw->core.depth);
3447a84e134Smrg    values.fill_style = FillTiled;
3457a84e134Smrg
3467a84e134Smrg    if (lw->simple.international == True)
3477a84e134Smrg	lw->list.graygc = XtAllocateGC(w, 0, GCTile | GCFillStyle,
3487a84e134Smrg				       &values, GCFont, 0);
3497a84e134Smrg    else
3507a84e134Smrg	lw->list.graygc = XtGetGC(w, GCFont | GCTile | GCFillStyle, &values);
3517a84e134Smrg}
3527a84e134Smrg
3537a84e134Smrgstatic void
3547a84e134SmrgCalculatedValues(Widget w)
3557a84e134Smrg{
3567a84e134Smrg    int i, len;
3577a84e134Smrg    ListWidget lw = (ListWidget)w;
3587a84e134Smrg
3597a84e134Smrg    /* If list is NULL then the list will just be the name of the widget */
3607a84e134Smrg    if (lw->list.list == NULL) {
3617a84e134Smrg	lw->list.list = &lw->core.name;
3627a84e134Smrg	lw->list.nitems = 1;
3637a84e134Smrg    }
3647a84e134Smrg
3657a84e134Smrg    /* Get number of items */
3667a84e134Smrg    if (lw->list.nitems == 0)
3677a84e134Smrg	for (; lw->list.list[lw->list.nitems] != NULL ; lw->list.nitems++)
3687a84e134Smrg	    ;
3697a84e134Smrg
3707a84e134Smrg    /* Get column width */
3717a84e134Smrg    if (LongestFree(lw)) {
3727a84e134Smrg	lw->list.longest = 0; /* so it will accumulate real longest below */
3737a84e134Smrg
3747a84e134Smrg	for (i = 0 ; i < lw->list.nitems; i++) {
3757a84e134Smrg	    if (lw->simple.international == True)
3767a84e134Smrg		len = XmbTextEscapement(lw->list.fontset, lw->list.list[i],
3775ec34c4cSmrg					(int)strlen(lw->list.list[i]));
3787a84e134Smrg	    else
3797a84e134Smrg		len = XTextWidth(lw->list.font, lw->list.list[i],
3805ec34c4cSmrg				 (int)strlen(lw->list.list[i]));
3817a84e134Smrg	    if (len > lw->list.longest)
3827a84e134Smrg		lw->list.longest = len;
3837a84e134Smrg	}
3847a84e134Smrg    }
3857a84e134Smrg
3867a84e134Smrg    lw->list.col_width = lw->list.longest + lw->list.column_space;
3877a84e134Smrg}
3887a84e134Smrg
3897a84e134Smrg/*
3907a84e134Smrg * Function:
3917a84e134Smrg *	ResetList
3927a84e134Smrg *
3937a84e134Smrg * Parameters:
3947a84e134Smrg *	w	- list widget
3957a84e134Smrg *	changex - allow the height or width to change?
3967a84e134Smrg *	changey - ""
3977a84e134Smrg *
3987a84e134Smrg * Description:
3997a84e134Smrg *	Resets the new list when important things change.
4007a84e134Smrg *
4017a84e134Smrg * Returns:
4027a84e134Smrg *	True if width or height have been changed
4037a84e134Smrg */
4047a84e134Smrgstatic void
4057a84e134SmrgResetList(Widget w, Bool changex, Bool changey)
4067a84e134Smrg{
4077a84e134Smrg    Dimension width = XtWidth(w);
4087a84e134Smrg    Dimension height = XtHeight(w);
4097a84e134Smrg
4107a84e134Smrg    CalculatedValues(w);
4117a84e134Smrg
4127a84e134Smrg    if (Layout(w, changex, changey, &width, &height)) {
4137a84e134Smrg	if (XtIsComposite(XtParent(w)))
4147a84e134Smrg	    ChangeSize(w, width, height);
4157a84e134Smrg	else {
4167a84e134Smrg	    XtWidth(w) = width;
4177a84e134Smrg	    XtHeight(w) = height;
4187a84e134Smrg	}
4197a84e134Smrg    }
4207a84e134Smrg}
4217a84e134Smrg
4227a84e134Smrg/*
4237a84e134Smrg * Function:
4247a84e134Smrg *	ChangeSize
4257a84e134Smrg *
4267a84e134Smrg * Parameters:
4277a84e134Smrg *	w - widget to try change the size of
4287a84e134Smrg *
4297a84e134Smrg * Description:
4307a84e134Smrg *	Laysout the widget.
4317a84e134Smrg */
4327a84e134Smrgstatic void
4337a84e134SmrgChangeSize(Widget w, unsigned int width, unsigned int height)
4347a84e134Smrg{
4357a84e134Smrg    XtWidgetGeometry request, reply;
4367a84e134Smrg
4377a84e134Smrg    request.request_mode = CWWidth | CWHeight;
4385ec34c4cSmrg    request.width = (Dimension)width;
4395ec34c4cSmrg    request.height = (Dimension)height;
4407a84e134Smrg
4417a84e134Smrg    switch (XtMakeGeometryRequest(w, &request, &reply)) {
4427a84e134Smrg	case XtGeometryYes:
4437a84e134Smrg	case XtGeometryNo:
4447a84e134Smrg	    break;
4457a84e134Smrg	case XtGeometryAlmost:
4467a84e134Smrg	    Layout(w, request.height != reply.height,
4477a84e134Smrg		   request.width != reply.width, &reply.width, &reply.height);
4487a84e134Smrg	    request = reply;
4497a84e134Smrg	    switch (XtMakeGeometryRequest(w, &request, &reply)) {
4507a84e134Smrg		case XtGeometryYes:
4517a84e134Smrg		case XtGeometryNo:
4527a84e134Smrg		    break;
4537a84e134Smrg		case XtGeometryAlmost:
4547a84e134Smrg		    request = reply;
4557a84e134Smrg		    Layout(w, False, False, &request.width, &request.height);
4567a84e134Smrg		    request.request_mode = CWWidth | CWHeight;
4577a84e134Smrg		    XtMakeGeometryRequest(w, &request, &reply);
4585b16253fSmrg		    /*FALLTHROUGH*/
4597a84e134Smrg		default:
4607a84e134Smrg		    break;
4617a84e134Smrg	}
4625b16253fSmrg	/*FALLTHROUGH*/
4637a84e134Smrg	default:
4647a84e134Smrg	    break;
4657a84e134Smrg    }
4667a84e134Smrg}
4677a84e134Smrg
4687a84e134Smrg/*ARGSUSED*/
469421c997bSmrgstatic void
4705ec34c4cSmrgXawListInitialize(Widget temp1 _X_UNUSED, Widget cnew, ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
4717a84e134Smrg{
4727a84e134Smrg    ListWidget lw = (ListWidget)cnew;
4737a84e134Smrg
4747a84e134Smrg    if (!lw->list.font) XtError("Aborting: no font found\n");
475421c997bSmrg    if (lw->simple.international && !lw->list.fontset)
4767a84e134Smrg	XtError("Aborting: no fontset found\n");
477421c997bSmrg
4787a84e134Smrg    /*
4797a84e134Smrg     * Initialize all private resources
4807a84e134Smrg     */
4817a84e134Smrg    /* record for posterity if we are free */
4827a84e134Smrg    lw->list.freedoms = ((XtWidth(lw) != 0) * WidthLock +
4837a84e134Smrg			 (XtHeight(lw) != 0) * HeightLock +
4847a84e134Smrg			 (lw->list.longest != 0) * LongestLock);
4857a84e134Smrg
4867a84e134Smrg    GetGCs(cnew);
4877a84e134Smrg
4887a84e134Smrg    /* Set row height, based on font or fontset */
4897a84e134Smrg    if (lw->simple.international == True)
4907a84e134Smrg	lw->list.row_height =
4917a84e134Smrg		XExtentsOfFontSet(lw->list.fontset)->max_ink_extent.height +
4927a84e134Smrg				  lw->list.row_space;
4937a84e134Smrg    else
4947a84e134Smrg	lw->list.row_height = lw->list.font->max_bounds.ascent +
4957a84e134Smrg			      lw->list.font->max_bounds.descent +
4967a84e134Smrg			      lw->list.row_space;
4977a84e134Smrg
4987a84e134Smrg    ResetList(cnew, WidthFree(lw), HeightFree(lw));
4997a84e134Smrg
5007a84e134Smrg    lw->list.highlight = lw->list.is_highlighted = NO_HIGHLIGHT;
5017a84e134Smrg}
5027a84e134Smrg
5037a84e134Smrg/*
5047a84e134Smrg * Function:
5057a84e134Smrg *	CvtToItem
5067a84e134Smrg *
5077a84e134Smrg * Parameters:
5087a84e134Smrg *	w    - list widget
5097a84e134Smrg *	xloc - x location
5107a84e134Smrg *	yloc - y location
5117a84e134Smrg *
5127a84e134Smrg * Description:
5137a84e134Smrg *	Converts Xcoord to item number of item containing that point.
5147a84e134Smrg *
5157a84e134Smrg * Returns:
5167a84e134Smrg *	Item number
5177a84e134Smrg */
5187a84e134Smrgstatic int
5197a84e134SmrgCvtToItem(Widget w, int xloc, int yloc, int *item)
5207a84e134Smrg{
5217a84e134Smrg    int one, another;
5227a84e134Smrg    ListWidget lw = (ListWidget)w;
5237a84e134Smrg    int ret_val = OKAY;
5247a84e134Smrg
5257a84e134Smrg    if (lw->list.vertical_cols) {
5267a84e134Smrg	one = lw->list.nrows * ((xloc - (int)lw->list.internal_width)
5277a84e134Smrg			        / lw->list.col_width);
5287a84e134Smrg	another = (yloc - (int)lw->list.internal_height) / lw->list.row_height;
5297a84e134Smrg	/* If out of range, return minimum possible value */
5307a84e134Smrg	if (another >= lw->list.nrows) {
5317a84e134Smrg	    another = lw->list.nrows - 1;
5327a84e134Smrg	    ret_val = OUT_OF_RANGE;
5337a84e134Smrg	}
5347a84e134Smrg    }
5357a84e134Smrg    else {
5367a84e134Smrg	one = (lw->list.ncols * ((yloc - (int)lw->list.internal_height)
5377a84e134Smrg				 / lw->list.row_height));
5387a84e134Smrg	/* If in right margin handle things right */
5397a84e134Smrg	another = (xloc - (int)lw->list.internal_width) / lw->list.col_width;
5407a84e134Smrg	if (another >= lw->list.ncols) {
541421c997bSmrg	    another = lw->list.ncols - 1;
5427a84e134Smrg	    ret_val = OUT_OF_RANGE;
5437a84e134Smrg	}
544421c997bSmrg    }
5457a84e134Smrg    if (xloc < 0 || yloc < 0)
5467a84e134Smrg	ret_val = OUT_OF_RANGE;
5477a84e134Smrg    if (one < 0)
5487a84e134Smrg	one = 0;
5497a84e134Smrg    if (another < 0)
5507a84e134Smrg	another = 0;
5517a84e134Smrg    *item = one + another;
5527a84e134Smrg    if (*item >= lw->list.nitems)
5537a84e134Smrg	return (OUT_OF_RANGE);
5547a84e134Smrg
5557a84e134Smrg  return (ret_val);
5567a84e134Smrg}
5577a84e134Smrg
5587a84e134Smrg/*
5597a84e134Smrg * Function:
5607a84e134Smrg *	FindCornerItems
5617a84e134Smrg *
5627a84e134Smrg * Arguments:
5637a84e134Smrg *	w      - list widget
5647a84e134Smrg *	event  - event structure that has the rectangle it it
5657a84e134Smrg *	ul_ret - the corners (return)
5667a84e134Smrg *	lr_ret - ""
5677a84e134Smrg *
5687a84e134Smrg * Description:
5697a84e134Smrg *	Find the corners of the rectangle in item space.
5707a84e134Smrg */
5717a84e134Smrgstatic void
5727a84e134SmrgFindCornerItems(Widget w, XEvent *event, int *ul_ret, int *lr_ret)
5737a84e134Smrg{
5747a84e134Smrg    int xloc, yloc;
5757a84e134Smrg
5767a84e134Smrg    xloc = event->xexpose.x;
5777a84e134Smrg    yloc = event->xexpose.y;
5787a84e134Smrg    CvtToItem(w, xloc, yloc, ul_ret);
5797a84e134Smrg    xloc += event->xexpose.width;
5807a84e134Smrg    yloc += event->xexpose.height;
5817a84e134Smrg    CvtToItem(w, xloc, yloc, lr_ret);
5827a84e134Smrg}
5837a84e134Smrg
5847a84e134Smrg/*
5857a84e134Smrg * Function:
5867a84e134Smrg *	ItemInRectangle
5877a84e134Smrg *
5887a84e134Smrg * Parameters:
5897a84e134Smrg *	w    - list widget
5907a84e134Smrg *	ul   - corners of the rectangle in item space
5917a84e134Smrg *	lr   - ""
5927a84e134Smrg *	item - item to check
5937a84e134Smrg *
5947a84e134Smrg * Returns:
5957a84e134Smrg *	True if the item passed is in the given rectangle
5967a84e134Smrg */
5977a84e134Smrgstatic Bool
5987a84e134SmrgItemInRectangle(Widget w, int ul, int lr, int item)
5997a84e134Smrg{
6007a84e134Smrg    ListWidget lw = (ListWidget)w;
6017a84e134Smrg    int mod_item;
6027a84e134Smrg    int things;
603421c997bSmrg
604421c997bSmrg    if (item < ul || item > lr)
6057a84e134Smrg      return (False);
6067a84e134Smrg    if (lw->list.vertical_cols)
6077a84e134Smrg	things = lw->list.nrows;
6087a84e134Smrg    else
6097a84e134Smrg	things = lw->list.ncols;
6107a84e134Smrg
6117a84e134Smrg    mod_item = item % things;
6127a84e134Smrg    if ((mod_item >= ul % things) && (mod_item <= lr % things))
6137a84e134Smrg      return (True);
6147a84e134Smrg
6157a84e134Smrg    return (False);
6167a84e134Smrg}
6177a84e134Smrg
6187a84e134Smrg/* HighlightBackground()
6197a84e134Smrg *
6207a84e134Smrg * Paints the color of the background for the given item.  It performs
6217a84e134Smrg * clipping to the interior of internal_width/height by hand, as its a
6227a84e134Smrg * simple calculation and probably much faster than using Xlib and a clip mask.
6237a84e134Smrg *
6247a84e134Smrg *  x, y - ul corner of the area item occupies.
6257a84e134Smrg *  gc - the gc to use to paint this rectangle
6267a84e134Smrg */
6277a84e134Smrgstatic void
6287a84e134SmrgHighlightBackground(Widget w, int x, int y, GC gc)
6297a84e134Smrg{
6307a84e134Smrg    ListWidget lw = (ListWidget)w;
6315ec34c4cSmrg    Dimension width = (Dimension)lw->list.col_width;
6325ec34c4cSmrg    Dimension height = (Dimension)lw->list.row_height;
6335ec34c4cSmrg    Dimension frame_limited_width = (Dimension)(XtWidth(w) - lw->list.internal_width - x);
6345ec34c4cSmrg    Dimension frame_limited_height= (Dimension)(XtHeight(w) - lw->list.internal_height - y);
6357a84e134Smrg
6367a84e134Smrg    /* Clip the rectangle width and height to the edge of the drawable area */
6377a84e134Smrg    if  (width > frame_limited_width)
6387a84e134Smrg	width = frame_limited_width;
6397a84e134Smrg    if  (height > frame_limited_height)
6407a84e134Smrg	height = frame_limited_height;
6417a84e134Smrg
6427a84e134Smrg    /* Clip the rectangle x and y to the edge of the drawable area */
6437a84e134Smrg    if (x < lw->list.internal_width) {
6445ec34c4cSmrg	width = (Dimension)(width - (lw->list.internal_width - x));
6457a84e134Smrg	x = lw->list.internal_width;
6467a84e134Smrg    }
6477a84e134Smrg    if (y < lw->list.internal_height) {
6485ec34c4cSmrg      height = (Dimension)(height - (lw->list.internal_height - y));
6497a84e134Smrg	y = lw->list.internal_height;
6507a84e134Smrg    }
6517a84e134Smrg
6527a84e134Smrg    if (gc == lw->list.revgc && lw->core.background_pixmap != XtUnspecifiedPixmap)
6537a84e134Smrg	XClearArea(XtDisplay(w), XtWindow(w), x, y, width, height, False);
6547a84e134Smrg    else
6557a84e134Smrg	XFillRectangle(XtDisplay(w), XtWindow(w), gc, x, y, width, height);
6567a84e134Smrg}
6577a84e134Smrg
6587a84e134Smrg
6597a84e134Smrg/* ClipToShadowInteriorAndLongest()
6607a84e134Smrg *
6617a84e134Smrg * Converts the passed gc so that any drawing done with that GC will not
6627a84e134Smrg * write in the empty margin (specified by internal_width/height) (which also
6637a84e134Smrg * prevents erasing the shadow.  It also clips against the value longest.
6647a84e134Smrg * If the user doesn't set longest, this has no effect (as longest is the
6657a84e134Smrg * maximum of all item lengths).  If the user does specify, say, 80 pixel
6667a84e134Smrg * columns, though, this prevents items from overwriting other items.
6677a84e134Smrg */
6687a84e134Smrgstatic void
6697a84e134SmrgClipToShadowInteriorAndLongest(ListWidget lw, GC *gc_p, unsigned int x)
6707a84e134Smrg{
6717a84e134Smrg    XRectangle rect;
6727a84e134Smrg
6735ec34c4cSmrg    rect.x = (short)x;
6745ec34c4cSmrg    rect.y = (short)lw->list.internal_height;
6755ec34c4cSmrg    rect.height = (unsigned short)(XtHeight(lw) - (lw->list.internal_height << 1));
6765ec34c4cSmrg    rect.width = (unsigned short)(XtWidth(lw) - (unsigned)lw->list.internal_width - x);
6777a84e134Smrg    if (rect.width > lw->list.longest)
6785ec34c4cSmrg	rect.width = (unsigned short)lw->list.longest;
6797a84e134Smrg
6807a84e134Smrg    XSetClipRectangles(XtDisplay((Widget)lw), *gc_p, 0, 0, &rect, 1, YXBanded);
6817a84e134Smrg}
6827a84e134Smrg
6837a84e134Smrgstatic void
6847a84e134SmrgPaintItemName(Widget w, int item)
6857a84e134Smrg{
6865ec34c4cSmrg    _Xconst char *str;
6877a84e134Smrg    GC gc;
6887a84e134Smrg    int x, y, str_y;
6897a84e134Smrg    ListWidget lw = (ListWidget)w;
6907a84e134Smrg    XFontSetExtents *ext  = XExtentsOfFontSet(lw->list.fontset);
6917a84e134Smrg
6927a84e134Smrg    if (!XtIsRealized(w) || item > lw->list.nitems)
6937a84e134Smrg      return;
6947a84e134Smrg
6957a84e134Smrg    if (lw->list.vertical_cols) {
6967a84e134Smrg	x = lw->list.col_width * (item / lw->list.nrows)
6977a84e134Smrg	  + lw->list.internal_width;
6987a84e134Smrg	y = lw->list.row_height * (item % lw->list.nrows)
6997a84e134Smrg	  + lw->list.internal_height;
7007a84e134Smrg    }
7017a84e134Smrg    else {
7027a84e134Smrg	x = lw->list.col_width * (item % lw->list.ncols)
7037a84e134Smrg	  + lw->list.internal_width;
7047a84e134Smrg	y = lw->list.row_height * (item / lw->list.ncols)
7057a84e134Smrg	  + lw->list.internal_height;
7067a84e134Smrg    }
7077a84e134Smrg
7087a84e134Smrg    if ( lw->simple.international == True )
7097a84e134Smrg	str_y = y + XawAbs(ext->max_ink_extent.y);
7107a84e134Smrg    else
7117a84e134Smrg	str_y = y + lw->list.font->max_bounds.ascent;
7127a84e134Smrg
7137a84e134Smrg    if (item == lw->list.is_highlighted) {
7147a84e134Smrg	if (item == lw->list.highlight) {
7157a84e134Smrg	    gc = lw->list.revgc;
7167a84e134Smrg	    HighlightBackground(w, x, y, lw->list.normgc);
7177a84e134Smrg	}
7187a84e134Smrg	else {
719421c997bSmrg	    if (XtIsSensitive(w))
7207a84e134Smrg		gc = lw->list.normgc;
7217a84e134Smrg	    else
7227a84e134Smrg		gc = lw->list.graygc;
7237a84e134Smrg	    HighlightBackground(w, x, y, lw->list.revgc);
7247a84e134Smrg	    lw->list.is_highlighted = NO_HIGHLIGHT;
7257a84e134Smrg	}
7267a84e134Smrg    }
7277a84e134Smrg    else {
7287a84e134Smrg	if (item == lw->list.highlight) {
7297a84e134Smrg	    gc = lw->list.revgc;
7307a84e134Smrg	    HighlightBackground(w, x, y, lw->list.normgc);
7317a84e134Smrg	    lw->list.is_highlighted = item;
7327a84e134Smrg	}
7337a84e134Smrg	else {
734421c997bSmrg	    if (XtIsSensitive(w))
7357a84e134Smrg		gc = lw->list.normgc;
7367a84e134Smrg	    else
7377a84e134Smrg		gc = lw->list.graygc;
7387a84e134Smrg	}
7397a84e134Smrg    }
7407a84e134Smrg
7417a84e134Smrg    /* List's overall width contains the same number of inter-column
7427a84e134Smrg       column_space's as columns.  There should thus be a half
7437a84e134Smrg       column_width margin on each side of each column.
7447a84e134Smrg       The row case is symmetric */
7457a84e134Smrg
7467a84e134Smrg    x += lw->list.column_space >> 1;
7477a84e134Smrg    str_y += lw->list.row_space >> 1;
7487a84e134Smrg
7497a84e134Smrg    str =  lw->list.list[item];	/* draw it */
7507a84e134Smrg
7515ec34c4cSmrg    ClipToShadowInteriorAndLongest(lw, &gc, (unsigned)x);
7527a84e134Smrg
7537a84e134Smrg    if (lw->simple.international == True)
7547a84e134Smrg	XmbDrawString(XtDisplay(w), XtWindow(w), lw->list.fontset,
7555ec34c4cSmrg		      gc, x, str_y, str, (int)strlen(str));
7567a84e134Smrg    else
7575ec34c4cSmrg	XDrawString(XtDisplay(w), XtWindow(w), gc, x, str_y, str, (int)strlen(str));
7587a84e134Smrg
7597a84e134Smrg    XSetClipMask(XtDisplay(w), gc, None);
7607a84e134Smrg}
7617a84e134Smrg
762421c997bSmrgstatic void
7637a84e134SmrgXawListRedisplay(Widget w, XEvent *event, Region region)
7647a84e134Smrg{
7657a84e134Smrg    int item;			/* an item to work with */
7667a84e134Smrg    int ul_item, lr_item;	/* corners of items we need to paint */
7677a84e134Smrg    ListWidget lw = (ListWidget)w;
7687a84e134Smrg
7697a84e134Smrg    if (event == NULL) {
7707a84e134Smrg	ul_item = 0;
7717a84e134Smrg	lr_item = lw->list.nrows * lw->list.ncols - 1;
7727a84e134Smrg	XClearWindow(XtDisplay(w), XtWindow(w));
7737a84e134Smrg    }
7747a84e134Smrg    else
7757a84e134Smrg	FindCornerItems(w, event, &ul_item, &lr_item);
7767a84e134Smrg
7777a84e134Smrg    if (Superclass->core_class.expose)
7787a84e134Smrg    (Superclass->core_class.expose)(w, event, region);
779421c997bSmrg
7807a84e134Smrg    for (item = ul_item; item <= lr_item && item < lw->list.nitems; item++)
7817a84e134Smrg	if (ItemInRectangle(w, ul_item, lr_item, item))
7827a84e134Smrg	    PaintItemName(w, item);
7837a84e134Smrg}
7847a84e134Smrg
7857a84e134Smrg/* XawListQueryGeometry()
7867a84e134Smrg *
7877a84e134Smrg * This tells the parent what size we would like to be
7887a84e134Smrg * given certain constraints.
7897a84e134Smrg * w - the widget.
7907a84e134Smrg * intended - what the parent intends to do with us.
7917a84e134Smrg * requested - what we want to happen */
792421c997bSmrgstatic XtGeometryResult
7937a84e134SmrgXawListQueryGeometry(Widget w, XtWidgetGeometry *intended,
7947a84e134Smrg		     XtWidgetGeometry *requested)
7957a84e134Smrg{
7967a84e134Smrg    Dimension new_width, new_height;
7977a84e134Smrg    Bool change, width_req, height_req;
798421c997bSmrg
7997a84e134Smrg    width_req = intended->request_mode & CWWidth;
8007a84e134Smrg    height_req = intended->request_mode & CWHeight;
8017a84e134Smrg
8027a84e134Smrg    if (width_req)
8037a84e134Smrg	new_width = intended->width;
8047a84e134Smrg    else
8057a84e134Smrg	new_width = XtWidth(w);
8067a84e134Smrg
8077a84e134Smrg    if (height_req)
8087a84e134Smrg	new_height = intended->height;
8097a84e134Smrg    else
8107a84e134Smrg	new_height = XtHeight(w);
8117a84e134Smrg
8127a84e134Smrg    requested->request_mode = 0;
813421c997bSmrg
8147a84e134Smrg   /*
8157a84e134Smrg    * We only care about our height and width
8167a84e134Smrg    */
8177a84e134Smrg    if (!width_req && !height_req)
8187a84e134Smrg	return (XtGeometryYes);
819421c997bSmrg
8207a84e134Smrg    change = Layout(w, !width_req, !height_req, &new_width, &new_height);
8217a84e134Smrg
8227a84e134Smrg    requested->request_mode |= CWWidth;
8237a84e134Smrg    requested->width = new_width;
8247a84e134Smrg    requested->request_mode |= CWHeight;
8257a84e134Smrg    requested->height = new_height;
8267a84e134Smrg
8277a84e134Smrg    if (change)
8287a84e134Smrg	return (XtGeometryAlmost);
8297a84e134Smrg
8307a84e134Smrg    return (XtGeometryYes);
8317a84e134Smrg}
8327a84e134Smrg
8337a84e134Smrgstatic void
8347a84e134SmrgXawListResize(Widget w)
8357a84e134Smrg{
8367a84e134Smrg    Dimension width, height;
8377a84e134Smrg
8387a84e134Smrg    width = XtWidth(w);
8397a84e134Smrg    height = XtHeight(w);
8407a84e134Smrg
8417a84e134Smrg    if (Layout(w, False, False, &width, &height))
8427a84e134Smrg	XtAppWarning(XtWidgetToApplicationContext(w),
8437a84e134Smrg		     "List Widget: Size changed when it shouldn't "
8447a84e134Smrg		     "have when resising.");
8457a84e134Smrg}
8467a84e134Smrg
8477a84e134Smrg/* Layout()
8487a84e134Smrg *
8497a84e134Smrg * lays out the item in the list.
8507a84e134Smrg * w - the widget.
8517a84e134Smrg * xfree, yfree - True if we are free to resize the widget in
8527a84e134Smrg *		this direction.
8537a84e134Smrg * width, height- the is the current width and height that we are going
8547a84e134Smrg *		we are going to layout the list widget to,
8557a84e134Smrg *		depending on xfree and yfree of course.
856421c997bSmrg *
8577a84e134Smrg * Return:
8587a84e134Smrg *	True if width or height have been changed */
8597a84e134Smrgstatic Bool
8607a84e134SmrgLayout(Widget w, Bool xfree, Bool yfree, Dimension *width, Dimension *height)
8617a84e134Smrg{
8627a84e134Smrg    ListWidget lw = (ListWidget)w;
8637a84e134Smrg    Bool change = False;
8647a84e134Smrg    unsigned long width2 = 0, height2 = 0;
8657a84e134Smrg
8667a84e134Smrg    /*
8677a84e134Smrg     * If force columns is set then always use number of columns specified
8687a84e134Smrg     * by default_cols
8697a84e134Smrg     */
8707a84e134Smrg    if (lw->list.force_cols) {
8717a84e134Smrg	lw->list.ncols = lw->list.default_cols;
8727a84e134Smrg	if (lw->list.ncols <= 0)
8737a84e134Smrg	    lw->list.ncols = 1;
8747a84e134Smrg	lw->list.nrows = ((lw->list.nitems - 1) / lw->list.ncols) + 1;
8757a84e134Smrg	if (xfree) {
8767a84e134Smrg	    /* this counts the same number
8777a84e134Smrg	       of inter-column column_space 's as columns.  There should thus
8787a84e134Smrg	       be a half column_space margin on each side of each column...*/
8795ec34c4cSmrg	    width2 = (unsigned long)(lw->list.ncols * lw->list.col_width +
8805ec34c4cSmrg		     (lw->list.internal_width << 1));
8817a84e134Smrg	    change = True;
8827a84e134Smrg	}
8837a84e134Smrg	if (yfree) {
8845ec34c4cSmrg	    height2 = (unsigned long)(lw->list.nrows * lw->list.row_height +
8855ec34c4cSmrg		      (lw->list.internal_height << 1));
8867a84e134Smrg	    change = True;
8877a84e134Smrg	}
8887a84e134Smrg    }
8897a84e134Smrg
8907a84e134Smrg    /*
8917a84e134Smrg     * If both width and height are free to change the use default_cols
8927a84e134Smrg     * to determine the number columns and set new width and height to
8937a84e134Smrg     * just fit the window
8947a84e134Smrg     */
8957a84e134Smrg    else if (xfree && yfree) {
8967a84e134Smrg	lw->list.ncols = lw->list.default_cols;
8977a84e134Smrg	if (lw->list.ncols <= 0) {
8987a84e134Smrg	    int wid = (int)XtWidth(lw) - (int)(lw->list.internal_width << 1)
8997a84e134Smrg	      + (int)lw->list.column_space;
9007a84e134Smrg
9017a84e134Smrg	    if (wid <= 0 || lw->list.col_width <= 0
9027a84e134Smrg		|| (lw->list.ncols = wid / lw->list.col_width) <= 0)
9037a84e134Smrg		lw->list.ncols = 1;
9047a84e134Smrg	}
9055ec34c4cSmrg	width2 = (unsigned long)((lw->list.ncols * lw->list.col_width)
9065ec34c4cSmrg		  + (lw->list.internal_width << 1));
9075ec34c4cSmrg	height2 = (unsigned long)((lw->list.nrows * lw->list.row_height)
9085ec34c4cSmrg		   + (lw->list.internal_height << 1));
9097a84e134Smrg	change = True;
9107a84e134Smrg    }
9117a84e134Smrg
9127a84e134Smrg    /*
9137a84e134Smrg     * If the width is fixed then use it to determine the number of columns.
9147a84e134Smrg     * If the height is free to move (width still fixed) then resize the height
9157a84e134Smrg     * of the widget to fit the current list exactly
9167a84e134Smrg     */
9177a84e134Smrg    else if (!xfree) {
9187a84e134Smrg	lw->list.ncols = ((int)(*width - (lw->list.internal_width << 1))
9197a84e134Smrg			  / (int)lw->list.col_width);
9207a84e134Smrg	if (lw->list.ncols <= 0)
9217a84e134Smrg	    lw->list.ncols = 1;
9227a84e134Smrg	lw->list.nrows = ((lw->list.nitems - 1) / lw->list.ncols) + 1;
9237a84e134Smrg	if (yfree) {
9245ec34c4cSmrg	    height2 = (unsigned long)((lw->list.nrows * lw->list.row_height) +
9255ec34c4cSmrg		      (lw->list.internal_height << 1));
9267a84e134Smrg	    change = True;
9277a84e134Smrg	}
9287a84e134Smrg    }
9297a84e134Smrg
9307a84e134Smrg    /*
9317a84e134Smrg     * The last case is xfree and !yfree we use the height to determine
9327a84e134Smrg     * the number of rows and then set the width to just fit the resulting
9337a84e134Smrg     * number of columns
9347a84e134Smrg     */
9357a84e134Smrg    else if (!yfree) {
9367a84e134Smrg	lw->list.nrows = ((int)(*height - (lw->list.internal_height << 1))
9377a84e134Smrg			  / (int)lw->list.row_height);
9387a84e134Smrg	if (lw->list.nrows <= 0)
9397a84e134Smrg	    lw->list.nrows = 1;
9407a84e134Smrg	lw->list.ncols = ((lw->list.nitems - 1) / lw->list.nrows) + 1;
9415ec34c4cSmrg	width2 = (unsigned long)((lw->list.ncols * lw->list.col_width) +
9425ec34c4cSmrg		 (lw->list.internal_width << 1));
9437a84e134Smrg	change = True;
9447a84e134Smrg    }
9457a84e134Smrg
9467a84e134Smrg    if (!lw->list.force_cols && lw->list.nrows) {
9477a84e134Smrg	/*CONSTCOND*/
9487a84e134Smrg	while (1) {
9497a84e134Smrg	    lw->list.nrows = ((lw->list.nitems - 1) / lw->list.ncols) + 1;
9505ec34c4cSmrg	    width2 = (unsigned long)((lw->list.ncols * lw->list.col_width) +
9515ec34c4cSmrg		     (lw->list.internal_width << 1));
9525ec34c4cSmrg	    height2 = (unsigned long)((lw->list.nrows * lw->list.row_height) +
9535ec34c4cSmrg		      (lw->list.internal_height << 1));
9547a84e134Smrg	    if (width2 >= MaxSize && height2 >= MaxSize)
9557a84e134Smrg		break;
9567a84e134Smrg	    if (height2 > MaxSize)
9577a84e134Smrg		++lw->list.ncols;
9587a84e134Smrg	    else if (width2 > MaxSize && lw->list.ncols > 1)
9597a84e134Smrg		--lw->list.ncols;
9607a84e134Smrg	    else
9617a84e134Smrg		break;
9627a84e134Smrg	}
9637a84e134Smrg    }
9647a84e134Smrg    if (width2)
9655ec34c4cSmrg	*width = (Dimension)width2;
9667a84e134Smrg    if (height2)
9675ec34c4cSmrg	*height = (Dimension)height2;
9687a84e134Smrg
9697a84e134Smrg    return (change);
9707a84e134Smrg}
9717a84e134Smrg
9727a84e134Smrg/* Notify() - Action
9737a84e134Smrg *
9747a84e134Smrg * Notifies the user that a button has been pressed, and
9757a84e134Smrg * calls the callback; if the XtNpasteBuffer resource is true
9767a84e134Smrg * then the name of the item is also put in CUT_BUFFER0 */
9777a84e134Smrg/*ARGSUSED*/
9787a84e134Smrgstatic void
9795ec34c4cSmrgNotify(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
9807a84e134Smrg{
9817a84e134Smrg    ListWidget lw = (ListWidget)w;
9827a84e134Smrg    int item, item_len;
9837a84e134Smrg    XawListReturnStruct ret_value;
9847a84e134Smrg
9857a84e134Smrg    /*
9867a84e134Smrg     * Find item and if out of range then unhighlight and return
987421c997bSmrg     *
9887a84e134Smrg     * If the current item is unhighlighted then the user has aborted the
9897a84e134Smrg     * notify, so unhighlight and return
9907a84e134Smrg     */
9917a84e134Smrg    if ((CvtToItem(w, event->xbutton.x, event->xbutton.y, &item) == OUT_OF_RANGE)
9927a84e134Smrg	|| lw->list.highlight != item) {
9937a84e134Smrg#ifndef OLDXAW
9947a84e134Smrg	if (!lw->list.show_current || lw->list.selected == NO_HIGHLIGHT)
9957a84e134Smrg	    XawListUnhighlight(w);
9967a84e134Smrg	else
9977a84e134Smrg	    XawListHighlight(w, lw->list.selected);
9987a84e134Smrg#else
9997a84e134Smrg	XawListUnhighlight(w);
10007a84e134Smrg#endif
10017a84e134Smrg	return;
10027a84e134Smrg    }
10037a84e134Smrg
10045ec34c4cSmrg    item_len = (int)strlen(lw->list.list[item]);
10057a84e134Smrg
10067a84e134Smrg    if (lw->list.paste)		/* if XtNpasteBuffer set then paste it */
10077a84e134Smrg	XStoreBytes(XtDisplay(w), lw->list.list[item], item_len);
10087a84e134Smrg
10097a84e134Smrg#ifndef OLDXAW
10107a84e134Smrg    lw->list.selected = item;
10117a84e134Smrg#endif
10127a84e134Smrg    /*
10137a84e134Smrg     * Call Callback function
10147a84e134Smrg     */
10157a84e134Smrg    ret_value.string = lw->list.list[item];
10167a84e134Smrg    ret_value.list_index = item;
1017421c997bSmrg
10187a84e134Smrg    XtCallCallbacks(w, XtNcallback, (XtPointer)&ret_value);
10197a84e134Smrg}
10207a84e134Smrg
10217a84e134Smrg/* Unset() - Action
10227a84e134Smrg *
10237a84e134Smrg * unhighlights the current element */
10247a84e134Smrg/*ARGSUSED*/
10257a84e134Smrgstatic void
10265ec34c4cSmrgUnset(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
10277a84e134Smrg{
10287a84e134Smrg    XawListUnhighlight(w);
10297a84e134Smrg}
10307a84e134Smrg
10317a84e134Smrg/* Set() - Action
10327a84e134Smrg *
10337a84e134Smrg * Highlights the current element */
10347a84e134Smrg/*ARGSUSED*/
10357a84e134Smrgstatic void
10365ec34c4cSmrgSet(Widget w, XEvent *event, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
10377a84e134Smrg{
10387a84e134Smrg    int item;
10397a84e134Smrg    ListWidget lw = (ListWidget)w;
10407a84e134Smrg
10417a84e134Smrg#ifndef OLDXAW
10427a84e134Smrg    lw->list.selected = lw->list.highlight;
10437a84e134Smrg#endif
10447a84e134Smrg    if (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item) == OUT_OF_RANGE)
10457a84e134Smrg	XawListUnhighlight(w);			/* Unhighlight current item */
10467a84e134Smrg    else if (lw->list.is_highlighted != item)	/* If this item is not */
10477a84e134Smrg	XawListHighlight(w, item);		/* highlighted then do it */
10487a84e134Smrg}
10497a84e134Smrg
10507a84e134Smrg/*
10517a84e134Smrg * Set specified arguments into widget
10527a84e134Smrg */
10537a84e134Smrg/*ARGSUSED*/
1054421c997bSmrgstatic Boolean
10557a84e134SmrgXawListSetValues(Widget current, Widget request, Widget cnew,
10565ec34c4cSmrg		 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
10577a84e134Smrg{
10587a84e134Smrg    ListWidget cl = (ListWidget)current;
10597a84e134Smrg    ListWidget rl = (ListWidget)request;
10607a84e134Smrg    ListWidget nl = (ListWidget)cnew;
10617a84e134Smrg    Bool redraw = False;
10627a84e134Smrg    XFontSetExtents *ext = XExtentsOfFontSet(nl->list.fontset);
10637a84e134Smrg
10647a84e134Smrg    /* If the request height/width is different, lock it.  Unless its 0. If
10657a84e134Smrg       neither new nor 0, leave it as it was.  Not in R5 */
10667a84e134Smrg    if (XtWidth(nl) != XtWidth(cl))
10677a84e134Smrg	nl->list.freedoms |= WidthLock;
10687a84e134Smrg    if (XtWidth(nl) == 0)
10697a84e134Smrg	nl->list.freedoms &= ~WidthLock;
10707a84e134Smrg
10717a84e134Smrg    if (XtHeight(nl) != XtHeight(cl))
10727a84e134Smrg	nl->list.freedoms |= HeightLock;
10737a84e134Smrg    if (XtHeight(nl) == 0)
10747a84e134Smrg	nl->list.freedoms &= ~HeightLock;
10757a84e134Smrg
10767a84e134Smrg    if (nl->list.longest != cl->list.longest)
10777a84e134Smrg	nl->list.freedoms |= LongestLock;
10787a84e134Smrg    if (nl->list.longest == 0)
10797a84e134Smrg	nl->list.freedoms &= ~LongestLock;
10807a84e134Smrg
10817a84e134Smrg    if (cl->list.foreground != nl->list.foreground ||
10827a84e134Smrg	cl->core.background_pixel != nl->core.background_pixel ||
10837a84e134Smrg	cl->list.font != nl->list.font) {
10847a84e134Smrg	XGCValues values;
10857a84e134Smrg
10867a84e134Smrg	XGetGCValues(XtDisplay(current), cl->list.graygc, GCTile, &values);
10877a84e134Smrg	XmuReleaseStippledPixmap(XtScreen(current), values.tile);
10887a84e134Smrg	XtReleaseGC(current, cl->list.graygc);
10897a84e134Smrg	XtReleaseGC(current, cl->list.revgc);
10907a84e134Smrg	XtReleaseGC(current, cl->list.normgc);
10917a84e134Smrg	GetGCs(cnew);
10927a84e134Smrg	redraw = True;
10937a84e134Smrg    }
10947a84e134Smrg
10957a84e134Smrg    if (cl->list.font != nl->list.font && cl->simple.international == False)
10967a84e134Smrg	nl->list.row_height = nl->list.font->max_bounds.ascent
10977a84e134Smrg			    + nl->list.font->max_bounds.descent
10987a84e134Smrg			    + nl->list.row_space;
10997a84e134Smrg    else if (cl->list.fontset != nl->list.fontset
11007a84e134Smrg	&& cl->simple.international == True)
11017a84e134Smrg	nl->list.row_height = ext->max_ink_extent.height + nl->list.row_space;
11027a84e134Smrg
11037a84e134Smrg    /* ...If the above two font(set) change checkers above both failed, check
11047a84e134Smrg       if row_space was altered.  If one of the above passed, row_height will
11057a84e134Smrg       already have been re-calculated */
11067a84e134Smrg    else if (cl->list.row_space != nl->list.row_space) {
11077a84e134Smrg	if (cl->simple.international == True)
11087a84e134Smrg	    nl->list.row_height = ext->max_ink_extent.height + nl->list.row_space;
11097a84e134Smrg	else
11107a84e134Smrg	    nl->list.row_height = nl->list.font->max_bounds.ascent
11117a84e134Smrg				+ nl->list.font->max_bounds.descent
11127a84e134Smrg				+ nl->list.row_space;
11137a84e134Smrg    }
11147a84e134Smrg
11157a84e134Smrg    if (XtWidth(cl) != XtWidth(nl) || XtHeight(cl) != XtHeight(nl)
11167a84e134Smrg	|| cl->list.internal_width != nl->list.internal_width
11177a84e134Smrg	|| cl->list.internal_height != nl->list.internal_height
11187a84e134Smrg	|| cl->list.column_space != nl->list.column_space
11197a84e134Smrg	|| cl->list.row_space != nl->list.row_space
11207a84e134Smrg	|| cl->list.default_cols != nl->list.default_cols
11217a84e134Smrg	|| (cl->list.force_cols != nl->list.force_cols
11227a84e134Smrg	    && rl->list.force_cols != nl->list.ncols)
11237a84e134Smrg	|| cl->list.vertical_cols != nl->list.vertical_cols
11247a84e134Smrg	|| cl->list.longest != nl->list.longest
11257a84e134Smrg	|| cl->list.nitems != nl->list.nitems
11267a84e134Smrg	|| cl->list.font != nl->list.font
11277a84e134Smrg	/* Equiv. fontsets might have different values, but the same fonts,
11287a84e134Smrg	   so the next comparison is sloppy but not dangerous  */
11297a84e134Smrg	|| cl->list.fontset != nl->list.fontset
11307a84e134Smrg	|| cl->list.list != nl->list.list) {
11317a84e134Smrg	CalculatedValues(cnew);
11327a84e134Smrg	Layout(cnew, WidthFree(nl), HeightFree(nl),
11337a84e134Smrg	       &nl->core.width, &nl->core.height);
11347a84e134Smrg	redraw = True;
11357a84e134Smrg    }
11367a84e134Smrg
11377a84e134Smrg    if (cl->list.list != nl->list.list || cl->list.nitems != nl->list.nitems)
11387a84e134Smrg	nl->list.is_highlighted = nl->list.highlight = NO_HIGHLIGHT;
11397a84e134Smrg
11407a84e134Smrg    if (cl->core.sensitive != nl->core.sensitive
11417a84e134Smrg	|| cl->core.ancestor_sensitive != nl->core.ancestor_sensitive) {
11427a84e134Smrg	nl->list.highlight = NO_HIGHLIGHT;
11437a84e134Smrg	redraw = True;
11447a84e134Smrg    }
1145421c997bSmrg
11465ec34c4cSmrg    return (Boolean)(redraw);
11477a84e134Smrg}
11487a84e134Smrg
11497a84e134Smrgstatic void
11507a84e134SmrgXawListDestroy(Widget w)
11517a84e134Smrg{
11527a84e134Smrg    ListWidget lw = (ListWidget)w;
11537a84e134Smrg    XGCValues values;
1154421c997bSmrg
11557a84e134Smrg    XGetGCValues(XtDisplay(w), lw->list.graygc, GCTile, &values);
11567a84e134Smrg    XmuReleaseStippledPixmap(XtScreen(w), values.tile);
11577a84e134Smrg    XtReleaseGC(w, lw->list.graygc);
11587a84e134Smrg    XtReleaseGC(w, lw->list.revgc);
11597a84e134Smrg    XtReleaseGC(w, lw->list.normgc);
11607a84e134Smrg}
11617a84e134Smrg
11627a84e134Smrg/*
11637a84e134Smrg * Function:
11647a84e134Smrg *	XawListChange
11657a84e134Smrg *
11667a84e134Smrg * Parameters:
11677a84e134Smrg *	w - list widget
11687a84e134Smrg *	list - new list
11697a84e134Smrg *	nitems - number of items in the list
11707a84e134Smrg *	longest - length (in Pixels) of the longest element in the list
11717a84e134Smrg *	resize - if True the the list widget will try to resize itself
11727a84e134Smrg *
11737a84e134Smrg * Description:
11747a84e134Smrg *	Changes the list being used and shown.
11757a84e134Smrg *
11767a84e134Smrg * Note:
11777a84e134Smrg *	If nitems of longest are <= 0 then they will be calculated
11787a84e134Smrg *	If nitems is <= 0 then the list needs to be NULL terminated
11797a84e134Smrg */
11807a84e134Smrgvoid
11815ec34c4cSmrgXawListChange(Widget w, _Xconst char **list, int nitems, int longest,
11827a84e134Smrg#if NeedWidePrototypes
11837a84e134Smrg	int resize_it
11847a84e134Smrg#else
11857a84e134Smrg	Boolean resize_it
11867a84e134Smrg#endif
11877a84e134Smrg)
11887a84e134Smrg{
11897a84e134Smrg    ListWidget lw = (ListWidget)w;
11907a84e134Smrg    Dimension new_width = XtWidth(w);
11917a84e134Smrg    Dimension new_height = XtHeight(w);
11927a84e134Smrg
11937a84e134Smrg    lw->list.list = list;
11947a84e134Smrg
11957a84e134Smrg    if (nitems <= 0)
11967a84e134Smrg	nitems = 0;
11977a84e134Smrg    lw->list.nitems = nitems;
11987a84e134Smrg    if (longest <= 0)
11997a84e134Smrg	longest = 0;
12007a84e134Smrg
12017a84e134Smrg    /* If the user passes 0 meaning "calculate it", it must be free */
12027a84e134Smrg    if (longest != 0)
12037a84e134Smrg	lw->list.freedoms |= LongestLock;
12047a84e134Smrg    else
12057a84e134Smrg	lw->list.freedoms &= ~LongestLock;
12067a84e134Smrg
12077a84e134Smrg    if (resize_it)
12087a84e134Smrg	lw->list.freedoms &= ~WidthLock & ~HeightLock;
12097a84e134Smrg
12107a84e134Smrg    lw->list.longest = longest;
12117a84e134Smrg
12127a84e134Smrg    CalculatedValues(w);
12137a84e134Smrg
12147a84e134Smrg    if (Layout(w, WidthFree(w), HeightFree(w), &new_width, &new_height))
12157a84e134Smrg	ChangeSize(w, new_width, new_height);
12167a84e134Smrg
12177a84e134Smrg    lw->list.is_highlighted = lw->list.highlight = NO_HIGHLIGHT;
12187a84e134Smrg    if (XtIsRealized(w))
12197a84e134Smrg	XawListRedisplay(w, NULL, NULL);
12207a84e134Smrg}
12217a84e134Smrg
12227a84e134Smrgvoid
12237a84e134SmrgXawListUnhighlight(Widget w)
12247a84e134Smrg{
12257a84e134Smrg    ListWidget lw = (ListWidget)w;
12267a84e134Smrg
12277a84e134Smrg    lw->list.highlight = NO_HIGHLIGHT;
12287a84e134Smrg    if (lw->list.is_highlighted != NO_HIGHLIGHT)
12297a84e134Smrg    PaintItemName(w, lw->list.is_highlighted);
12307a84e134Smrg}
12317a84e134Smrg
12327a84e134Smrgvoid
12337a84e134SmrgXawListHighlight(Widget w, int item)
12347a84e134Smrg{
12357a84e134Smrg    ListWidget lw = (ListWidget)w;
1236421c997bSmrg
12377a84e134Smrg    if (XtIsSensitive(w)) {
12387a84e134Smrg	lw->list.highlight = item;
12397a84e134Smrg	if (lw->list.is_highlighted != NO_HIGHLIGHT)
12407a84e134Smrg	PaintItemName(w, lw->list.is_highlighted);
12417a84e134Smrg	PaintItemName(w, item);
12427a84e134Smrg    }
12437a84e134Smrg}
12447a84e134Smrg
12457a84e134Smrg/*
12467a84e134Smrg * Function:
12477a84e134Smrg *	XawListShowCurrent
12487a84e134Smrg *
12497a84e134Smrg * Parameters:
12507a84e134Smrg *	w - list widget
12517a84e134Smrg *
12527a84e134Smrg * Returns:
12537a84e134Smrg *	Info about the currently highlighted object
12547a84e134Smrg */
12557a84e134SmrgXawListReturnStruct *
12567a84e134SmrgXawListShowCurrent(Widget w)
12577a84e134Smrg{
12587a84e134Smrg    ListWidget lw = (ListWidget)w;
12597a84e134Smrg    XawListReturnStruct *ret_val;
12607a84e134Smrg
12617a84e134Smrg    ret_val = (XawListReturnStruct *)XtMalloc(sizeof(XawListReturnStruct));
1262421c997bSmrg
12637a84e134Smrg    ret_val->list_index = lw->list.highlight;
12647a84e134Smrg    if (ret_val->list_index == XAW_LIST_NONE)
12657a84e134Smrg	ret_val->string = "";
12667a84e134Smrg    else
12677a84e134Smrg	ret_val->string = lw->list.list[ret_val->list_index];
12687a84e134Smrg
12697a84e134Smrg    return (ret_val);
12707a84e134Smrg}
1271