11abf7346Smrg/*
21abf7346Smrg
31abf7346SmrgCopyright (c) 1987, 1988  X Consortium
41abf7346Smrg
51abf7346SmrgPermission is hereby granted, free of charge, to any person obtaining
61abf7346Smrga copy of this software and associated documentation files (the
71abf7346Smrg"Software"), to deal in the Software without restriction, including
81abf7346Smrgwithout limitation the rights to use, copy, modify, merge, publish,
91abf7346Smrgdistribute, sublicense, and/or sell copies of the Software, and to
101abf7346Smrgpermit persons to whom the Software is furnished to do so, subject to
111abf7346Smrgthe following conditions:
121abf7346Smrg
131abf7346SmrgThe above copyright notice and this permission notice shall be included
141abf7346Smrgin all copies or substantial portions of the Software.
151abf7346Smrg
161abf7346SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
171abf7346SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
181abf7346SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
191abf7346SmrgIN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
201abf7346SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
211abf7346SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
221abf7346SmrgOTHER DEALINGS IN THE SOFTWARE.
231abf7346Smrg
241abf7346SmrgExcept as contained in this notice, the name of the X Consortium shall
251abf7346Smrgnot be used in advertising or otherwise to promote the sale, use or
261abf7346Smrgother dealings in this Software without prior written authorization
271abf7346Smrgfrom the X Consortium.
281abf7346Smrg
291abf7346Smrg*/
301abf7346Smrg
311abf7346Smrg#include <stdio.h>
321abf7346Smrg#include <ctype.h>
331abf7346Smrg#include <X11/Xos.h>
341abf7346Smrg#include <stdlib.h>
35a5a2a776Smrg#include <limits.h>
361abf7346Smrg
371abf7346Smrg#include <X11/IntrinsicP.h>
386d36ef34Smrg#include <sys/stat.h>           /* depends on IntrinsicP.h */
391abf7346Smrg#include <X11/StringDefs.h>
401abf7346Smrg
411abf7346Smrg#include <X11/Xaw/Scrollbar.h>
421abf7346Smrg
431abf7346Smrg#include "ScrollByLP.h"
441abf7346Smrg
451abf7346Smrg/* Default Translation Table */
461abf7346Smrg
476d36ef34Smrgstatic char defaultTranslations[] =
481abf7346Smrg  "<Key>f:      Page(Forward) \n\
491abf7346Smrg   <Key>b:      Page(Back) \n\
501abf7346Smrg   <Key>1:      Page(Line, 1) \n\
511abf7346Smrg   <Key>2:      Page(Line, 2) \n\
521abf7346Smrg   <Key>3:      Page(Line, 3) \n\
531abf7346Smrg   <Key>4:      Page(Line, 4) \n\
541abf7346Smrg   <Key>\\ :    Page(Forward)";
551abf7346Smrg
561abf7346Smrg/****************************************************************
571abf7346Smrg *
581abf7346Smrg * ScrollByLine Resources
591abf7346Smrg *
601abf7346Smrg ****************************************************************/
611abf7346Smrg
621abf7346Smrg#define Offset(field) XtOffset(ScrollByLineWidget, scroll.field)
631abf7346Smrg#define CoreOffset(field) XtOffset(ScrollByLineWidget, core.field)
641abf7346Smrg
651abf7346Smrgstatic XtResource resources[] = {
661abf7346Smrg    {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
676d36ef34Smrg     CoreOffset(width), XtRImmediate, (caddr_t) 500},
681abf7346Smrg    {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
696d36ef34Smrg     CoreOffset(height), XtRImmediate, (caddr_t) 700},
701abf7346Smrg
711abf7346Smrg    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
726d36ef34Smrg     Offset(foreground), XtRString, "XtDefaultForeground"},
731abf7346Smrg    {XtNforceVert, XtCBoolean, XtRBoolean, sizeof(Boolean),
746d36ef34Smrg     Offset(force_vert), XtRImmediate, (caddr_t) FALSE},
751abf7346Smrg    {XtNindent, XtCIndent, XtRDimension, sizeof(Dimension),
766d36ef34Smrg     Offset(indent), XtRImmediate, (caddr_t) 15},
771abf7346Smrg    {XtNuseRight, XtCBoolean, XtRBoolean, sizeof(Boolean),
786d36ef34Smrg     Offset(use_right), XtRImmediate, (caddr_t) FALSE},
791abf7346Smrg    {XtNmanualFontNormal, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
806d36ef34Smrg     Offset(normal_font), XtRString, MANPAGE_NORMAL},
811abf7346Smrg    {XtNmanualFontBold, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
826d36ef34Smrg     Offset(bold_font), XtRString, MANPAGE_BOLD},
831abf7346Smrg    {XtNmanualFontItalic, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
846d36ef34Smrg     Offset(italic_font), XtRString, MANPAGE_ITALIC},
851abf7346Smrg    {XtNmanualFontSymbol, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
866d36ef34Smrg     Offset(symbol_font), XtRString, MANPAGE_SYMBOL},
871abf7346Smrg    {XtNfile, XtCFile, XtRFile, sizeof(FILE *),
886d36ef34Smrg     Offset(file), XtRImmediate, (caddr_t) NULL},
891abf7346Smrg    {XtNNumTotalLines, XtCNumTotalLines, XtRInt, sizeof(int),
906d36ef34Smrg     Offset(lines), XtRImmediate, (caddr_t) 0},
911abf7346Smrg    {XtNNumVisibleLines, XtCNumVisibleLines, XtRInt, sizeof(int),
926d36ef34Smrg     Offset(num_visible_lines), XtRImmediate, (caddr_t) 0},
931abf7346Smrg};
941abf7346Smrg
951abf7346Smrg#undef Offset
961abf7346Smrg#undef CoreOffset
971abf7346Smrg
981abf7346Smrg/****************************************************************
991abf7346Smrg *
1001abf7346Smrg * Full class record constant
1011abf7346Smrg *
1021abf7346Smrg ****************************************************************/
1031abf7346Smrg
1041abf7346Smrgstatic void CreateScrollbar(Widget w);
1051abf7346Smrgstatic Boolean ScrollVerticalText(Widget w, int new_line, Boolean force_redisp);
1061abf7346Smrgstatic void Layout(Widget w);
1071abf7346Smrgstatic void LoadFile(Widget w);
1081abf7346Smrgstatic void MoveAndClearText(Widget w, int old_y, int height, int new_y);
1091abf7346Smrgstatic void PaintText(Widget w, int y_loc, int height);
1101abf7346Smrgstatic void PrintText(Widget w, int start_line, int num_lines, int location);
1111abf7346Smrgstatic void SetThumbHeight(Widget w);
1121abf7346Smrgstatic void VerticalJump(Widget w, XtPointer junk, XtPointer percent_ptr);
1136d36ef34Smrgstatic void VerticalScroll(Widget w, XtPointer client_data,
1146d36ef34Smrg                           XtPointer call_data);
1151abf7346Smrg
1161abf7346Smrg/* semi - public functions. */
1171abf7346Smrg
1186d36ef34Smrgstatic void Realize(Widget w, Mask *valueMask,
1196d36ef34Smrg                    XSetWindowAttributes *attributes);
1206d36ef34Smrgstatic void Initialize(Widget req, Widget new, ArgList args,
1216d36ef34Smrg                       Cardinal *num_args);
1221abf7346Smrgstatic void Destroy(Widget w);
1231abf7346Smrgstatic void Redisplay(Widget w, XEvent *event, Region region);
1246d36ef34Smrgstatic void Page(Widget w, XEvent *event, String *params, Cardinal *num_params);
1251abf7346Smrgstatic Boolean SetValuesHook(Widget w, ArgList args, Cardinal *num_args);
1261abf7346Smrg
1271abf7346Smrgstatic XtActionsRec actions[] = {
1286d36ef34Smrg    {"Page", Page},
1291abf7346Smrg};
1301abf7346Smrg
1311abf7346Smrg#define superclass		(&simpleClassRec)
1321abf7346Smrg#define SuperClass		simpleWidgetClass
1331abf7346Smrg
1341abf7346SmrgScrollByLineClassRec scrollByLineClassRec = {
1356d36ef34Smrg    {
1361abf7346Smrg/* core_class fields      */
1376d36ef34Smrg     /* superclass         */ (WidgetClass) superclass,
1386d36ef34Smrg     /* class_name         */ "ScrollByLine",
1396d36ef34Smrg     /* widget_size        */ sizeof(ScrollByLineRec),
1406d36ef34Smrg     /* class_initialize   */ NULL,
1416d36ef34Smrg     /* class_part_init    */ NULL,
1426d36ef34Smrg     /* class_inited       */ FALSE,
1436d36ef34Smrg     /* initialize         */ Initialize,
1446d36ef34Smrg     /* initialize_hook    */ NULL,
1456d36ef34Smrg     /* realize            */ Realize,
1466d36ef34Smrg     /* actions            */ actions,
1476d36ef34Smrg     /* num_actions        */ XtNumber(actions),
1486d36ef34Smrg     /* resources          */ resources,
1496d36ef34Smrg     /* num_resources      */ XtNumber(resources),
1506d36ef34Smrg     /* xrm_class          */ NULLQUARK,
1516d36ef34Smrg     /* compress_motion    */ TRUE,
1526d36ef34Smrg     /* compress_exposure  */ FALSE,
1536d36ef34Smrg     /* compress_enterleave */ TRUE,
1546d36ef34Smrg     /* visible_interest   */ FALSE,
1556d36ef34Smrg     /* destroy            */ Destroy,
1566d36ef34Smrg     /* resize             */ Layout,
1576d36ef34Smrg     /* expose             */ Redisplay,
1586d36ef34Smrg     /* set_values         */ NULL,
1596d36ef34Smrg     /* set_values_hook    */ SetValuesHook,
1606d36ef34Smrg     /* set_values_almost  */ XtInheritSetValuesAlmost,
1616d36ef34Smrg     /* get_values_hook    */ NULL,
1626d36ef34Smrg     /* accept_focus       */ NULL,
1636d36ef34Smrg     /* version            */ XtVersion,
1646d36ef34Smrg     /* callback_private   */ NULL,
1656d36ef34Smrg     /* tm_table           */ defaultTranslations,
1666d36ef34Smrg     /* query_geometry     */ XtInheritQueryGeometry,
1676d36ef34Smrg     /* display_accelerator */ XtInheritDisplayAccelerator,
1686d36ef34Smrg     /* extension          */ NULL,
1696d36ef34Smrg     },
1706d36ef34Smrg    {
1716d36ef34Smrg/* simple fields */
1726d36ef34Smrg     /* change_sensitive         */ XtInheritChangeSensitive
1736d36ef34Smrg     }
1741abf7346Smrg};
1751abf7346Smrg
1766d36ef34SmrgWidgetClass scrollByLineWidgetClass = (WidgetClass) &scrollByLineClassRec;
1771abf7346Smrg
1781abf7346Smrg/****************************************************************
1791abf7346Smrg *
1801abf7346Smrg * Private Routines
1811abf7346Smrg *
1821abf7346Smrg ****************************************************************/
1831abf7346Smrg
1841abf7346Smrg/*	Function Name: Layout
1851abf7346Smrg *	Description: This function lays out the scroll widget.
1861abf7346Smrg *	Arguments: w - the scroll widget.
1871abf7346Smrg *                 key - a boolean: if true then resize the widget to the child
1881abf7346Smrg *                                  if false the resize children to fit widget.
1891abf7346Smrg *	Returns: TRUE if successful.
1901abf7346Smrg */
1911abf7346Smrg
1921abf7346Smrgstatic void
1931abf7346SmrgLayout(Widget w)
1946d36ef34Smrg{
1956d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
1966d36ef34Smrg    Dimension width, height;
1976d36ef34Smrg    Widget bar;
1986d36ef34Smrg    Position bar_bw;
1991abf7346Smrg
2006d36ef34Smrg    CreateScrollbar(w);
2011abf7346Smrg
2026d36ef34Smrg/*
2031abf7346Smrg * For now always show the bar.
2041abf7346Smrg */
2051abf7346Smrg
2066d36ef34Smrg    bar = sblw->scroll.bar;
2076d36ef34Smrg    height = sblw->core.height;
2086d36ef34Smrg    width = sblw->core.width;
2096d36ef34Smrg    bar_bw = bar->core.border_width;
2101abf7346Smrg
2116d36ef34Smrg    /* Move child and v_bar to correct location. */
2126d36ef34Smrg    if (sblw->scroll.use_right) {
2136d36ef34Smrg        XtMoveWidget(bar, width - (bar->core.width + bar_bw), -bar_bw);
2146d36ef34Smrg        sblw->scroll.offset = 0;
2156d36ef34Smrg    }
2166d36ef34Smrg    else {
2176d36ef34Smrg        XtMoveWidget(bar, -bar_bw, -bar_bw);
2186d36ef34Smrg        sblw->scroll.offset = bar->core.width + bar_bw;
2196d36ef34Smrg    }
2201abf7346Smrg
2216d36ef34Smrg    /* resize the scrollbar to be the correct height or width. */
2226d36ef34Smrg    XtResizeWidget(bar, bar->core.width, height, bar->core.border_width);
2231abf7346Smrg
2246d36ef34Smrg    SetThumbHeight(w);
2251abf7346Smrg
2266d36ef34Smrg    sblw->scroll.num_visible_lines = height / sblw->scroll.font_height + 1;
2271abf7346Smrg}
2281abf7346Smrg
2291abf7346Smrg/* ARGSUSED */
2306d36ef34Smrgstatic void
2316d36ef34SmrgGExpose(Widget w, XtPointer junk, XEvent * event, Boolean * cont)
2321abf7346Smrg{
2331abf7346Smrg
2341abf7346Smrg/*
2351abf7346Smrg * Graphics exposure events are not currently sent to exposure proc.
2361abf7346Smrg */
2371abf7346Smrg
2386d36ef34Smrg    if (event->type == GraphicsExpose)
2396d36ef34Smrg        Redisplay(w, event, NULL);
2401abf7346Smrg
2416d36ef34Smrg}                               /* ChildExpose */
2421abf7346Smrg
2431abf7346Smrg/*
2441abf7346Smrg * Repaint the widget's child Window Widget.
2451abf7346Smrg */
2461abf7346Smrg
2471abf7346Smrg/* ARGSUSED */
2481abf7346Smrgstatic void
2496d36ef34SmrgRedisplay(Widget w, XEvent * event, Region region)
2501abf7346Smrg{
2516d36ef34Smrg    int top, height;            /* the locations of the top and height
2526d36ef34Smrg                                   of the region that needs to be repainted. */
2536d36ef34Smrg
2541abf7346Smrg/*
2556d36ef34Smrg * This routine tells the client which sections of the window to
2561abf7346Smrg * repaint in his callback function which does the actual repainting.
2571abf7346Smrg */
2581abf7346Smrg
2596d36ef34Smrg    if (event->type == Expose) {
2606d36ef34Smrg        top = event->xexpose.y;
2616d36ef34Smrg        height = event->xexpose.height;
2626d36ef34Smrg    }
2636d36ef34Smrg    else {
2646d36ef34Smrg        top = event->xgraphicsexpose.y;
2656d36ef34Smrg        height = event->xgraphicsexpose.height;
2666d36ef34Smrg    }
2676d36ef34Smrg
2686d36ef34Smrg    PaintText(w, top, height);
2696d36ef34Smrg}                               /* redisplay (expose) */
2701abf7346Smrg
2711abf7346Smrg/*	Function Name: PaintText
2721abf7346Smrg *	Description: paints the text at the give location for a given height.
2731abf7346Smrg *	Arguments: w - the sbl widget.
2741abf7346Smrg *                 y_loc, height - location and size of area to paint.
2751abf7346Smrg *	Returns: none
2761abf7346Smrg */
2771abf7346Smrg
2781abf7346Smrgstatic void
2791abf7346SmrgPaintText(Widget w, int y_loc, int height)
2801abf7346Smrg{
2816d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
2826d36ef34Smrg    int start_line, location;
2836d36ef34Smrg
2846d36ef34Smrg    start_line = y_loc / sblw->scroll.font_height + sblw->scroll.line_pointer;
2851abf7346Smrg
2866d36ef34Smrg    if (start_line >= sblw->scroll.lines)
2876d36ef34Smrg        return;
2881abf7346Smrg
2891abf7346Smrg/*
2906d36ef34Smrg * Only integer arithmetic makes this possible.
2911abf7346Smrg */
2921abf7346Smrg
2936d36ef34Smrg    location = y_loc / sblw->scroll.font_height * sblw->scroll.font_height;
2941abf7346Smrg
2956d36ef34Smrg    PrintText(w, start_line, sblw->scroll.num_visible_lines, location);
2966d36ef34Smrg}
2971abf7346Smrg
2981abf7346Smrg/*	Function Name: Page
2996d36ef34Smrg *	Description: This function pages the widget, by the amount it receives
3001abf7346Smrg *                   from the translation Manager.
3011abf7346Smrg *	Arguments: w - the ScrollByLineWidget.
3021abf7346Smrg *                 event - the event that caused this return.
3031abf7346Smrg *                 params - the parameters passed to it.
3041abf7346Smrg *                 num_params - the number of parameters.
3051abf7346Smrg *	Returns: none.
3061abf7346Smrg */
3071abf7346Smrg
3081abf7346Smrg/* ARGSUSED */
3096d36ef34Smrgstatic void
3106d36ef34SmrgPage(Widget w, XEvent * event, String * params, Cardinal * num_params)
3111abf7346Smrg{
3126d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
3136d36ef34Smrg    Widget bar = sblw->scroll.bar;
3141abf7346Smrg
3156d36ef34Smrg    if (*num_params < 1)
3166d36ef34Smrg        return;
3171abf7346Smrg/*
3181abf7346Smrg * If no scroll bar is visible then do not page, as the entire window is shown,
3196d36ef34Smrg * or scrolling has been turned off.
3201abf7346Smrg */
3211abf7346Smrg
3226d36ef34Smrg    if (bar == (Widget) NULL)
3236d36ef34Smrg        return;
3246d36ef34Smrg
3256d36ef34Smrg    switch (params[0][0]) {
3266d36ef34Smrg    case 'f':
3276d36ef34Smrg    case 'F':
3286d36ef34Smrg        /* move one page forward */
3296d36ef34Smrg        VerticalScroll(bar, NULL, (XtPointer) ((long) bar->core.height));
3306d36ef34Smrg        break;
3316d36ef34Smrg    case 'b':
3326d36ef34Smrg    case 'B':
3336d36ef34Smrg        /* move one page backward */
3346d36ef34Smrg        VerticalScroll(bar, NULL, (XtPointer) (-(long) bar->core.height));
3356d36ef34Smrg        break;
3366d36ef34Smrg    case 'L':
3376d36ef34Smrg    case 'l':
3386d36ef34Smrg        /* move one line forward */
3396d36ef34Smrg        VerticalScroll(bar, NULL,
3406d36ef34Smrg                       (XtPointer) ((long) atoi(params[1]) *
3416d36ef34Smrg                                    sblw->scroll.font_height));
3426d36ef34Smrg        break;
3436d36ef34Smrg    default:
3446d36ef34Smrg        return;
3456d36ef34Smrg    }
3461abf7346Smrg}
3471abf7346Smrg
3481abf7346Smrg/*	Function Name: CreateScrollbar
3491abf7346Smrg *	Description: createst the scrollbar for us.
3501abf7346Smrg *	Arguments: w - sblw widget.
3511abf7346Smrg *	Returns: none.
3521abf7346Smrg */
3531abf7346Smrg
3541abf7346Smrgstatic void
3551abf7346SmrgCreateScrollbar(Widget w)
3561abf7346Smrg{
3576d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
3586d36ef34Smrg    Arg args[5];
3596d36ef34Smrg    Cardinal num_args = 0;
3606d36ef34Smrg
3616d36ef34Smrg    if (sblw->scroll.bar != NULL)
3626d36ef34Smrg        return;
3636d36ef34Smrg
3646d36ef34Smrg    XtSetArg(args[num_args], XtNorientation, XtorientVertical);
3656d36ef34Smrg    num_args++;
3666d36ef34Smrg
3676d36ef34Smrg    sblw->scroll.bar = XtCreateWidget("scrollbar", scrollbarWidgetClass, w,
3686d36ef34Smrg                                      args, num_args);
3696d36ef34Smrg    XtAddCallback(sblw->scroll.bar, XtNscrollProc, VerticalScroll, NULL);
3706d36ef34Smrg    XtAddCallback(sblw->scroll.bar, XtNjumpProc, VerticalJump, NULL);
3711abf7346Smrg}
3721abf7346Smrg
3731abf7346Smrg/*	Function Name: ScrollVerticalText
3741abf7346Smrg *	Description: This accomplished the actual movement of the text.
3751abf7346Smrg *	Arguments: w - the ScrollByLine Widget.
3761abf7346Smrg *                 new_line - the new location for the line pointer
3776d36ef34Smrg *                 force_redisplay - should we force this window to get
3781abf7346Smrg *                                   redisplayed?
3791abf7346Smrg *	Returns: True if the thumb needs to be moved.
3801abf7346Smrg */
3811abf7346Smrg
3821abf7346Smrgstatic Boolean
3836d36ef34SmrgScrollVerticalText(Widget w, int new_line, Boolean force_redisp)
3841abf7346Smrg{
3856d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
3866d36ef34Smrg    int num_lines = sblw->scroll.num_visible_lines;
3876d36ef34Smrg    int max_lines, old_line;
3886d36ef34Smrg    Boolean move_thumb = FALSE;
3891abf7346Smrg
3901abf7346Smrg/*
3911abf7346Smrg * Do not let the window extend out of bounds.
3921abf7346Smrg */
3931abf7346Smrg
3946d36ef34Smrg    if (new_line < 0) {
3956d36ef34Smrg        new_line = 0;
3966d36ef34Smrg        move_thumb = TRUE;
3976d36ef34Smrg    }
3986d36ef34Smrg    else {
3996d36ef34Smrg        max_lines = sblw->scroll.lines -
4006d36ef34Smrg            (int) w->core.height / sblw->scroll.font_height;
4016d36ef34Smrg        if (max_lines < 0)
4026d36ef34Smrg            max_lines = 0;
4036d36ef34Smrg
4046d36ef34Smrg        if (new_line > max_lines) {
4056d36ef34Smrg            new_line = max_lines;
4066d36ef34Smrg            move_thumb = TRUE;
4076d36ef34Smrg        }
4081abf7346Smrg    }
4091abf7346Smrg
4106d36ef34Smrg/*
4111abf7346Smrg * If forced to redisplay then do a full redisplay and return.
4121abf7346Smrg */
4131abf7346Smrg
4146d36ef34Smrg    old_line = sblw->scroll.line_pointer;
4156d36ef34Smrg    sblw->scroll.line_pointer = new_line;       /* Set current top of page. */
4161abf7346Smrg
4176d36ef34Smrg    if (force_redisp)
4186d36ef34Smrg        MoveAndClearText(w, 0, /* cause a full redisplay */ 0, 0);
4191abf7346Smrg
4206d36ef34Smrg    if (new_line == old_line)
4216d36ef34Smrg        return (move_thumb);
4221abf7346Smrg
4231abf7346Smrg/*
4241abf7346Smrg * Scroll forward.
4251abf7346Smrg */
4261abf7346Smrg
4276d36ef34Smrg    else if (new_line < old_line) {
4286d36ef34Smrg        int lines_to_scroll = old_line - new_line;
4296d36ef34Smrg        MoveAndClearText(w, 0, num_lines - lines_to_scroll, lines_to_scroll);
4306d36ef34Smrg    }
4311abf7346Smrg
4326d36ef34Smrg/*
4331abf7346Smrg * Scroll back.
4341abf7346Smrg */
4351abf7346Smrg
4366d36ef34Smrg    else {
4376d36ef34Smrg        int lines_to_scroll = new_line - old_line;
4386d36ef34Smrg        MoveAndClearText(w, lines_to_scroll, num_lines - lines_to_scroll, 0);
4396d36ef34Smrg    }
4401abf7346Smrg
4416d36ef34Smrg    return (move_thumb);
4421abf7346Smrg}
4431abf7346Smrg
4441abf7346Smrg/*	Function Name: MoveAndClearText
4451abf7346Smrg *	Description: Blits as much text as it can and clear the
4461abf7346Smrg *                   remaining area with generate exposures TRUE.
4471abf7346Smrg *	Arguments: w - the sbl widget.
4481abf7346Smrg *                 old_y - the old y position.
4491abf7346Smrg *                 height - height of area to move.
4501abf7346Smrg *                 new_y - new y position.
4511abf7346Smrg *	Returns: none
4521abf7346Smrg */
4536d36ef34Smrg
4541abf7346Smrgstatic void
4551abf7346SmrgMoveAndClearText(Widget w, int old_y, int height, int new_y)
4561abf7346Smrg{
4576d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
4586d36ef34Smrg    int from_left = sblw->scroll.indent + sblw->scroll.offset - 1;
4596d36ef34Smrg    int y_clear;
4601abf7346Smrg
4616d36ef34Smrg    old_y *= sblw->scroll.font_height;
4626d36ef34Smrg    new_y *= sblw->scroll.font_height;
4636d36ef34Smrg    height *= sblw->scroll.font_height;
4641abf7346Smrg
4651abf7346Smrg/*
4661abf7346Smrg * If we are already at the right location then do nothing.
4671abf7346Smrg * (height == 0).
4681abf7346Smrg *
4691abf7346Smrg * If we have scrolled more than a screen height then just clear
4701abf7346Smrg * the window.
4711abf7346Smrg */
4721abf7346Smrg
4736d36ef34Smrg    if (height <= sblw->scroll.font_height) {   /* avoid rounding errors. */
4746d36ef34Smrg        XClearArea(XtDisplay(w), XtWindow(w), from_left, 0,
4756d36ef34Smrg                   (unsigned int) 0, (unsigned int) 0, FALSE);
4766d36ef34Smrg        PaintText(w, 0, (int) sblw->core.height);
4776d36ef34Smrg        return;
4786d36ef34Smrg    }
4796d36ef34Smrg
4806d36ef34Smrg    if ((int) height + (int) old_y > (int) w->core.height)
4816d36ef34Smrg        height = w->core.height - old_y;
4826d36ef34Smrg
4836d36ef34Smrg    XCopyArea(XtDisplay(w), XtWindow(w), XtWindow(w), sblw->scroll.move_gc,
4846d36ef34Smrg              from_left, old_y,
4856d36ef34Smrg              (unsigned int) w->core.width - from_left, (unsigned int) height,
4866d36ef34Smrg              from_left, new_y);
4876d36ef34Smrg
4886d36ef34Smrg    if (old_y > new_y)
4896d36ef34Smrg        height -= sblw->scroll.font_height / 2; /* clear 1/2 font of extra space,
4906d36ef34Smrg                                                   to make sure we don't lose or
4916d36ef34Smrg                                                   gain descenders. */
4926d36ef34Smrg    else
4936d36ef34Smrg        height -= sblw->scroll.font_height;     /* clear 1 font of extra space,
4946d36ef34Smrg                                                   to make sure we don't overwrite
4956d36ef34Smrg                                                   with a last line in buffer. */
4966d36ef34Smrg
4976d36ef34Smrg    if (old_y > new_y)
4986d36ef34Smrg        y_clear = height;
4996d36ef34Smrg    else
5006d36ef34Smrg        y_clear = 0;
5016d36ef34Smrg
5021abf7346Smrg/*
5031abf7346Smrg * We cannot use generate exposures, since that may allow another move and
5041abf7346Smrg * clear before the area get repainted, this would be bad.
5051abf7346Smrg */
5061abf7346Smrg
5076d36ef34Smrg    XClearArea(XtDisplay(w), XtWindow(w), from_left, y_clear,
5086d36ef34Smrg               (unsigned int) 0, (unsigned int) (w->core.height - height),
5096d36ef34Smrg               FALSE);
5106d36ef34Smrg    PaintText(w, (int) y_clear, (int) (w->core.height - height));
5111abf7346Smrg}
5121abf7346Smrg
5131abf7346Smrg/*	Function Name: SetThumbHeight
5141abf7346Smrg *	Description: Set the height of the thumb.
5151abf7346Smrg *	Arguments: w - the sblw widget.
5161abf7346Smrg *	Returns: none
5171abf7346Smrg */
5181abf7346Smrg
5191abf7346Smrgstatic void
5201abf7346SmrgSetThumbHeight(Widget w)
5211abf7346Smrg{
5226d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
5236d36ef34Smrg    float shown;
5241abf7346Smrg
5256d36ef34Smrg    if (sblw->scroll.bar == NULL)
5266d36ef34Smrg        return;
5271abf7346Smrg
5286d36ef34Smrg    if (sblw->scroll.lines == 0)
5296d36ef34Smrg        shown = 1.0;
5306d36ef34Smrg    else
5316d36ef34Smrg        shown = (float) w->core.height / (float) (sblw->scroll.lines *
5326d36ef34Smrg                                                  sblw->scroll.font_height);
5336d36ef34Smrg    if (shown > 1.0)
5346d36ef34Smrg        shown = 1.0;
5351abf7346Smrg
5366d36ef34Smrg    XawScrollbarSetThumb(sblw->scroll.bar, (float) -1, shown);
5371abf7346Smrg}
5381abf7346Smrg
5391abf7346Smrg/*	Function Name: SetThumb
5401abf7346Smrg *	Description: Set the thumb location.
5411abf7346Smrg *	Arguments: w - the sblw.
5421abf7346Smrg *	Returns: none
5431abf7346Smrg */
5441abf7346Smrg
5451abf7346Smrgstatic void
5461abf7346SmrgSetThumb(Widget w)
5471abf7346Smrg{
5486d36ef34Smrg    float location;
5496d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
5501abf7346Smrg
5516d36ef34Smrg    if ((sblw->scroll.lines == 0) || (sblw->scroll.bar == NULL))
5526d36ef34Smrg        return;
5531abf7346Smrg
5546d36ef34Smrg    location = (float) sblw->scroll.line_pointer / (float) sblw->scroll.lines;
5556d36ef34Smrg    XawScrollbarSetThumb(sblw->scroll.bar, location, (float) -1);
5561abf7346Smrg}
5571abf7346Smrg
5581abf7346Smrg/*	Function Name: VerticalJump.
5591abf7346Smrg *	Description: This function moves the test
5601abf7346Smrg *                   as the vertical scroll bar is moved.
5611abf7346Smrg *	Arguments: w - the scrollbar widget.
5621abf7346Smrg *                 junk - not used.
5631abf7346Smrg *                 percent - the position of the scrollbar.
5641abf7346Smrg *	Returns: none.
5651abf7346Smrg */
5661abf7346Smrg
5671abf7346Smrg/* ARGSUSED */
5681abf7346Smrgstatic void
5691abf7346SmrgVerticalJump(Widget w, XtPointer junk, XtPointer percent_ptr)
5701abf7346Smrg{
5716d36ef34Smrg    float percent = *((float *) percent_ptr);
5726d36ef34Smrg    int new_line;               /* The new location for the line pointer. */
5736d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) XtParent(w);
5741abf7346Smrg
5756d36ef34Smrg    new_line = (int) ((float) sblw->scroll.lines * percent);
5766d36ef34Smrg    if (ScrollVerticalText((Widget) sblw, new_line, FALSE))
5776d36ef34Smrg        SetThumb((Widget) sblw);
5781abf7346Smrg}
5791abf7346Smrg
5801abf7346Smrg/*	Function Name: VerticalScroll
5816d36ef34Smrg *	Description: This function moves the position of the interior window
5821abf7346Smrg *                   as the vertical scroll bar is moved.
5831abf7346Smrg *	Arguments: w - the scrollbar widget.
5841abf7346Smrg *                 junk - not used.
5851abf7346Smrg *                 pos - the position of the cursor.
5861abf7346Smrg *	Returns: none.
5871abf7346Smrg */
5881abf7346Smrg
5891abf7346Smrg/* ARGSUSED */
5901abf7346Smrgstatic void
5911abf7346SmrgVerticalScroll(Widget w, XtPointer client_data, XtPointer call_data)
5921abf7346Smrg{
5936d36ef34Smrg    int pos = (int) (long) call_data;
5946d36ef34Smrg    int new_line;               /* The new location for the line pointer. */
5956d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) XtParent(w);
5961abf7346Smrg
5976d36ef34Smrg    new_line = sblw->scroll.line_pointer + (pos / sblw->scroll.font_height);
5986d36ef34Smrg    (void) ScrollVerticalText((Widget) sblw, new_line, FALSE);
5996d36ef34Smrg    SetThumb((Widget) sblw);
6001abf7346Smrg}
6011abf7346Smrg
6021abf7346Smrg/* ARGSUSED */
6036d36ef34Smrgstatic void
6046d36ef34SmrgInitialize(Widget req, Widget new, ArgList args, Cardinal * num_args)
6051abf7346Smrg{
6066d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) new;
6076d36ef34Smrg    unsigned long figWidth;
6086d36ef34Smrg    Atom atomNum;
6091abf7346Smrg
6106d36ef34Smrg    sblw->scroll.top_line = NULL;
6116d36ef34Smrg    sblw->scroll.line_pointer = 0;
6126d36ef34Smrg    LoadFile(new);
6136d36ef34Smrg    sblw->scroll.bar = (Widget) NULL;
6141abf7346Smrg
6156d36ef34Smrg    sblw->scroll.font_height = (sblw->scroll.normal_font->max_bounds.ascent +
6166d36ef34Smrg                                sblw->scroll.normal_font->max_bounds.descent);
6171abf7346Smrg
6186d36ef34Smrg    atomNum = XInternAtom(XtDisplay(req), "FIGURE_WIDTH", False);
6191abf7346Smrg
6206d36ef34Smrg    if (XGetFontProperty(sblw->scroll.normal_font, atomNum, &figWidth))
6216d36ef34Smrg        sblw->scroll.h_width = figWidth;
6226d36ef34Smrg    else
6236d36ef34Smrg        sblw->scroll.h_width = XTextWidth(sblw->scroll.normal_font, "$", 1);
6246d36ef34Smrg}                               /* Initialize. */
6251abf7346Smrg
6261abf7346Smrg/*	Function Name: CreateGCs
6276d36ef34Smrg *	Description: Creates the graphics contexts that we need.
6281abf7346Smrg *	Arguments: w - the sblw.
6291abf7346Smrg *	Returns: none
6301abf7346Smrg */
6311abf7346Smrg
6321abf7346Smrgstatic void
6331abf7346SmrgCreateGCs(Widget w)
6341abf7346Smrg{
6356d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
6366d36ef34Smrg
6376d36ef34Smrg    XtGCMask mask;
6386d36ef34Smrg    XGCValues values;
6391abf7346Smrg
6406d36ef34Smrg    values.graphics_exposures = TRUE;
6416d36ef34Smrg    sblw->scroll.move_gc = XtGetGC(w, GCGraphicsExposures, &values);
6421abf7346Smrg
6436d36ef34Smrg    mask = GCForeground | GCFont;
6446d36ef34Smrg    values.foreground = sblw->scroll.foreground;
6451abf7346Smrg
6466d36ef34Smrg    values.font = sblw->scroll.normal_font->fid;
6476d36ef34Smrg    sblw->scroll.normal_gc = XtGetGC(w, mask, &values);
6481abf7346Smrg
6496d36ef34Smrg    values.font = sblw->scroll.italic_font->fid;
6506d36ef34Smrg    sblw->scroll.italic_gc = XtGetGC(w, mask, &values);
6511abf7346Smrg
6526d36ef34Smrg    values.font = sblw->scroll.bold_font->fid;
6536d36ef34Smrg    sblw->scroll.bold_gc = XtGetGC(w, mask, &values);
6541abf7346Smrg
6556d36ef34Smrg    values.font = sblw->scroll.symbol_font->fid;
6566d36ef34Smrg    sblw->scroll.symbol_gc = XtGetGC(w, mask, &values);
6571abf7346Smrg}
6581abf7346Smrg
6591abf7346Smrg/*	Function Name: DestroyGCs
6601abf7346Smrg *	Description: removes all gcs for this widget.
6611abf7346Smrg *	Arguments: w - the widget.
6621abf7346Smrg *	Returns: none
6631abf7346Smrg */
6641abf7346Smrg
6651abf7346Smrgstatic void
6661abf7346SmrgDestroyGCs(Widget w)
6671abf7346Smrg{
6686d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
6691abf7346Smrg
6706d36ef34Smrg    XtReleaseGC(w, sblw->scroll.normal_gc);
6716d36ef34Smrg    XtReleaseGC(w, sblw->scroll.bold_gc);
6726d36ef34Smrg    XtReleaseGC(w, sblw->scroll.italic_gc);
6736d36ef34Smrg    XtReleaseGC(w, sblw->scroll.move_gc);
6741abf7346Smrg}
6751abf7346Smrg
6761abf7346Smrgstatic void
6776d36ef34SmrgRealize(Widget w, Mask *valueMask, XSetWindowAttributes * attributes)
6781abf7346Smrg{
6796d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
6801abf7346Smrg
6816d36ef34Smrg    CreateScrollbar(w);
6826d36ef34Smrg    CreateGCs(w);
6836d36ef34Smrg    Layout(w);
6846d36ef34Smrg    (*SuperClass->core_class.realize) (w, valueMask, attributes);
6856d36ef34Smrg    XtRealizeWidget(sblw->scroll.bar);  /* realize scrollbar. */
6866d36ef34Smrg    XtMapWidget(sblw->scroll.bar);      /* map scrollbar. */
6871abf7346Smrg
6886d36ef34Smrg    XtAddEventHandler(w, 0, TRUE, GExpose, NULL);       /* Get Graphics Exposures */
6896d36ef34Smrg}                               /* Realize */
6901abf7346Smrg
6911abf7346Smrg/*	Function Name: Destroy
6921abf7346Smrg *	Description: Cleans up when we are killed.
6931abf7346Smrg *	Arguments: w - the widget.
6941abf7346Smrg *	Returns: none
6951abf7346Smrg */
6961abf7346Smrg
6971abf7346Smrgstatic void
6981abf7346SmrgDestroy(Widget w)
6991abf7346Smrg{
7006d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
7011abf7346Smrg
7026d36ef34Smrg    if (sblw->scroll.bar != NULL)
7036d36ef34Smrg        XtDestroyWidget(sblw->scroll.bar);      /* Destroy scrollbar. */
704a5a2a776Smrg    if (sblw->scroll.file != NULL) {
7056d36ef34Smrg        fclose(sblw->scroll.file);
706a5a2a776Smrg        sblw->scroll.file = NULL;
707a5a2a776Smrg    }
708a5a2a776Smrg    LoadFile(w);
7096d36ef34Smrg    DestroyGCs(w);
7101abf7346Smrg}
7111abf7346Smrg
7121abf7346Smrg/*
7131abf7346Smrg *
7141abf7346Smrg * Set Values
7151abf7346Smrg *
7161abf7346Smrg */
7171abf7346Smrg
7181abf7346Smrg/* ARGSUSED */
7196d36ef34Smrgstatic Boolean
7206d36ef34SmrgSetValuesHook(Widget w, ArgList args, Cardinal * num_args)
7211abf7346Smrg{
7226d36ef34Smrg    Boolean ret = TRUE;
7236d36ef34Smrg    Cardinal i;
7246d36ef34Smrg
7256d36ef34Smrg    for (i = 0; i < *num_args; i++) {
7266d36ef34Smrg        if (strcmp(XtNfile, args[i].name) == 0) {
7276d36ef34Smrg            LoadFile(w);
7286d36ef34Smrg            ret = TRUE;
7296d36ef34Smrg        }
7301abf7346Smrg    }
7311abf7346Smrg
7321abf7346Smrg/*
7336d36ef34Smrg * Changing anything else will have strange effects, I don't need it so
7341abf7346Smrg * I didn't code it.
7351abf7346Smrg */
7361abf7346Smrg
7376d36ef34Smrg    return (ret);
7381abf7346Smrg
7396d36ef34Smrg}                               /* Set Values */
7401abf7346Smrg
7416d36ef34Smrg/*
7426d36ef34Smrg * A little design philosophy is probably wise to include at this point.
7431abf7346Smrg *
7441abf7346Smrg * One of the things that I has hoped to achieve with xman is to make the
7451abf7346Smrg * viewing of manpage not only easy for the nieve user, but also fast for
7461abf7346Smrg * the experienced user, I wanted to be able to use it too.  To achieve this
7471abf7346Smrg * I end up sacrificing a bit of start up time for the manual data structure.
7486d36ef34Smrg * As well as, the overhead of reading the entire file before putting it up
7491abf7346Smrg * on the display.  This is actually hardly even noticeable since most manual
7501abf7346Smrg * pages are shots, one to two pages - the notable exception is of course csh,
7516d36ef34Smrg * but then that should be broken up anyway.
7521abf7346Smrg *
7531abf7346Smrg * METHOD:
7541abf7346Smrg *
7551abf7346Smrg * I allocate a chunk of space that is the size of the file, plus a null for
7566d36ef34Smrg * debugging.  Then copies the file into this chunk of memory. I then allocate
7571abf7346Smrg * an array of char*'s that are assigned to the beginning of each line.  Yes,
7586d36ef34Smrg * this means that I have to read the file twice, and could probably be more
7591abf7346Smrg * clever about it, but once it is in memory the second read is damn fast.
7606d36ef34Smrg * There are a few obscurities here about guessing the number of lines and
7616d36ef34Smrg * reallocing if I guess wrong, but other than that it is pretty straight
7621abf7346Smrg * forward.
7631abf7346Smrg *
7641abf7346Smrg *                                         Chris Peterson
7651abf7346Smrg *                                         1/27/88
7661abf7346Smrg */
7671abf7346Smrg
7686d36ef34Smrg#define ADD_MORE_MEM 100        /* first guesses for allocations. */
7691abf7346Smrg#define CHAR_PER_LINE 40
7701abf7346Smrg
7711abf7346Smrg/*	Function Name: LoadFile
7721abf7346Smrg *	Description: Loads the current file into the internal memory.
7731abf7346Smrg *	Arguments: w - the sblw.
7741abf7346Smrg *	Returns: none
7751abf7346Smrg */
7761abf7346Smrg
7771abf7346Smrgstatic void
7781abf7346SmrgLoadFile(Widget w)
7791abf7346Smrg{
7806d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
7816d36ef34Smrg    FILE *file = sblw->scroll.file;
7826d36ef34Smrg
7836d36ef34Smrg    char *page;
7846d36ef34Smrg    char **line_pointer, **top_line;    /* pointers to beginnings of the
7856d36ef34Smrg                                           lines of the file. */
7866d36ef34Smrg    int nlines;                 /* the current number of allocated lines. */
7876d36ef34Smrg    struct stat fileinfo;       /* file information from fstat. */
7886d36ef34Smrg
7896d36ef34Smrg    if (sblw->scroll.top_line != NULL) {
7906d36ef34Smrg        XtFree(*(sblw->scroll.top_line));       /* free characters. */
7916d36ef34Smrg        XtFree((char *) (sblw->scroll.top_line));       /* free lines. */
7926d36ef34Smrg    }
7936d36ef34Smrg    sblw->scroll.top_line = NULL;
7941abf7346Smrg
7956d36ef34Smrg    if (file == NULL)
7966d36ef34Smrg        return;
7971abf7346Smrg
7981abf7346Smrg/*
7996d36ef34Smrg * Get file size and allocate a chunk of memory for the file to be
8001abf7346Smrg * copied into.
8011abf7346Smrg */
8021abf7346Smrg
8036d36ef34Smrg    if (fstat(fileno(file), &fileinfo))
8046d36ef34Smrg        XtAppError(XtWidgetToApplicationContext(w),
8056d36ef34Smrg                   "SBLW LoadFile: Failure in fstat.");
8061abf7346Smrg
807a5a2a776Smrg/*
808a5a2a776Smrg * The XtMalloc below is limited to a size of int by the libXt API.
809a5a2a776Smrg */
810a5a2a776Smrg    if (fileinfo.st_size >= INT_MAX)
811a5a2a776Smrg        XtAppError(XtWidgetToApplicationContext(w),
812a5a2a776Smrg                   "SBLW LoadFile: File too large.");
813a5a2a776Smrg
8146d36ef34Smrg/*
8151abf7346Smrg * Allocate a space for a list of pointer to the beginning of each line.
8161abf7346Smrg */
8171abf7346Smrg
8186d36ef34Smrg    if ((nlines = fileinfo.st_size / CHAR_PER_LINE) == 0)
8196d36ef34Smrg        return;
8201abf7346Smrg
8216d36ef34Smrg    page = XtMalloc(fileinfo.st_size + 1);      /* leave space for the NULL */
8226d36ef34Smrg    top_line = line_pointer = (char **) XtMalloc(nlines * sizeof(char *));
8231abf7346Smrg
8241abf7346Smrg/*
8256d36ef34Smrg * Copy the file into memory.
8261abf7346Smrg */
8271abf7346Smrg
8286d36ef34Smrg    fseek(file, 0L, SEEK_SET);
8296d36ef34Smrg    if (fread(page, sizeof(char), fileinfo.st_size, file) == 0)
8306d36ef34Smrg        XtAppError(XtWidgetToApplicationContext(w),
8316d36ef34Smrg                   "SBLW LoadFile: Failure in fread.");
8321abf7346Smrg
8331abf7346Smrg/* put NULL at end of buffer. */
8341abf7346Smrg
8356d36ef34Smrg    *(page + fileinfo.st_size) = '\0';
8361abf7346Smrg
8371abf7346Smrg/*
8386d36ef34Smrg * Go through the file setting a line pointer to the character after each
8391abf7346Smrg * new line.  If we run out of line pointer space then realloc that space
8401abf7346Smrg * with space for more lines.
8411abf7346Smrg */
8421abf7346Smrg
8436d36ef34Smrg    *line_pointer++ = page;     /* first line points to first char in buffer. */
8446d36ef34Smrg    while (*page != '\0') {
8456d36ef34Smrg
8466d36ef34Smrg        if (*page == '\n') {
8476d36ef34Smrg            *line_pointer++ = page + 1;
8486d36ef34Smrg
8496d36ef34Smrg            if (line_pointer >= top_line + nlines) {
8506d36ef34Smrg                top_line = (char **) XtRealloc((char *) top_line, (nlines +
8516d36ef34Smrg                                                                   ADD_MORE_MEM)
8526d36ef34Smrg                                               * sizeof(char *));
8536d36ef34Smrg                line_pointer = top_line + nlines;
8546d36ef34Smrg                nlines += ADD_MORE_MEM;
8556d36ef34Smrg            }
8566d36ef34Smrg        }
8576d36ef34Smrg        page++;
8581abf7346Smrg    }
8596d36ef34Smrg
8601abf7346Smrg/*
8611abf7346Smrg *  Realloc the line pointer space to take only the minimum amount of memory
8621abf7346Smrg */
8631abf7346Smrg
8646d36ef34Smrg    sblw->scroll.lines = nlines = line_pointer - top_line - 1;
8656d36ef34Smrg    top_line = (char **) XtRealloc((char *) top_line, nlines * sizeof(char *));
8661abf7346Smrg
8671abf7346Smrg/*
8681abf7346Smrg * Store the memory pointers
8691abf7346Smrg */
8701abf7346Smrg
8716d36ef34Smrg    sblw->scroll.top_line = top_line;
8726d36ef34Smrg    sblw->scroll.line_pointer = 0;
8736d36ef34Smrg    SetThumbHeight(w);
8746d36ef34Smrg    SetThumb(w);
8751abf7346Smrg}
8761abf7346Smrg
8776d36ef34Smrg#define NLINES  66              /* This is the number of lines to wait until
8786d36ef34Smrg                                   we boldify the line again, this allows
8796d36ef34Smrg                                   me to bold the first line of each page. */
8806d36ef34Smrg#define BACKSPACE 010           /* I doubt you would want to change this. */
8811abf7346Smrg
8821abf7346Smrg#define NORMAL	0
8831abf7346Smrg#define BOLD	1
8841abf7346Smrg#define ITALIC	2
8851abf7346Smrg#define SYMBOL	3
8861abf7346Smrg#define WHICH(italic, bold)	((bold) ? BOLD : ((italic) ? ITALIC : NORMAL))
8876d36ef34Smrg                                /* Choose BOLD over ITALICS.  If neither */
8886d36ef34Smrg                                /* is chosen, use NORMAL. */
8891abf7346Smrg
8906d36ef34Smrgstatic int DumpText(Widget w, int x_loc, int y_loc, char *buf, int len,
8916d36ef34Smrg                    int format);
8921abf7346Smrgstatic Boolean Boldify(char *);
8931abf7346Smrg
8941abf7346Smrg/*	Function Name: PrintText
8951abf7346Smrg *	Description: This function actually prints the text.
8961abf7346Smrg *	Arguments: w - the ScrollByLine widget.
8971abf7346Smrg *                 start_line - line to start printing,
8981abf7346Smrg *                 num_lines - the number of lines to print.
8991abf7346Smrg *                 location - the location to print the text.
9001abf7346Smrg *	Returns: none.
9011abf7346Smrg */
9021abf7346Smrg
9031abf7346Smrg/* ARGSUSED */
9041abf7346Smrgstatic void
9051abf7346SmrgPrintText(Widget w, int start_line, int num_lines, int location)
9061abf7346Smrg{
9076d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
9081abf7346Smrg
9096d36ef34Smrg    register char *bufp, *c;    /* Generic char pointers */
9106d36ef34Smrg    int current_line;           /* the number of the current line */
9116d36ef34Smrg    char buf[BUFSIZ];           /* Misc. characters */
9126d36ef34Smrg    Boolean italicflag = FALSE; /* Print text in italics?? */
9136d36ef34Smrg    Boolean first = TRUE;       /* First line of a manual page??? */
9146d36ef34Smrg    int x_loc, y_loc;           /* x and y location of text. */
9151abf7346Smrg
9161abf7346Smrg/*
9171abf7346Smrg * For table hack
9181abf7346Smrg * To get columns to line up reasonably in most cases, make the
9191abf7346Smrg * assumption that they were lined up using lots of spaces, where
9201abf7346Smrg * lots is greater than two. Use a space width of 70% of the
9211abf7346Smrg * widest character in the font.
9221abf7346Smrg */
9236d36ef34Smrg    int h_col, h_fix;
9246d36ef34Smrg    char *h_c;
9251abf7346Smrg
9261abf7346Smrg/*
9271abf7346Smrg * Nothing loaded, take no action.
9281abf7346Smrg */
9291abf7346Smrg
9306d36ef34Smrg    if (sblw->scroll.top_line == NULL || num_lines == 0)
9316d36ef34Smrg        return;
9321abf7346Smrg
9336d36ef34Smrg    current_line = start_line;
9341abf7346Smrg
9351abf7346Smrg/* Set the first character to print at the first line. */
9361abf7346Smrg
9376d36ef34Smrg    c = *(sblw->scroll.top_line + start_line);
9381abf7346Smrg
9391abf7346Smrg/*
9401abf7346Smrg * Because XDrawString uses the bottom of the text as a position
9411abf7346Smrg * reference, add the height from the top of the font to the baseline
9421abf7346Smrg * to the ScollByLine position reference.
9431abf7346Smrg */
9441abf7346Smrg
9456d36ef34Smrg    y_loc = location + sblw->scroll.normal_font->max_bounds.ascent;
9461abf7346Smrg
9471abf7346Smrg/*
9481abf7346Smrg * Ok, here's the more than mildly heuristic man page formatter.
9491abf7346Smrg * We put chars into buf until either a font change or newline
9501abf7346Smrg * occurs (at which time we flush it to the screen.)
9511abf7346Smrg */
9521abf7346Smrg
9536d36ef34Smrg    bufp = buf;
9546d36ef34Smrg    x_loc = sblw->scroll.offset + sblw->scroll.indent;
9556d36ef34Smrg    h_col = 0;
9561abf7346Smrg
9571abf7346Smrg/*
9581abf7346Smrg * A fix:
9591abf7346Smrg * Assume that we are always starting to print on or before the
9601abf7346Smrg * first line of a page, and then prove it if we aren't.
9611abf7346Smrg */
9626d36ef34Smrg    for (h_fix = 1; h_fix <= (start_line % NLINES); h_fix++)
9636d36ef34Smrg        if (**(sblw->scroll.top_line + start_line - h_fix) != '\n') {
9646d36ef34Smrg            first = FALSE;
9656d36ef34Smrg            break;
9666d36ef34Smrg        }
9676d36ef34Smrg
9686d36ef34Smrg    while (TRUE) {
9696d36ef34Smrg        if (current_line % NLINES == 0)
9706d36ef34Smrg            first = TRUE;
9716d36ef34Smrg
9726d36ef34Smrg/*
9731abf7346Smrg * Lets make sure that we do not run out of space in our buffer, making full
9741abf7346Smrg * use of it is not critical since no window will be wide enough to display
9751abf7346Smrg * nearly BUFSIZ characters.
9761abf7346Smrg */
9771abf7346Smrg
9786d36ef34Smrg        if ((bufp - buf) > (BUFSIZ - 10))
9796d36ef34Smrg            /* Toss everything until we find a <CR> or the end of the buffer. */
9806d36ef34Smrg            while ((*c != '\n') && (*c != '\0'))
9816d36ef34Smrg                c++;
9826d36ef34Smrg
9836d36ef34Smrg        switch (*c) {
9841abf7346Smrg
9856d36ef34Smrg        case '\0':             /* If we reach the end of the file then return */
9866d36ef34Smrg            DumpText(w, x_loc, y_loc, buf, bufp - buf,
9876d36ef34Smrg                     WHICH(italicflag, first));
9886d36ef34Smrg            return;
9891abf7346Smrg
9906d36ef34Smrg        case '\n':
9916d36ef34Smrg            if (bufp != buf) {
9926d36ef34Smrg                Boolean bold;
9931abf7346Smrg
9946d36ef34Smrg                *bufp = '\0';   /* for Boldify. */
9956d36ef34Smrg                bold = ((first) || ((x_loc == (sblw->scroll.offset +
9966d36ef34Smrg                                               sblw->scroll.indent)) &&
9976d36ef34Smrg                                    Boldify(buf)));
9981abf7346Smrg
9996d36ef34Smrg                (void) DumpText(w, x_loc, y_loc, buf, bufp - buf,
10006d36ef34Smrg                                WHICH(italicflag, bold));
10011abf7346Smrg
10026d36ef34Smrg                if (bold)
10036d36ef34Smrg                    first = FALSE;
10046d36ef34Smrg            }
10051abf7346Smrg
10066d36ef34Smrg/*
10071abf7346Smrg * If we have painted the required number of lines then we should now return.
10081abf7346Smrg */
10096d36ef34Smrg            if (++current_line == start_line + num_lines)
10106d36ef34Smrg                return;
10111abf7346Smrg
10126d36ef34Smrg            bufp = buf;
10136d36ef34Smrg            italicflag = FALSE;
10146d36ef34Smrg            x_loc = sblw->scroll.offset + sblw->scroll.indent;
10156d36ef34Smrg            h_col = 0;
10166d36ef34Smrg            y_loc += sblw->scroll.font_height;
10176d36ef34Smrg            break;
10181abf7346Smrg
10191abf7346Smrg/*
10201abf7346Smrg * This tab handling code is not very clever it moves the cursor over
10216d36ef34Smrg * to the next boundary of eight (8) spaces, as calculated in width just
10221abf7346Smrg * before the printing loop started.
10231abf7346Smrg */
10241abf7346Smrg
10256d36ef34Smrg        case '\t':             /* TAB */
10266d36ef34Smrg            x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
10276d36ef34Smrg                             WHICH(italicflag, first));
10286d36ef34Smrg            h_col += bufp - buf;
10296d36ef34Smrg            bufp = buf;
10306d36ef34Smrg            italicflag = FALSE;
10316d36ef34Smrg            x_loc = sblw->scroll.offset + sblw->scroll.indent;
10326d36ef34Smrg            h_col = h_col + 8 - (h_col % 8);
10336d36ef34Smrg            x_loc += sblw->scroll.h_width * h_col;
10346d36ef34Smrg            break;
10356d36ef34Smrg
10366d36ef34Smrg        case ' ':
10376d36ef34Smrg            h_c = c + 1;
10386d36ef34Smrg            while (*h_c == ' ')
10396d36ef34Smrg                h_c++;
10406d36ef34Smrg
10416d36ef34Smrg            if (h_c - c < 4) {
10426d36ef34Smrg                *bufp++ = *c;
10436d36ef34Smrg                break;
10446d36ef34Smrg            }
10456d36ef34Smrg
10466d36ef34Smrg            x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
10476d36ef34Smrg                             WHICH(italicflag, first));
10486d36ef34Smrg            h_col += bufp - buf;
10496d36ef34Smrg            bufp = buf;
10506d36ef34Smrg            italicflag = FALSE;
10516d36ef34Smrg
10526d36ef34Smrg            x_loc = sblw->scroll.offset + sblw->scroll.indent;
10536d36ef34Smrg            h_col += (h_c - c);
10546d36ef34Smrg            x_loc += sblw->scroll.h_width * h_col;
10556d36ef34Smrg            c = h_c - 1;
10566d36ef34Smrg            break;
10576d36ef34Smrg
10586d36ef34Smrg        case '\033':           /* ignore esc sequences for now */
10596d36ef34Smrg            c++;                /* should always be esc-x */
10606d36ef34Smrg            break;
10616d36ef34Smrg
10626d36ef34Smrg/*
10636d36ef34Smrg * Overstrike code supplied by: cs.utexas.edu!ut-emx!clyde@rutgers.edu
10641abf7346Smrg * Since my manual pages do not have overstrike I couldn't test this.
10651abf7346Smrg */
10661abf7346Smrg
10676d36ef34Smrg        case BACKSPACE:        /* Backspacing for nroff bolding */
10686d36ef34Smrg            if (c[-1] == c[1] && c[1] != BACKSPACE) {   /* overstriking one char */
10696d36ef34Smrg                if (bufp > buf) {
10706d36ef34Smrg                    bufp--;     /* Zap 1st instance of char to bolden */
10716d36ef34Smrg                    x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
10726d36ef34Smrg                                     WHICH(italicflag, FALSE));
10736d36ef34Smrg                    h_col += bufp - buf;
10746d36ef34Smrg                }
10756d36ef34Smrg                bufp = buf;
10766d36ef34Smrg                *bufp++ = c[1];
10776d36ef34Smrg                x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, BOLD);
10786d36ef34Smrg                h_col += bufp - buf;
10796d36ef34Smrg                bufp = buf;
10806d36ef34Smrg                first = FALSE;
10816d36ef34Smrg
10826d36ef34Smrg                /*
10836d36ef34Smrg                 *     Nroff bolding looks like:
10846d36ef34Smrg                 *               C\bC\bC\bCN...
10856d36ef34Smrg                 * c points to ----^      ^
10866d36ef34Smrg                 * it needs to point to --^
10876d36ef34Smrg                 */
10886d36ef34Smrg                while (*c == BACKSPACE && c[-1] == c[1])
10896d36ef34Smrg                    c += 2;
10906d36ef34Smrg                c--;            /* Back up to previous char */
10916d36ef34Smrg            }
10926d36ef34Smrg            else {
10936d36ef34Smrg                if ((c[-1] == 'o' && c[1] == '+')       /* Nroff bullet */
10946d36ef34Smrg                    ||(c[-1] == '+' && c[1] == 'o')) {  /* Nroff bullet */
10956d36ef34Smrg                    /* If we run into a bullet, print out */
10966d36ef34Smrg                    /* everything that's accumulated to this */
10976d36ef34Smrg                    /* point, then the bullet, then resume. */
10986d36ef34Smrg                    if (bufp > buf) {
10996d36ef34Smrg                        bufp--;
11006d36ef34Smrg                        x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
11016d36ef34Smrg                                         WHICH(italicflag, FALSE));
11026d36ef34Smrg                        h_col += bufp - buf;
11036d36ef34Smrg                    }
11046d36ef34Smrg                    bufp = buf;
11056d36ef34Smrg                    *bufp = (char) 183;
11066d36ef34Smrg                    x_loc = DumpText(w, x_loc, y_loc, buf, 1, SYMBOL);
11076d36ef34Smrg                    h_col++;
11086d36ef34Smrg                    c++;
11096d36ef34Smrg                }
11106d36ef34Smrg                else {          /* 'real' backspace - back up output ptr */
11116d36ef34Smrg                    if (bufp > buf)
11126d36ef34Smrg                        bufp--;
11136d36ef34Smrg                }
11146d36ef34Smrg            }
11156d36ef34Smrg            break;
11161abf7346Smrg
11171abf7346Smrg/* End of contributed overstrike code. */
11181abf7346Smrg
11196d36ef34Smrg        case '_':              /* look for underlining [italicize] */
11206d36ef34Smrg            if (*(c + 1) == BACKSPACE) {
11216d36ef34Smrg                if (!italicflag) {      /* font change? */
11226d36ef34Smrg                    if (bufp != buf) {
11236d36ef34Smrg                        x_loc =
11246d36ef34Smrg                            DumpText(w, x_loc, y_loc, buf, bufp - buf, NORMAL);
11256d36ef34Smrg                        h_col += bufp - buf;
11266d36ef34Smrg                        bufp = buf;
11276d36ef34Smrg                    }
11286d36ef34Smrg                    italicflag = TRUE;
11296d36ef34Smrg                }
11306d36ef34Smrg                c += 2;
11316d36ef34Smrg                *bufp++ = *c;
11326d36ef34Smrg                break;
11336d36ef34Smrg            }
1134ae5a67adSmrg            /* else fall through - to default, because this was a real underscore. */
11356d36ef34Smrg
11366d36ef34Smrg        default:
11376d36ef34Smrg            if (italicflag) {   /* font change? */
11386d36ef34Smrg                if (bufp != buf) {
11396d36ef34Smrg                    x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
11406d36ef34Smrg                                     WHICH(italicflag, FALSE));
11416d36ef34Smrg                    h_col += bufp - buf;
11426d36ef34Smrg                    bufp = buf;
11436d36ef34Smrg                }
11446d36ef34Smrg                italicflag = FALSE;
11456d36ef34Smrg            }
11466d36ef34Smrg            *bufp++ = *c;
11476d36ef34Smrg            break;
11486d36ef34Smrg        }
11496d36ef34Smrg        c++;
11501abf7346Smrg    }
11511abf7346Smrg}
11521abf7346Smrg
11531abf7346Smrg/*	Function Name: DumpText
11541abf7346Smrg *	Description: Dumps text to the screen.
11551abf7346Smrg *	Arguments: w - the widget.
11561abf7346Smrg *                 x_loc - to dump text at.
11571abf7346Smrg *                 y_loc - the y_location to draw_text.
11581abf7346Smrg *                 buf - buffer to dump.
11591abf7346Smrg *                 italic, bold, boolean that tells us which gc to use.
11601abf7346Smrg *	Returns: x_location of the end of the text.
11611abf7346Smrg */
11621abf7346Smrg
11631abf7346Smrgstatic int
11646d36ef34SmrgDumpText(Widget w, int x_loc, int y_loc, char *buf, int len, int format)
11651abf7346Smrg{
11666d36ef34Smrg    ScrollByLineWidget sblw = (ScrollByLineWidget) w;
11676d36ef34Smrg    GC gc;
11686d36ef34Smrg    XFontStruct *font;
11696d36ef34Smrg
11706d36ef34Smrg    switch (format) {
11716d36ef34Smrg
11726d36ef34Smrg    case ITALIC:
11736d36ef34Smrg        gc = sblw->scroll.italic_gc;
11746d36ef34Smrg        font = sblw->scroll.italic_font;
11756d36ef34Smrg        break;
11766d36ef34Smrg
11776d36ef34Smrg    case BOLD:
11786d36ef34Smrg        gc = sblw->scroll.bold_gc;
11796d36ef34Smrg        font = sblw->scroll.bold_font;
11806d36ef34Smrg        break;
11816d36ef34Smrg
11826d36ef34Smrg    case SYMBOL:
11836d36ef34Smrg        gc = sblw->scroll.symbol_gc;
11846d36ef34Smrg        font = sblw->scroll.symbol_font;
11856d36ef34Smrg        break;
11866d36ef34Smrg
11876d36ef34Smrg    default:
11886d36ef34Smrg        gc = sblw->scroll.normal_gc;
11896d36ef34Smrg        font = sblw->scroll.normal_font;
11906d36ef34Smrg        break;
11911abf7346Smrg    }
11921abf7346Smrg
11936d36ef34Smrg    XDrawString(XtDisplay(w), XtWindow(w), gc, x_loc, y_loc, buf, len);
11946d36ef34Smrg    return (x_loc + XTextWidth(font, buf, len));
11951abf7346Smrg}
11961abf7346Smrg
11971abf7346Smrg/*	Function Name: Boldify
11981abf7346Smrg *	Description: look for keyword.
11991abf7346Smrg *	Arguments: sp - string pointer.
12001abf7346Smrg *	Returns: 1 if keyword else 0.
12011abf7346Smrg */
12021abf7346Smrg
12031abf7346Smrgstatic Boolean
12041abf7346SmrgBoldify(register char *sp)
12051abf7346Smrg{
12066d36ef34Smrg    register char *sp_pointer;
12076d36ef34Smrg    int length, count;
12081abf7346Smrg
12096d36ef34Smrg/*
12101abf7346Smrg * If there are not lower case letters in the line the assume it is a
12111abf7346Smrg * keyword and boldify it in PrintManpage.
12121abf7346Smrg */
12131abf7346Smrg
12146d36ef34Smrg    length = strlen(sp);
12156d36ef34Smrg    for (sp_pointer = sp, count = 0; count < length; sp_pointer++, count++)
12166d36ef34Smrg        if (!isupper(*sp_pointer) && !isspace(*sp_pointer))
12176d36ef34Smrg            return (0);
12186d36ef34Smrg    return (1);
12191abf7346Smrg}
12201abf7346Smrg
12211abf7346Smrg#undef superclass
12221abf7346Smrg#undef SuperClass
1223