ScrollByL.c revision 1abf7346
11abf7346Smrg/* $XConsortium: ScrollByL.c,v 1.30 94/04/17 20:43:46 rws Exp $ */
21abf7346Smrg/*
31abf7346Smrg
41abf7346SmrgCopyright (c) 1987, 1988  X Consortium
51abf7346Smrg
61abf7346SmrgPermission is hereby granted, free of charge, to any person obtaining
71abf7346Smrga copy of this software and associated documentation files (the
81abf7346Smrg"Software"), to deal in the Software without restriction, including
91abf7346Smrgwithout limitation the rights to use, copy, modify, merge, publish,
101abf7346Smrgdistribute, sublicense, and/or sell copies of the Software, and to
111abf7346Smrgpermit persons to whom the Software is furnished to do so, subject to
121abf7346Smrgthe following conditions:
131abf7346Smrg
141abf7346SmrgThe above copyright notice and this permission notice shall be included
151abf7346Smrgin all copies or substantial portions of the Software.
161abf7346Smrg
171abf7346SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
181abf7346SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
191abf7346SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
201abf7346SmrgIN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
211abf7346SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
221abf7346SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
231abf7346SmrgOTHER DEALINGS IN THE SOFTWARE.
241abf7346Smrg
251abf7346SmrgExcept as contained in this notice, the name of the X Consortium shall
261abf7346Smrgnot be used in advertising or otherwise to promote the sale, use or
271abf7346Smrgother dealings in this Software without prior written authorization
281abf7346Smrgfrom the X Consortium.
291abf7346Smrg
301abf7346Smrg*/
311abf7346Smrg/* $XFree86: xc/programs/xman/ScrollByL.c,v 1.6tsi Exp $ */
321abf7346Smrg
331abf7346Smrg#if !defined(lint) && !defined(SABER) && 0
341abf7346Smrg  static char rcs_version[] = "$Athena: ScrollByL.c,v 4.5 88/12/19 13:46:04 kit Exp $";
351abf7346Smrg#endif
361abf7346Smrg
371abf7346Smrg#include <stdio.h>
381abf7346Smrg#include <ctype.h>
391abf7346Smrg#include <X11/Xos.h>
401abf7346Smrg#include <stdlib.h>
411abf7346Smrg
421abf7346Smrg#include <X11/IntrinsicP.h>
431abf7346Smrg#include <sys/stat.h>		/* depends on IntrinsicP.h */
441abf7346Smrg#include <X11/StringDefs.h>
451abf7346Smrg
461abf7346Smrg#include <X11/Xaw/Scrollbar.h>
471abf7346Smrg#include <X11/Xmu/Misc.h>
481abf7346Smrg
491abf7346Smrg#include "ScrollByLP.h"
501abf7346Smrg
511abf7346Smrg/* Default Translation Table */
521abf7346Smrg
531abf7346Smrgstatic char defaultTranslations[] =
541abf7346Smrg  "<Key>f:      Page(Forward) \n\
551abf7346Smrg   <Key>b:      Page(Back) \n\
561abf7346Smrg   <Key>1:      Page(Line, 1) \n\
571abf7346Smrg   <Key>2:      Page(Line, 2) \n\
581abf7346Smrg   <Key>3:      Page(Line, 3) \n\
591abf7346Smrg   <Key>4:      Page(Line, 4) \n\
601abf7346Smrg   <Key>\\ :    Page(Forward)";
611abf7346Smrg
621abf7346Smrg
631abf7346Smrg/****************************************************************
641abf7346Smrg *
651abf7346Smrg * ScrollByLine Resources
661abf7346Smrg *
671abf7346Smrg ****************************************************************/
681abf7346Smrg
691abf7346Smrg#define Offset(field) XtOffset(ScrollByLineWidget, scroll.field)
701abf7346Smrg#define CoreOffset(field) XtOffset(ScrollByLineWidget, core.field)
711abf7346Smrg
721abf7346Smrgstatic XtResource resources[] = {
731abf7346Smrg    {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
741abf7346Smrg       CoreOffset(width), XtRImmediate, (caddr_t) 500},
751abf7346Smrg    {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
761abf7346Smrg       CoreOffset(height), XtRImmediate, (caddr_t) 700},
771abf7346Smrg
781abf7346Smrg    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
791abf7346Smrg       Offset(foreground), XtRString, "XtDefaultForeground"},
801abf7346Smrg    {XtNforceVert, XtCBoolean, XtRBoolean, sizeof(Boolean),
811abf7346Smrg       Offset(force_vert), XtRImmediate, (caddr_t) FALSE},
821abf7346Smrg    {XtNindent, XtCIndent, XtRDimension, sizeof(Dimension),
831abf7346Smrg       Offset(indent), XtRImmediate, (caddr_t) 15},
841abf7346Smrg    {XtNuseRight, XtCBoolean, XtRBoolean, sizeof(Boolean),
851abf7346Smrg       Offset(use_right), XtRImmediate, (caddr_t) FALSE},
861abf7346Smrg    {XtNmanualFontNormal, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
871abf7346Smrg       Offset(normal_font), XtRString, MANPAGE_NORMAL},
881abf7346Smrg    {XtNmanualFontBold, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
891abf7346Smrg       Offset(bold_font), XtRString, MANPAGE_BOLD},
901abf7346Smrg    {XtNmanualFontItalic, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
911abf7346Smrg       Offset(italic_font), XtRString, MANPAGE_ITALIC},
921abf7346Smrg    {XtNmanualFontSymbol, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
931abf7346Smrg       Offset(symbol_font), XtRString, MANPAGE_SYMBOL},
941abf7346Smrg    {XtNfile, XtCFile, XtRFile, sizeof(FILE *),
951abf7346Smrg       Offset(file), XtRImmediate, (caddr_t) NULL},
961abf7346Smrg    {XtNNumTotalLines, XtCNumTotalLines, XtRInt, sizeof(int),
971abf7346Smrg       Offset(lines), XtRImmediate, (caddr_t) 0},
981abf7346Smrg    {XtNNumVisibleLines, XtCNumVisibleLines, XtRInt, sizeof(int),
991abf7346Smrg       Offset(num_visible_lines), XtRImmediate, (caddr_t) 0},
1001abf7346Smrg};
1011abf7346Smrg
1021abf7346Smrg#undef Offset
1031abf7346Smrg#undef CoreOffset
1041abf7346Smrg
1051abf7346Smrg/****************************************************************
1061abf7346Smrg *
1071abf7346Smrg * Full class record constant
1081abf7346Smrg *
1091abf7346Smrg ****************************************************************/
1101abf7346Smrg
1111abf7346Smrgstatic void CreateScrollbar(Widget w);
1121abf7346Smrgstatic Boolean ScrollVerticalText(Widget w, int new_line, Boolean force_redisp);
1131abf7346Smrgstatic void Layout(Widget w);
1141abf7346Smrgstatic void LoadFile(Widget w);
1151abf7346Smrgstatic void MoveAndClearText(Widget w, int old_y, int height, int new_y);
1161abf7346Smrgstatic void PaintText(Widget w, int y_loc, int height);
1171abf7346Smrgstatic void PrintText(Widget w, int start_line, int num_lines, int location);
1181abf7346Smrgstatic void SetThumbHeight(Widget w);
1191abf7346Smrgstatic void VerticalJump(Widget w, XtPointer junk, XtPointer percent_ptr);
1201abf7346Smrgstatic void VerticalScroll(Widget w, XtPointer client_data, XtPointer call_data);
1211abf7346Smrg
1221abf7346Smrg/* semi - public functions. */
1231abf7346Smrg
1241abf7346Smrgstatic void Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes);
1251abf7346Smrgstatic void Initialize(Widget req, Widget new, ArgList args, Cardinal *num_args);
1261abf7346Smrgstatic void Destroy(Widget w);
1271abf7346Smrgstatic void Redisplay(Widget w, XEvent *event, Region region);
1281abf7346Smrgstatic void Page(Widget w, XEvent * event, String * params, Cardinal *num_params);
1291abf7346Smrgstatic Boolean SetValuesHook(Widget w, ArgList args, Cardinal *num_args);
1301abf7346Smrg
1311abf7346Smrgstatic XtActionsRec actions[] = {
1321abf7346Smrg  { "Page",   Page},
1331abf7346Smrg};
1341abf7346Smrg
1351abf7346Smrg#define superclass		(&simpleClassRec)
1361abf7346Smrg#define SuperClass		simpleWidgetClass
1371abf7346Smrg
1381abf7346SmrgScrollByLineClassRec scrollByLineClassRec = {
1391abf7346Smrg  {
1401abf7346Smrg/* core_class fields      */
1411abf7346Smrg    /* superclass         */    (WidgetClass) superclass,
1421abf7346Smrg    /* class_name         */    "ScrollByLine",
1431abf7346Smrg    /* widget_size        */    sizeof(ScrollByLineRec),
1441abf7346Smrg    /* class_initialize   */    NULL,
1451abf7346Smrg    /* class_part_init    */    NULL,
1461abf7346Smrg    /* class_inited       */	FALSE,
1471abf7346Smrg    /* initialize         */    Initialize,
1481abf7346Smrg    /* initialize_hook    */    NULL,
1491abf7346Smrg    /* realize            */    Realize,
1501abf7346Smrg    /* actions            */    actions,
1511abf7346Smrg    /* num_actions	  */	XtNumber(actions),
1521abf7346Smrg    /* resources          */    resources,
1531abf7346Smrg    /* num_resources      */    XtNumber(resources),
1541abf7346Smrg    /* xrm_class          */    NULLQUARK,
1551abf7346Smrg    /* compress_motion	  */	TRUE,
1561abf7346Smrg    /* compress_exposure  */	FALSE,
1571abf7346Smrg    /* compress_enterleave*/    TRUE,
1581abf7346Smrg    /* visible_interest   */    FALSE,
1591abf7346Smrg    /* destroy            */    Destroy,
1601abf7346Smrg    /* resize             */    Layout,
1611abf7346Smrg    /* expose             */    Redisplay,
1621abf7346Smrg    /* set_values         */    NULL,
1631abf7346Smrg    /* set_values_hook    */    SetValuesHook,
1641abf7346Smrg    /* set_values_almost  */    XtInheritSetValuesAlmost,
1651abf7346Smrg    /* get_values_hook    */    NULL,
1661abf7346Smrg    /* accept_focus       */    NULL,
1671abf7346Smrg    /* version            */    XtVersion,
1681abf7346Smrg    /* callback_private   */    NULL,
1691abf7346Smrg    /* tm_table           */    defaultTranslations,
1701abf7346Smrg    /* query_geometry	  */	XtInheritQueryGeometry,
1711abf7346Smrg    /* display_accelerator*/	XtInheritDisplayAccelerator,
1721abf7346Smrg    /* extension	  */	NULL,
1731abf7346Smrg  },
1741abf7346Smrg  { /* simple fields */
1751abf7346Smrg    /* change_sensitive		*/	XtInheritChangeSensitive
1761abf7346Smrg  }
1771abf7346Smrg};
1781abf7346Smrg
1791abf7346SmrgWidgetClass scrollByLineWidgetClass =
1801abf7346Smrg            (WidgetClass) &scrollByLineClassRec;
1811abf7346Smrg
1821abf7346Smrg
1831abf7346Smrg/****************************************************************
1841abf7346Smrg *
1851abf7346Smrg * Private Routines
1861abf7346Smrg *
1871abf7346Smrg ****************************************************************/
1881abf7346Smrg
1891abf7346Smrg/*	Function Name: Layout
1901abf7346Smrg *	Description: This function lays out the scroll widget.
1911abf7346Smrg *	Arguments: w - the scroll widget.
1921abf7346Smrg *                 key - a boolean: if true then resize the widget to the child
1931abf7346Smrg *                                  if false the resize children to fit widget.
1941abf7346Smrg *	Returns: TRUE if successful.
1951abf7346Smrg */
1961abf7346Smrg
1971abf7346Smrgstatic void
1981abf7346SmrgLayout(Widget w)
1991abf7346Smrg{
2001abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
2011abf7346Smrg  Dimension width, height;
2021abf7346Smrg  Widget bar;
2031abf7346Smrg  Position bar_bw;
2041abf7346Smrg
2051abf7346Smrg  CreateScrollbar(w);
2061abf7346Smrg
2071abf7346Smrg/*
2081abf7346Smrg * For now always show the bar.
2091abf7346Smrg */
2101abf7346Smrg
2111abf7346Smrg  bar = sblw->scroll.bar;
2121abf7346Smrg  height = sblw->core.height;
2131abf7346Smrg  width = sblw->core.width;
2141abf7346Smrg  bar_bw = bar->core.border_width;
2151abf7346Smrg
2161abf7346Smrg  /* Move child and v_bar to correct location. */
2171abf7346Smrg
2181abf7346Smrg  if (sblw->scroll.use_right) {
2191abf7346Smrg    XtMoveWidget(bar, width - (bar->core.width + bar_bw), - bar_bw);
2201abf7346Smrg    sblw->scroll.offset = 0;
2211abf7346Smrg  }
2221abf7346Smrg  else {
2231abf7346Smrg    XtMoveWidget(bar, - bar_bw, - bar_bw);
2241abf7346Smrg    sblw->scroll.offset = bar->core.width + bar_bw;
2251abf7346Smrg  }
2261abf7346Smrg
2271abf7346Smrg  /* resize the scrollbar to be the correct height or width. */
2281abf7346Smrg
2291abf7346Smrg  XtResizeWidget(bar, bar->core.width, height, bar->core.border_width);
2301abf7346Smrg
2311abf7346Smrg  SetThumbHeight(w);
2321abf7346Smrg
2331abf7346Smrg  sblw->scroll.num_visible_lines = height / sblw->scroll.font_height + 1;
2341abf7346Smrg}
2351abf7346Smrg
2361abf7346Smrg/* ARGSUSED */
2371abf7346Smrgstatic void
2381abf7346SmrgGExpose(Widget w, XtPointer junk, XEvent *event, Boolean *cont)
2391abf7346Smrg{
2401abf7346Smrg
2411abf7346Smrg/*
2421abf7346Smrg * Graphics exposure events are not currently sent to exposure proc.
2431abf7346Smrg */
2441abf7346Smrg
2451abf7346Smrg  if (event->type == GraphicsExpose)
2461abf7346Smrg    Redisplay(w, event, NULL);
2471abf7346Smrg
2481abf7346Smrg} /* ChildExpose */
2491abf7346Smrg
2501abf7346Smrg/*
2511abf7346Smrg * Repaint the widget's child Window Widget.
2521abf7346Smrg */
2531abf7346Smrg
2541abf7346Smrg/* ARGSUSED */
2551abf7346Smrgstatic void
2561abf7346SmrgRedisplay(Widget w, XEvent *event, Region region)
2571abf7346Smrg{
2581abf7346Smrg  int top, height;		/* the locations of the top and height
2591abf7346Smrg				   of the region that needs to be repainted. */
2601abf7346Smrg
2611abf7346Smrg/*
2621abf7346Smrg * This routine tells the client which sections of the window to
2631abf7346Smrg * repaint in his callback function which does the actual repainting.
2641abf7346Smrg */
2651abf7346Smrg
2661abf7346Smrg  if (event->type == Expose) {
2671abf7346Smrg    top = event->xexpose.y;
2681abf7346Smrg    height = event->xexpose.height;
2691abf7346Smrg  }
2701abf7346Smrg  else {
2711abf7346Smrg    top = event->xgraphicsexpose.y;
2721abf7346Smrg    height  = event->xgraphicsexpose.height;
2731abf7346Smrg  }
2741abf7346Smrg
2751abf7346Smrg  PaintText(w, top, height);
2761abf7346Smrg} /* redisplay (expose) */
2771abf7346Smrg
2781abf7346Smrg/*	Function Name: PaintText
2791abf7346Smrg *	Description: paints the text at the give location for a given height.
2801abf7346Smrg *	Arguments: w - the sbl widget.
2811abf7346Smrg *                 y_loc, height - location and size of area to paint.
2821abf7346Smrg *	Returns: none
2831abf7346Smrg */
2841abf7346Smrg
2851abf7346Smrgstatic void
2861abf7346SmrgPaintText(Widget w, int y_loc, int height)
2871abf7346Smrg{
2881abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
2891abf7346Smrg  int start_line, location;
2901abf7346Smrg
2911abf7346Smrg  start_line = y_loc / sblw->scroll.font_height + sblw->scroll.line_pointer;
2921abf7346Smrg
2931abf7346Smrg  if (start_line >= sblw->scroll.lines)
2941abf7346Smrg    return;
2951abf7346Smrg
2961abf7346Smrg/*
2971abf7346Smrg * Only integer arithmetic makes this possible.
2981abf7346Smrg */
2991abf7346Smrg
3001abf7346Smrg  location =  y_loc / sblw->scroll.font_height * sblw->scroll.font_height;
3011abf7346Smrg
3021abf7346Smrg  PrintText(w, start_line, sblw->scroll.num_visible_lines, location);
3031abf7346Smrg}
3041abf7346Smrg
3051abf7346Smrg/*	Function Name: Page
3061abf7346Smrg *	Description: This function pages the widget, by the amount it recieves
3071abf7346Smrg *                   from the translation Manager.
3081abf7346Smrg *	Arguments: w - the ScrollByLineWidget.
3091abf7346Smrg *                 event - the event that caused this return.
3101abf7346Smrg *                 params - the parameters passed to it.
3111abf7346Smrg *                 num_params - the number of parameters.
3121abf7346Smrg *	Returns: none.
3131abf7346Smrg */
3141abf7346Smrg
3151abf7346Smrg/* ARGSUSED */
3161abf7346Smrgstatic void
3171abf7346SmrgPage(Widget w, XEvent * event, String * params, Cardinal *num_params)
3181abf7346Smrg{
3191abf7346Smrg   ScrollByLineWidget sblw = (ScrollByLineWidget) w;
3201abf7346Smrg   Widget bar = sblw->scroll.bar;
3211abf7346Smrg
3221abf7346Smrg   if (*num_params < 1)
3231abf7346Smrg     return;
3241abf7346Smrg/*
3251abf7346Smrg * If no scroll bar is visible then do not page, as the entire window is shown,
3261abf7346Smrg * of scrolling has been turned off.
3271abf7346Smrg */
3281abf7346Smrg
3291abf7346Smrg   if (bar == (Widget) NULL)
3301abf7346Smrg     return;
3311abf7346Smrg
3321abf7346Smrg   switch ( params[0][0] ) {
3331abf7346Smrg   case 'f':
3341abf7346Smrg   case 'F':
3351abf7346Smrg     /* move one page forward */
3361abf7346Smrg     VerticalScroll(bar, NULL, (XtPointer)((long) bar->core.height));
3371abf7346Smrg     break;
3381abf7346Smrg   case 'b':
3391abf7346Smrg   case 'B':
3401abf7346Smrg     /* move one page backward */
3411abf7346Smrg     VerticalScroll(bar, NULL,  (XtPointer)(- (long) bar->core.height));
3421abf7346Smrg     break;
3431abf7346Smrg   case 'L':
3441abf7346Smrg   case 'l':
3451abf7346Smrg     /* move one line forward */
3461abf7346Smrg     VerticalScroll(bar, NULL,
3471abf7346Smrg		(XtPointer)((long) atoi(params[1]) * sblw->scroll.font_height));
3481abf7346Smrg     break;
3491abf7346Smrg   default:
3501abf7346Smrg     return;
3511abf7346Smrg   }
3521abf7346Smrg}
3531abf7346Smrg
3541abf7346Smrg/*	Function Name: CreateScrollbar
3551abf7346Smrg *	Description: createst the scrollbar for us.
3561abf7346Smrg *	Arguments: w - sblw widget.
3571abf7346Smrg *	Returns: none.
3581abf7346Smrg */
3591abf7346Smrg
3601abf7346Smrgstatic void
3611abf7346SmrgCreateScrollbar(Widget w)
3621abf7346Smrg{
3631abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
3641abf7346Smrg  Arg args[5];
3651abf7346Smrg  Cardinal num_args = 0;
3661abf7346Smrg
3671abf7346Smrg  if (sblw->scroll.bar != NULL)
3681abf7346Smrg    return;
3691abf7346Smrg
3701abf7346Smrg  XtSetArg(args[num_args], XtNorientation, XtorientVertical); num_args++;
3711abf7346Smrg
3721abf7346Smrg  sblw->scroll.bar = XtCreateWidget("scrollbar", scrollbarWidgetClass, w,
3731abf7346Smrg				    args, num_args);
3741abf7346Smrg  XtAddCallback(sblw->scroll.bar, XtNscrollProc, VerticalScroll, NULL);
3751abf7346Smrg  XtAddCallback(sblw->scroll.bar, XtNjumpProc, VerticalJump, NULL);
3761abf7346Smrg}
3771abf7346Smrg
3781abf7346Smrg/*	Function Name: ScrollVerticalText
3791abf7346Smrg *	Description: This accomplished the actual movement of the text.
3801abf7346Smrg *	Arguments: w - the ScrollByLine Widget.
3811abf7346Smrg *                 new_line - the new location for the line pointer
3821abf7346Smrg *                 force_redisplay - should we force this window to get
3831abf7346Smrg *                                   redisplayed?
3841abf7346Smrg *	Returns: True if the thumb needs to be moved.
3851abf7346Smrg */
3861abf7346Smrg
3871abf7346Smrgstatic Boolean
3881abf7346SmrgScrollVerticalText(
3891abf7346SmrgWidget w,
3901abf7346Smrgint new_line,
3911abf7346SmrgBoolean force_redisp)
3921abf7346Smrg{
3931abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
3941abf7346Smrg  int num_lines = sblw->scroll.num_visible_lines;
3951abf7346Smrg  int max_lines, old_line;
3961abf7346Smrg  Boolean move_thumb = FALSE;
3971abf7346Smrg
3981abf7346Smrg/*
3991abf7346Smrg * Do not let the window extend out of bounds.
4001abf7346Smrg */
4011abf7346Smrg
4021abf7346Smrg  if ( new_line < 0) {
4031abf7346Smrg    new_line = 0;
4041abf7346Smrg    move_thumb = TRUE;
4051abf7346Smrg  }
4061abf7346Smrg  else {
4071abf7346Smrg    max_lines = sblw->scroll.lines - (int)w->core.height / sblw->scroll.font_height;
4081abf7346Smrg    AssignMax(max_lines, 0);
4091abf7346Smrg
4101abf7346Smrg    if ( new_line > max_lines ) {
4111abf7346Smrg      new_line = max_lines;
4121abf7346Smrg      move_thumb = TRUE;
4131abf7346Smrg    }
4141abf7346Smrg  }
4151abf7346Smrg
4161abf7346Smrg/*
4171abf7346Smrg * If forced to redisplay then do a full redisplay and return.
4181abf7346Smrg */
4191abf7346Smrg
4201abf7346Smrg  old_line = sblw->scroll.line_pointer;
4211abf7346Smrg  sblw->scroll.line_pointer = new_line;	/* Set current top of page. */
4221abf7346Smrg
4231abf7346Smrg  if (force_redisp)
4241abf7346Smrg    MoveAndClearText(w, 0, /* cause a full redisplay */ 0, 0);
4251abf7346Smrg
4261abf7346Smrg  if (new_line == old_line)
4271abf7346Smrg    return(move_thumb);
4281abf7346Smrg
4291abf7346Smrg/*
4301abf7346Smrg * Scroll forward.
4311abf7346Smrg */
4321abf7346Smrg
4331abf7346Smrg  else if (new_line < old_line) {
4341abf7346Smrg    int lines_to_scroll = old_line - new_line;
4351abf7346Smrg    MoveAndClearText(w, 0, num_lines - lines_to_scroll, lines_to_scroll);
4361abf7346Smrg  }
4371abf7346Smrg
4381abf7346Smrg/*
4391abf7346Smrg * Scroll back.
4401abf7346Smrg */
4411abf7346Smrg
4421abf7346Smrg  else {
4431abf7346Smrg    int lines_to_scroll = new_line - old_line;
4441abf7346Smrg    MoveAndClearText(w, lines_to_scroll, num_lines - lines_to_scroll, 0);
4451abf7346Smrg  }
4461abf7346Smrg
4471abf7346Smrg  return(move_thumb);
4481abf7346Smrg}
4491abf7346Smrg
4501abf7346Smrg/*	Function Name: MoveAndClearText
4511abf7346Smrg *	Description: Blits as much text as it can and clear the
4521abf7346Smrg *                   remaining area with generate exposures TRUE.
4531abf7346Smrg *	Arguments: w - the sbl widget.
4541abf7346Smrg *                 old_y - the old y position.
4551abf7346Smrg *                 height - height of area to move.
4561abf7346Smrg *                 new_y - new y position.
4571abf7346Smrg *	Returns: none
4581abf7346Smrg */
4591abf7346Smrg
4601abf7346Smrgstatic void
4611abf7346SmrgMoveAndClearText(Widget w, int old_y, int height, int new_y)
4621abf7346Smrg{
4631abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
4641abf7346Smrg  int from_left = sblw->scroll.indent + sblw->scroll.offset - 1;
4651abf7346Smrg  int y_clear;
4661abf7346Smrg
4671abf7346Smrg  old_y *= sblw->scroll.font_height;
4681abf7346Smrg  new_y *= sblw->scroll.font_height;
4691abf7346Smrg  height *= sblw->scroll.font_height;
4701abf7346Smrg
4711abf7346Smrg/*
4721abf7346Smrg * If we are already at the right location then do nothing.
4731abf7346Smrg * (height == 0).
4741abf7346Smrg *
4751abf7346Smrg * If we have scrolled more than a screen height then just clear
4761abf7346Smrg * the window.
4771abf7346Smrg */
4781abf7346Smrg
4791abf7346Smrg  if (height <= sblw->scroll.font_height) { /* avoid rounding errors. */
4801abf7346Smrg    XClearArea( XtDisplay(w), XtWindow(w), from_left, 0,
4811abf7346Smrg	       (unsigned int) 0, (unsigned int) 0, FALSE);
4821abf7346Smrg    PaintText(w, 0, (int) sblw->core.height);
4831abf7346Smrg    return;
4841abf7346Smrg  }
4851abf7346Smrg
4861abf7346Smrg  if ((int)height + (int)old_y > (int)w->core.height)
4871abf7346Smrg    height = w->core.height - old_y;
4881abf7346Smrg
4891abf7346Smrg  XCopyArea(XtDisplay(w), XtWindow(w), XtWindow(w), sblw->scroll.move_gc,
4901abf7346Smrg	    from_left, old_y,
4911abf7346Smrg	    (unsigned int) w->core.width - from_left, (unsigned int) height,
4921abf7346Smrg	    from_left, new_y);
4931abf7346Smrg
4941abf7346Smrg  if (old_y > new_y)
4951abf7346Smrg    height -= sblw->scroll.font_height/2;  /* clear 1/2 font of extra space,
4961abf7346Smrg					      to make sure we don't lose or
4971abf7346Smrg					      gain decenders. */
4981abf7346Smrg  else
4991abf7346Smrg    height -= sblw->scroll.font_height;  /* clear 1 font of extra space,
5001abf7346Smrg					    to make sure we don't overwrite
5011abf7346Smrg					    with a last line in buffer. */
5021abf7346Smrg
5031abf7346Smrg  if (old_y > new_y)
5041abf7346Smrg    y_clear = height;
5051abf7346Smrg  else
5061abf7346Smrg    y_clear = 0;
5071abf7346Smrg
5081abf7346Smrg/*
5091abf7346Smrg * We cannot use generate exposures, since that may allow another move and
5101abf7346Smrg * clear before the area get repainted, this would be bad.
5111abf7346Smrg */
5121abf7346Smrg
5131abf7346Smrg  XClearArea( XtDisplay(w), XtWindow(w), from_left, y_clear,
5141abf7346Smrg	     (unsigned int) 0, (unsigned int) (w->core.height - height),
5151abf7346Smrg	     FALSE);
5161abf7346Smrg  PaintText(w, (int) y_clear, (int) (w->core.height - height));
5171abf7346Smrg}
5181abf7346Smrg
5191abf7346Smrg/*	Function Name: SetThumbHeight
5201abf7346Smrg *	Description: Set the height of the thumb.
5211abf7346Smrg *	Arguments: w - the sblw widget.
5221abf7346Smrg *	Returns: none
5231abf7346Smrg */
5241abf7346Smrg
5251abf7346Smrgstatic void
5261abf7346SmrgSetThumbHeight(Widget w)
5271abf7346Smrg{
5281abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
5291abf7346Smrg  float shown;
5301abf7346Smrg
5311abf7346Smrg  if (sblw->scroll.bar == NULL)
5321abf7346Smrg    return;
5331abf7346Smrg
5341abf7346Smrg  if (sblw->scroll.lines == 0)
5351abf7346Smrg    shown = 1.0;
5361abf7346Smrg  else
5371abf7346Smrg    shown = (float) w->core.height / (float) (sblw->scroll.lines *
5381abf7346Smrg					      sblw->scroll.font_height);
5391abf7346Smrg  if (shown > 1.0)
5401abf7346Smrg    shown = 1.0;
5411abf7346Smrg
5421abf7346Smrg  XawScrollbarSetThumb( sblw->scroll.bar, (float) -1, shown );
5431abf7346Smrg}
5441abf7346Smrg
5451abf7346Smrg/*	Function Name: SetThumb
5461abf7346Smrg *	Description: Set the thumb location.
5471abf7346Smrg *	Arguments: w - the sblw.
5481abf7346Smrg *	Returns: none
5491abf7346Smrg */
5501abf7346Smrg
5511abf7346Smrgstatic void
5521abf7346SmrgSetThumb(Widget w)
5531abf7346Smrg{
5541abf7346Smrg  float location;
5551abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
5561abf7346Smrg
5571abf7346Smrg  if ( (sblw->scroll.lines == 0) || (sblw->scroll.bar == NULL) )
5581abf7346Smrg    return;
5591abf7346Smrg
5601abf7346Smrg  location = (float) sblw->scroll.line_pointer / (float) sblw->scroll.lines;
5611abf7346Smrg  XawScrollbarSetThumb( sblw->scroll.bar, location , (float) -1 );
5621abf7346Smrg}
5631abf7346Smrg
5641abf7346Smrg/*	Function Name: VerticalJump.
5651abf7346Smrg *	Description: This function moves the test
5661abf7346Smrg *                   as the vertical scroll bar is moved.
5671abf7346Smrg *	Arguments: w - the scrollbar widget.
5681abf7346Smrg *                 junk - not used.
5691abf7346Smrg *                 percent - the position of the scrollbar.
5701abf7346Smrg *	Returns: none.
5711abf7346Smrg */
5721abf7346Smrg
5731abf7346Smrg/* ARGSUSED */
5741abf7346Smrgstatic void
5751abf7346SmrgVerticalJump(Widget w, XtPointer junk, XtPointer percent_ptr)
5761abf7346Smrg{
5771abf7346Smrg  float percent = *((float *) percent_ptr);
5781abf7346Smrg  int new_line;			/* The new location for the line pointer. */
5791abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) XtParent(w);
5801abf7346Smrg
5811abf7346Smrg  new_line = (int) ((float) sblw->scroll.lines * percent);
5821abf7346Smrg  if (ScrollVerticalText( (Widget) sblw, new_line, FALSE))
5831abf7346Smrg    SetThumb((Widget) sblw);
5841abf7346Smrg}
5851abf7346Smrg
5861abf7346Smrg/*	Function Name: VerticalScroll
5871abf7346Smrg *	Description: This function moves the postition of the interior window
5881abf7346Smrg *                   as the vertical scroll bar is moved.
5891abf7346Smrg *	Arguments: w - the scrollbar widget.
5901abf7346Smrg *                 junk - not used.
5911abf7346Smrg *                 pos - the position of the cursor.
5921abf7346Smrg *	Returns: none.
5931abf7346Smrg */
5941abf7346Smrg
5951abf7346Smrg/* ARGSUSED */
5961abf7346Smrgstatic void
5971abf7346SmrgVerticalScroll(Widget w, XtPointer client_data, XtPointer call_data)
5981abf7346Smrg{
5991abf7346Smrg  int pos = (int)(long) call_data;
6001abf7346Smrg  int new_line;			/* The new location for the line pointer. */
6011abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) XtParent(w);
6021abf7346Smrg
6031abf7346Smrg  new_line = sblw->scroll.line_pointer + (pos / sblw->scroll.font_height);
6041abf7346Smrg  (void) ScrollVerticalText( (Widget) sblw, new_line, FALSE);
6051abf7346Smrg  SetThumb( (Widget) sblw);
6061abf7346Smrg}
6071abf7346Smrg
6081abf7346Smrg/* ARGSUSED */
6091abf7346Smrgstatic void
6101abf7346SmrgInitialize(Widget req, Widget new, ArgList args, Cardinal *num_args)
6111abf7346Smrg{
6121abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) new;
6131abf7346Smrg  unsigned long figWidth;
6141abf7346Smrg  Atom atomNum;
6151abf7346Smrg
6161abf7346Smrg  sblw->scroll.top_line = NULL;
6171abf7346Smrg  sblw->scroll.line_pointer = 0;
6181abf7346Smrg  LoadFile(new);
6191abf7346Smrg  sblw->scroll.bar = (Widget) NULL;
6201abf7346Smrg
6211abf7346Smrg  sblw->scroll.font_height = (sblw->scroll.normal_font->max_bounds.ascent +
6221abf7346Smrg			      sblw->scroll.normal_font->max_bounds.descent);
6231abf7346Smrg
6241abf7346Smrg  atomNum = XInternAtom(XtDisplay(req), "FIGURE_WIDTH", False);
6251abf7346Smrg
6261abf7346Smrg  if (XGetFontProperty(sblw->scroll.normal_font, atomNum, &figWidth))
6271abf7346Smrg    sblw->scroll.h_width = figWidth;
6281abf7346Smrg  else
6291abf7346Smrg    sblw->scroll.h_width = XTextWidth(sblw->scroll.normal_font, "$", 1);
6301abf7346Smrg} /* Initialize. */
6311abf7346Smrg
6321abf7346Smrg/*	Function Name: CreateGCs
6331abf7346Smrg *	Description: Creates the graphics contexts that we need.
6341abf7346Smrg *	Arguments: w - the sblw.
6351abf7346Smrg *	Returns: none
6361abf7346Smrg */
6371abf7346Smrg
6381abf7346Smrgstatic void
6391abf7346SmrgCreateGCs(Widget w)
6401abf7346Smrg{
6411abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
6421abf7346Smrg
6431abf7346Smrg  XtGCMask mask;
6441abf7346Smrg  XGCValues values;
6451abf7346Smrg
6461abf7346Smrg  values.graphics_exposures = TRUE;
6471abf7346Smrg  sblw->scroll.move_gc = XtGetGC(w, GCGraphicsExposures, &values);
6481abf7346Smrg
6491abf7346Smrg  mask = GCForeground | GCFont;
6501abf7346Smrg  values.foreground = sblw->scroll.foreground;
6511abf7346Smrg
6521abf7346Smrg  values.font = sblw->scroll.normal_font->fid;
6531abf7346Smrg  sblw->scroll.normal_gc = XtGetGC(w, mask, &values);
6541abf7346Smrg
6551abf7346Smrg  values.font = sblw->scroll.italic_font->fid;
6561abf7346Smrg  sblw->scroll.italic_gc = XtGetGC(w, mask, &values);
6571abf7346Smrg
6581abf7346Smrg  values.font = sblw->scroll.bold_font->fid;
6591abf7346Smrg  sblw->scroll.bold_gc = XtGetGC(w, mask, &values);
6601abf7346Smrg
6611abf7346Smrg  values.font = sblw->scroll.symbol_font->fid;
6621abf7346Smrg  sblw->scroll.symbol_gc = XtGetGC(w, mask, &values);
6631abf7346Smrg}
6641abf7346Smrg
6651abf7346Smrg/*	Function Name: DestroyGCs
6661abf7346Smrg *	Description: removes all gcs for this widget.
6671abf7346Smrg *	Arguments: w - the widget.
6681abf7346Smrg *	Returns: none
6691abf7346Smrg */
6701abf7346Smrg
6711abf7346Smrgstatic void
6721abf7346SmrgDestroyGCs(Widget w)
6731abf7346Smrg{
6741abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
6751abf7346Smrg
6761abf7346Smrg  XtReleaseGC(w, sblw->scroll.normal_gc);
6771abf7346Smrg  XtReleaseGC(w, sblw->scroll.bold_gc);
6781abf7346Smrg  XtReleaseGC(w, sblw->scroll.italic_gc);
6791abf7346Smrg  XtReleaseGC(w, sblw->scroll.move_gc);
6801abf7346Smrg}
6811abf7346Smrg
6821abf7346Smrgstatic void
6831abf7346SmrgRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
6841abf7346Smrg{
6851abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
6861abf7346Smrg
6871abf7346Smrg  CreateScrollbar(w);
6881abf7346Smrg  CreateGCs(w);
6891abf7346Smrg  Layout(w);
6901abf7346Smrg  (*SuperClass->core_class.realize) (w, valueMask, attributes);
6911abf7346Smrg  XtRealizeWidget(sblw->scroll.bar); /* realize scrollbar. */
6921abf7346Smrg  XtMapWidget(sblw->scroll.bar); /* map scrollbar. */
6931abf7346Smrg
6941abf7346Smrg  XtAddEventHandler(w, 0, TRUE, GExpose, NULL); /* Get Graphics Exposures */
6951abf7346Smrg} /* Realize */
6961abf7346Smrg
6971abf7346Smrg/*	Function Name: Destroy
6981abf7346Smrg *	Description: Cleans up when we are killed.
6991abf7346Smrg *	Arguments: w - the widget.
7001abf7346Smrg *	Returns: none
7011abf7346Smrg */
7021abf7346Smrg
7031abf7346Smrgstatic void
7041abf7346SmrgDestroy(Widget w)
7051abf7346Smrg{
7061abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
7071abf7346Smrg
7081abf7346Smrg  if (sblw->scroll.bar != NULL)
7091abf7346Smrg    XtDestroyWidget(sblw->scroll.bar); /* Destroy scrollbar. */
7101abf7346Smrg  if (sblw->scroll.file != NULL)
7111abf7346Smrg    fclose(sblw->scroll.file);
7121abf7346Smrg  DestroyGCs(w);
7131abf7346Smrg}
7141abf7346Smrg
7151abf7346Smrg/*
7161abf7346Smrg *
7171abf7346Smrg * Set Values
7181abf7346Smrg *
7191abf7346Smrg */
7201abf7346Smrg
7211abf7346Smrg/* ARGSUSED */
7221abf7346Smrgstatic Boolean
7231abf7346SmrgSetValuesHook(Widget w, ArgList args, Cardinal *num_args)
7241abf7346Smrg{
7251abf7346Smrg  Boolean ret = TRUE;
7261abf7346Smrg  Cardinal i;
7271abf7346Smrg
7281abf7346Smrg  for (i = 0; i < *num_args; i++) {
7291abf7346Smrg    if (strcmp(XtNfile, args[i].name) == 0) {
7301abf7346Smrg      LoadFile(w);
7311abf7346Smrg      ret = TRUE;
7321abf7346Smrg    }
7331abf7346Smrg  }
7341abf7346Smrg
7351abf7346Smrg/*
7361abf7346Smrg * Changing anthing else will have strange effects, I don't need it so
7371abf7346Smrg * I didn't code it.
7381abf7346Smrg */
7391abf7346Smrg
7401abf7346Smrg  return(ret);
7411abf7346Smrg
7421abf7346Smrg} /* Set Values */
7431abf7346Smrg
7441abf7346Smrg/*
7451abf7346Smrg * A little design philosophy is probabally wise to include at this point.
7461abf7346Smrg *
7471abf7346Smrg * One of the things that I has hoped to achieve with xman is to make the
7481abf7346Smrg * viewing of manpage not only easy for the nieve user, but also fast for
7491abf7346Smrg * the experienced user, I wanted to be able to use it too.  To achieve this
7501abf7346Smrg * I end up sacrificing a bit of start up time for the manual data structure.
7511abf7346Smrg * As well as, the overhead of reading the entire file before putting it up
7521abf7346Smrg * on the display.  This is actually hardly even noticeable since most manual
7531abf7346Smrg * pages are shots, one to two pages - the notable exception is of course csh,
7541abf7346Smrg * but then that should be broken up anyway.
7551abf7346Smrg *
7561abf7346Smrg * METHOD:
7571abf7346Smrg *
7581abf7346Smrg * I allocate a chunk of space that is the size of the file, plus a null for
7591abf7346Smrg * debugging.  Then copiesthe file into this chunk of memory.  I then allocate
7601abf7346Smrg * an array of char*'s that are assigned to the beginning of each line.  Yes,
7611abf7346Smrg * this means that I have to read the file twice, and could probabally be more
7621abf7346Smrg * clever about it, but once it is in memory the second read is damn fast.
7631abf7346Smrg * There are a few obsucrities here about guessing the number of lines and
7641abf7346Smrg * reallocing if I guess wrong, but other than that it is pretty straight
7651abf7346Smrg * forward.
7661abf7346Smrg *
7671abf7346Smrg *                                         Chris Peterson
7681abf7346Smrg *                                         1/27/88
7691abf7346Smrg */
7701abf7346Smrg
7711abf7346Smrg#define ADD_MORE_MEM 100	/* first guesses for allocations. */
7721abf7346Smrg#define CHAR_PER_LINE 40
7731abf7346Smrg
7741abf7346Smrg/*	Function Name: LoadFile
7751abf7346Smrg *	Description: Loads the current file into the internal memory.
7761abf7346Smrg *	Arguments: w - the sblw.
7771abf7346Smrg *	Returns: none
7781abf7346Smrg */
7791abf7346Smrg
7801abf7346Smrgstatic void
7811abf7346SmrgLoadFile(Widget w)
7821abf7346Smrg{
7831abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
7841abf7346Smrg  FILE * file = sblw->scroll.file;
7851abf7346Smrg
7861abf7346Smrg  char *page;
7871abf7346Smrg  char **line_pointer,**top_line; /* pointers to beginnings of the
7881abf7346Smrg				     lines of the file. */
7891abf7346Smrg  int nlines;			/* the current number of allocated lines. */
7901abf7346Smrg  struct stat fileinfo;		/* file information from fstat. */
7911abf7346Smrg
7921abf7346Smrg  if ( sblw->scroll.top_line != NULL) {
7931abf7346Smrg    XtFree(*(sblw->scroll.top_line)); /* free characters. */
7941abf7346Smrg    XtFree((char *)(sblw->scroll.top_line)); /* free lines. */
7951abf7346Smrg  }
7961abf7346Smrg  sblw->scroll.top_line = NULL;
7971abf7346Smrg
7981abf7346Smrg  if (file == NULL)
7991abf7346Smrg    return;
8001abf7346Smrg
8011abf7346Smrg/*
8021abf7346Smrg * Get file size and allocate a chunk of memory for the file to be
8031abf7346Smrg * copied into.
8041abf7346Smrg */
8051abf7346Smrg
8061abf7346Smrg  if (fstat(fileno(file), &fileinfo))
8071abf7346Smrg    XtAppError(XtWidgetToApplicationContext(w),
8081abf7346Smrg	       "SBLW LoadFile: Failure in fstat.");
8091abf7346Smrg
8101abf7346Smrg/*
8111abf7346Smrg * Allocate a space for a list of pointer to the beginning of each line.
8121abf7346Smrg */
8131abf7346Smrg
8141abf7346Smrg  if ( (nlines = fileinfo.st_size/CHAR_PER_LINE) == 0)
8151abf7346Smrg    return;
8161abf7346Smrg
8171abf7346Smrg  page = XtMalloc(fileinfo.st_size + 1); /* leave space for the NULL */
8181abf7346Smrg  top_line = line_pointer = (char**) XtMalloc( nlines * sizeof(char *) );
8191abf7346Smrg
8201abf7346Smrg/*
8211abf7346Smrg * Copy the file into memory.
8221abf7346Smrg */
8231abf7346Smrg
8241abf7346Smrg  fseek(file, 0L, SEEK_SET);
8251abf7346Smrg  if (fread(page, sizeof(char), fileinfo.st_size, file) == 0)
8261abf7346Smrg    XtAppError(XtWidgetToApplicationContext(w),
8271abf7346Smrg	       "SBLW LoadFile: Failure in fread.");
8281abf7346Smrg
8291abf7346Smrg
8301abf7346Smrg/* put NULL at end of buffer. */
8311abf7346Smrg
8321abf7346Smrg  *(page + fileinfo.st_size) = '\0';
8331abf7346Smrg
8341abf7346Smrg/*
8351abf7346Smrg * Go through the file setting a line pointer to the character after each
8361abf7346Smrg * new line.  If we run out of line pointer space then realloc that space
8371abf7346Smrg * with space for more lines.
8381abf7346Smrg */
8391abf7346Smrg
8401abf7346Smrg  *line_pointer++ = page;	/* first line points to first char in buffer.*/
8411abf7346Smrg  while (*page != '\0') {
8421abf7346Smrg
8431abf7346Smrg    if ( *page == '\n' ) {
8441abf7346Smrg      *line_pointer++ = page + 1;
8451abf7346Smrg
8461abf7346Smrg      if (line_pointer >= top_line + nlines) {
8471abf7346Smrg	top_line = (char **) XtRealloc( (char *)top_line, (nlines +
8481abf7346Smrg					  ADD_MORE_MEM) * sizeof(char *) );
8491abf7346Smrg	line_pointer = top_line + nlines;
8501abf7346Smrg	nlines += ADD_MORE_MEM;
8511abf7346Smrg      }
8521abf7346Smrg    }
8531abf7346Smrg    page++;
8541abf7346Smrg  }
8551abf7346Smrg
8561abf7346Smrg/*
8571abf7346Smrg *  Realloc the line pointer space to take only the minimum amount of memory
8581abf7346Smrg */
8591abf7346Smrg
8601abf7346Smrg  sblw->scroll.lines = nlines = line_pointer - top_line - 1;
8611abf7346Smrg  top_line = (char **) XtRealloc((char *)top_line, nlines * sizeof(char *));
8621abf7346Smrg
8631abf7346Smrg/*
8641abf7346Smrg * Store the memory pointers
8651abf7346Smrg */
8661abf7346Smrg
8671abf7346Smrg  sblw->scroll.top_line = top_line;
8681abf7346Smrg  sblw->scroll.line_pointer = 0;
8691abf7346Smrg  SetThumbHeight(w);
8701abf7346Smrg  SetThumb(w);
8711abf7346Smrg}
8721abf7346Smrg
8731abf7346Smrg#define NLINES  66		/* This is the number of lines to wait until
8741abf7346Smrg				   we boldify the line again, this allows
8751abf7346Smrg				   me to bold the first line of each page.*/
8761abf7346Smrg#define BACKSPACE 010		/* I doubt you would want to change this. */
8771abf7346Smrg
8781abf7346Smrg#define NORMAL	0
8791abf7346Smrg#define BOLD	1
8801abf7346Smrg#define ITALIC	2
8811abf7346Smrg#define SYMBOL	3
8821abf7346Smrg#define WHICH(italic, bold)	((bold) ? BOLD : ((italic) ? ITALIC : NORMAL))
8831abf7346Smrg				/* Choose BOLD over ITALICS.  If neither */
8841abf7346Smrg				/* is chosen, use NORMAL. */
8851abf7346Smrg
8861abf7346Smrgstatic int DumpText(Widget w, int x_loc, int y_loc, char * buf, int len, int format);
8871abf7346Smrgstatic Boolean Boldify(char *);
8881abf7346Smrg
8891abf7346Smrg/*	Function Name: PrintText
8901abf7346Smrg *	Description: This function actually prints the text.
8911abf7346Smrg *	Arguments: w - the ScrollByLine widget.
8921abf7346Smrg *                 start_line - line to start printing,
8931abf7346Smrg *                 num_lines - the number of lines to print.
8941abf7346Smrg *                 location - the location to print the text.
8951abf7346Smrg *	Returns: none.
8961abf7346Smrg */
8971abf7346Smrg
8981abf7346Smrg/* ARGSUSED */
8991abf7346Smrg
9001abf7346Smrgstatic void
9011abf7346SmrgPrintText(Widget w, int start_line, int num_lines, int location)
9021abf7346Smrg{
9031abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
9041abf7346Smrg
9051abf7346Smrg  register char *bufp, *c;	/* Generic char pointers */
9061abf7346Smrg  int current_line;		/* the number of the currrent line */
9071abf7346Smrg  char buf[BUFSIZ];		/* Misc. characters */
9081abf7346Smrg  Boolean italicflag = FALSE;	/* Print text in italics?? */
9091abf7346Smrg  Boolean first = TRUE;	        /* First line of a manual page??? */
9101abf7346Smrg  int x_loc, y_loc;		/* x and y location of text. */
9111abf7346Smrg
9121abf7346Smrg/*
9131abf7346Smrg * For table hack
9141abf7346Smrg * To get columns to line up reasonably in most cases, make the
9151abf7346Smrg * assumption that they were lined up using lots of spaces, where
9161abf7346Smrg * lots is greater than two. Use a space width of 70% of the
9171abf7346Smrg * widest character in the font.
9181abf7346Smrg */
9191abf7346Smrg  int h_col, h_fix;
9201abf7346Smrg  char * h_c;
9211abf7346Smrg
9221abf7346Smrg/*
9231abf7346Smrg * Nothing loaded, take no action.
9241abf7346Smrg */
9251abf7346Smrg
9261abf7346Smrg  if (sblw->scroll.top_line == NULL || num_lines == 0)
9271abf7346Smrg    return;
9281abf7346Smrg
9291abf7346Smrg  current_line = start_line;
9301abf7346Smrg
9311abf7346Smrg/* Set the first character to print at the first line. */
9321abf7346Smrg
9331abf7346Smrg  c = *(sblw->scroll.top_line + start_line);
9341abf7346Smrg
9351abf7346Smrg/*
9361abf7346Smrg * Because XDrawString uses the bottom of the text as a position
9371abf7346Smrg * reference, add the height from the top of the font to the baseline
9381abf7346Smrg * to the ScollByLine position reference.
9391abf7346Smrg */
9401abf7346Smrg
9411abf7346Smrg  y_loc = location + sblw->scroll.normal_font->max_bounds.ascent;
9421abf7346Smrg
9431abf7346Smrg/*
9441abf7346Smrg * Ok, here's the more than mildly heuristic man page formatter.
9451abf7346Smrg * We put chars into buf until either a font change or newline
9461abf7346Smrg * occurs (at which time we flush it to the screen.)
9471abf7346Smrg */
9481abf7346Smrg
9491abf7346Smrg
9501abf7346Smrg  bufp = buf;
9511abf7346Smrg  x_loc = sblw->scroll.offset + sblw->scroll.indent;
9521abf7346Smrg  h_col = 0;
9531abf7346Smrg
9541abf7346Smrg/*
9551abf7346Smrg * A fix:
9561abf7346Smrg * Assume that we are always starting to print on or before the
9571abf7346Smrg * first line of a page, and then prove it if we aren't.
9581abf7346Smrg */
9591abf7346Smrg  for (h_fix = 1; h_fix <= (start_line % NLINES); h_fix++)
9601abf7346Smrg    if (**(sblw->scroll.top_line + start_line - h_fix) != '\n')
9611abf7346Smrg      {
9621abf7346Smrg	first = FALSE;
9631abf7346Smrg	break;
9641abf7346Smrg      }
9651abf7346Smrg
9661abf7346Smrg  while(TRUE) {
9671abf7346Smrg    if (current_line % NLINES == 0)
9681abf7346Smrg      first = TRUE;
9691abf7346Smrg
9701abf7346Smrg/*
9711abf7346Smrg * Lets make sure that we do not run out of space in our buffer, making full
9721abf7346Smrg * use of it is not critical since no window will be wide enough to display
9731abf7346Smrg * nearly BUFSIZ characters.
9741abf7346Smrg */
9751abf7346Smrg
9761abf7346Smrg    if ( (bufp - buf) > (BUFSIZ - 10) )
9771abf7346Smrg      /* Toss everything until we find a <CR> or the end of the buffer. */
9781abf7346Smrg      while ( (*c != '\n') && (*c != '\0') ) c++;
9791abf7346Smrg
9801abf7346Smrg    switch(*c) {
9811abf7346Smrg
9821abf7346Smrg    case '\0':		      /* If we reach the end of the file then return */
9831abf7346Smrg      DumpText(w, x_loc, y_loc, buf, bufp - buf, WHICH(italicflag, first));
9841abf7346Smrg      return;
9851abf7346Smrg
9861abf7346Smrg    case '\n':
9871abf7346Smrg      if (bufp != buf) {
9881abf7346Smrg	Boolean bold;
9891abf7346Smrg	*bufp = '\0';		/* for Boldify. */
9901abf7346Smrg	bold = ( (first) || ((x_loc == (sblw->scroll.offset +
9911abf7346Smrg			      sblw->scroll.indent)) && Boldify(buf)) );
9921abf7346Smrg
9931abf7346Smrg	(void) DumpText(w, x_loc, y_loc, buf, bufp - buf,
9941abf7346Smrg			WHICH(italicflag, bold));
9951abf7346Smrg
9961abf7346Smrg	if (bold)
9971abf7346Smrg	  first = FALSE;
9981abf7346Smrg      }
9991abf7346Smrg
10001abf7346Smrg/*
10011abf7346Smrg * If we have painted the required number of lines then we should now return.
10021abf7346Smrg */
10031abf7346Smrg      if (++current_line == start_line + num_lines )
10041abf7346Smrg	return;
10051abf7346Smrg
10061abf7346Smrg      bufp = buf;
10071abf7346Smrg      italicflag = FALSE;
10081abf7346Smrg      x_loc = sblw->scroll.offset + sblw->scroll.indent;
10091abf7346Smrg      h_col = 0;
10101abf7346Smrg      y_loc += sblw->scroll.font_height;
10111abf7346Smrg      break;
10121abf7346Smrg
10131abf7346Smrg/*
10141abf7346Smrg * This tab handling code is not very clever it moves the cursor over
10151abf7346Smrg * to the next boundry of eight (8) spaces, as calculated in width just
10161abf7346Smrg * before the printing loop started.
10171abf7346Smrg */
10181abf7346Smrg
10191abf7346Smrg    case '\t':			/* TAB */
10201abf7346Smrg      x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
10211abf7346Smrg		       WHICH(italicflag, first));
10221abf7346Smrg      h_col += bufp - buf;
10231abf7346Smrg      bufp = buf;
10241abf7346Smrg      italicflag = FALSE;
10251abf7346Smrg      x_loc = sblw->scroll.offset + sblw->scroll.indent;
10261abf7346Smrg      h_col = h_col + 8 - (h_col%8);
10271abf7346Smrg      x_loc += sblw->scroll.h_width * h_col;
10281abf7346Smrg      break;
10291abf7346Smrg
10301abf7346Smrg    case ' ':
10311abf7346Smrg      h_c = c + 1;
10321abf7346Smrg      while (*h_c == ' ') h_c++;
10331abf7346Smrg
10341abf7346Smrg      if (h_c - c < 4)
10351abf7346Smrg	{
10361abf7346Smrg	  *bufp++ = *c;
10371abf7346Smrg	  break;
10381abf7346Smrg	}
10391abf7346Smrg
10401abf7346Smrg      x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
10411abf7346Smrg		       WHICH(italicflag, first));
10421abf7346Smrg      h_col += bufp - buf;
10431abf7346Smrg      bufp = buf;
10441abf7346Smrg      italicflag = FALSE;
10451abf7346Smrg
10461abf7346Smrg      x_loc = sblw->scroll.offset + sblw->scroll.indent;
10471abf7346Smrg      h_col += (h_c - c);
10481abf7346Smrg      x_loc += sblw->scroll.h_width * h_col;
10491abf7346Smrg      c = h_c - 1;
10501abf7346Smrg      break;
10511abf7346Smrg
10521abf7346Smrg    case '\033':		/* ignore esc sequences for now */
10531abf7346Smrg      c++;			/* should always be esc-x */
10541abf7346Smrg      break;
10551abf7346Smrg
10561abf7346Smrg/*
10571abf7346Smrg * Overstrike code supplied by: cs.utexas.edu!ut-emx!clyde@rutgers.edu
10581abf7346Smrg * Since my manual pages do not have overstrike I couldn't test this.
10591abf7346Smrg */
10601abf7346Smrg
10611abf7346Smrg    case BACKSPACE:		/* Backspacing for nroff bolding */
10621abf7346Smrg      if (c[-1] == c[1] && c[1] != BACKSPACE) {	/* overstriking one char */
10631abf7346Smrg        if (bufp > buf) {
10641abf7346Smrg	  bufp--;		/* Zap 1st instance of char to bolden */
10651abf7346Smrg	  x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
10661abf7346Smrg			   WHICH(italicflag, FALSE));
10671abf7346Smrg	  h_col += bufp - buf;
10681abf7346Smrg	}
10691abf7346Smrg	bufp = buf;
10701abf7346Smrg	*bufp++ = c[1];
10711abf7346Smrg	x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, BOLD);
10721abf7346Smrg	h_col += bufp - buf;
10731abf7346Smrg	bufp = buf;
10741abf7346Smrg	first = FALSE;
10751abf7346Smrg
10761abf7346Smrg	/*
10771abf7346Smrg	 *     Nroff bolding looks like:
10781abf7346Smrg	 * 	         C\bC\bC\bCN...
10791abf7346Smrg	 * c points to ----^      ^
10801abf7346Smrg	 * it needs to point to --^
10811abf7346Smrg	 */
10821abf7346Smrg	while (*c == BACKSPACE && c[-1] == c[1])
10831abf7346Smrg	  c += 2;
10841abf7346Smrg	c--;		/* Back up to previous char */
10851abf7346Smrg      }
10861abf7346Smrg      else {
10871abf7346Smrg	if ((c[-1] == 'o' && c[1] == '+')          /* Nroff bullet */
10881abf7346Smrg	    || (c[-1] == '+' && c[1] == 'o')) {	   /* Nroff bullet */
10891abf7346Smrg				/* If we run into a bullet, print out */
10901abf7346Smrg				/* everything that's accumulated to this */
10911abf7346Smrg				/* point, then the bullet, then resume. */
10921abf7346Smrg	  if (bufp>buf) {
10931abf7346Smrg	    bufp--;
10941abf7346Smrg	    x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
10951abf7346Smrg		 	     WHICH(italicflag, FALSE));
10961abf7346Smrg	    h_col += bufp - buf;
10971abf7346Smrg	  }
10981abf7346Smrg	  bufp = buf;
10991abf7346Smrg	  *bufp = (char)183;
11001abf7346Smrg	  x_loc = DumpText(w, x_loc, y_loc, buf, 1, SYMBOL);
11011abf7346Smrg	  h_col++;
11021abf7346Smrg	  c++;
11031abf7346Smrg	}
11041abf7346Smrg	else {		/* 'real' backspace - back up output ptr */
11051abf7346Smrg	  if (bufp>buf)
11061abf7346Smrg	    bufp--;
11071abf7346Smrg	}
11081abf7346Smrg      }
11091abf7346Smrg      break;
11101abf7346Smrg
11111abf7346Smrg/* End of contributed overstrike code. */
11121abf7346Smrg
11131abf7346Smrg   case '_':			/* look for underlining [italicize] */
11141abf7346Smrg      if(*(c + 1) == BACKSPACE) {
11151abf7346Smrg	if(!italicflag) {	/* font change? */
11161abf7346Smrg	  if (bufp != buf) {
11171abf7346Smrg	    x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, NORMAL);
11181abf7346Smrg	    h_col += bufp - buf;
11191abf7346Smrg	    bufp = buf;
11201abf7346Smrg	  }
11211abf7346Smrg	  italicflag = TRUE;
11221abf7346Smrg	}
11231abf7346Smrg	c += 2;
11241abf7346Smrg	*bufp++ = *c;
11251abf7346Smrg	break;
11261abf7346Smrg      }
11271abf7346Smrg      /* else fall through to default, because this was a real underscore. */
11281abf7346Smrg
11291abf7346Smrg    default:
11301abf7346Smrg      if(italicflag) { 			/* font change? */
11311abf7346Smrg	if (bufp != buf) {
11321abf7346Smrg	  x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf,
11331abf7346Smrg			   WHICH(italicflag, FALSE));
11341abf7346Smrg	  h_col += bufp - buf;
11351abf7346Smrg	  bufp = buf;
11361abf7346Smrg	}
11371abf7346Smrg	italicflag = FALSE;
11381abf7346Smrg      }
11391abf7346Smrg      *bufp++ = *c;
11401abf7346Smrg      break;
11411abf7346Smrg    }
11421abf7346Smrg    c++;
11431abf7346Smrg  }
11441abf7346Smrg}
11451abf7346Smrg
11461abf7346Smrg/*	Function Name: DumpText
11471abf7346Smrg *	Description: Dumps text to the screen.
11481abf7346Smrg *	Arguments: w - the widget.
11491abf7346Smrg *                 x_loc - to dump text at.
11501abf7346Smrg *                 y_loc - the y_location to draw_text.
11511abf7346Smrg *                 buf - buffer to dump.
11521abf7346Smrg *                 italic, bold, boolean that tells us which gc to use.
11531abf7346Smrg *	Returns: x_location of the end of the text.
11541abf7346Smrg */
11551abf7346Smrg
11561abf7346Smrgstatic int
11571abf7346SmrgDumpText(Widget w, int x_loc, int y_loc, char * buf, int len, int format)
11581abf7346Smrg{
11591abf7346Smrg  ScrollByLineWidget sblw = (ScrollByLineWidget) w;
11601abf7346Smrg  GC gc;
11611abf7346Smrg  XFontStruct * font;
11621abf7346Smrg
11631abf7346Smrg  switch(format) {
11641abf7346Smrg
11651abf7346Smrg  case ITALIC:
11661abf7346Smrg    gc = sblw->scroll.italic_gc;
11671abf7346Smrg    font = sblw->scroll.italic_font;
11681abf7346Smrg    break;
11691abf7346Smrg
11701abf7346Smrg  case BOLD:
11711abf7346Smrg      gc = sblw->scroll.bold_gc;
11721abf7346Smrg      font = sblw->scroll.bold_font;
11731abf7346Smrg    break;
11741abf7346Smrg
11751abf7346Smrg  case SYMBOL:
11761abf7346Smrg    gc = sblw->scroll.symbol_gc;
11771abf7346Smrg    font = sblw->scroll.symbol_font;
11781abf7346Smrg    break;
11791abf7346Smrg
11801abf7346Smrg  default:
11811abf7346Smrg      gc = sblw->scroll.normal_gc;
11821abf7346Smrg      font = sblw->scroll.normal_font;
11831abf7346Smrg    break;
11841abf7346Smrg    }
11851abf7346Smrg
11861abf7346Smrg  XDrawString(XtDisplay(w), XtWindow(w), gc, x_loc, y_loc, buf, len);
11871abf7346Smrg  return(x_loc + XTextWidth(font, buf, len));
11881abf7346Smrg}
11891abf7346Smrg
11901abf7346Smrg/*	Function Name: Boldify
11911abf7346Smrg *	Description: look for keyword.
11921abf7346Smrg *	Arguments: sp - string pointer.
11931abf7346Smrg *	Returns: 1 if keyword else 0.
11941abf7346Smrg */
11951abf7346Smrg
11961abf7346Smrgstatic Boolean
11971abf7346SmrgBoldify(register char *sp)
11981abf7346Smrg{
11991abf7346Smrg  register char *sp_pointer;
12001abf7346Smrg  int length,count;
12011abf7346Smrg
12021abf7346Smrg/*
12031abf7346Smrg * If there are not lower case letters in the line the assume it is a
12041abf7346Smrg * keyword and boldify it in PrintManpage.
12051abf7346Smrg */
12061abf7346Smrg
12071abf7346Smrg  length = strlen(sp);
12081abf7346Smrg  for (sp_pointer = sp, count = 0; count < length; sp_pointer++,count++)
12091abf7346Smrg    if ( !isupper(*sp_pointer) && !isspace(*sp_pointer) )
12101abf7346Smrg      return(0);
12111abf7346Smrg  return(1);
12121abf7346Smrg}
12131abf7346Smrg
12141abf7346Smrg#undef superclass
12151abf7346Smrg#undef SuperClass
1216