home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / telecomm / terms / term-4.1-source.lha / Extras / Source / term-Source.lha / termTextBuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-04  |  42.1 KB  |  1,933 lines

  1. /*
  2. **    termTextBuffer.c
  3. **
  4. **    Support routines for the text buffer.
  5. **
  6. **    Copyright © 1990-1994 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Gadget ID codes. */
  13.  
  14. enum    {    GAD_SCROLLER,GAD_UP,GAD_DOWN };
  15.  
  16.     /* Menu ID codes. */
  17.  
  18. enum    {    MEN_SEARCH,MEN_REPEAT,MEN_GOTO,MEN_CLEARBUF_CONTENTS,MEN_QUITBUF };
  19.  
  20.     /* Gadget ID codes. */
  21.  
  22. enum    {    GAD_STRING,GAD_LOAD,GAD_OK,GAD_CANCEL };
  23.  
  24.     /* A handy macro to determine the length of a string. */
  25.  
  26. #define LINE_WIDTH(s)    (s)[-1]
  27.  
  28.     /* The dimensions of the scroller images. */
  29.  
  30. #define ARROW_WIDTH    18
  31. #define ARROW_HEIGHT    11
  32.  
  33. STATIC struct NewMenu BufferMenu[] =
  34. {
  35.     { NM_TITLE, NULL,         0 , 0, 0, (APTR)0},
  36.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_SEARCH},
  37.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_REPEAT},
  38.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  39.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_GOTO},
  40.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  41.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_CLEARBUF_CONTENTS},
  42.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  43.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_QUITBUF},
  44.  
  45.     { NM_END, 0,             0 , 0, 0, (APTR)0}
  46. };
  47.  
  48.     /* Some private data (render info & window). */
  49.  
  50. STATIC struct Window        *BufferWindow;
  51. STATIC struct Screen        *BufferScreen;
  52. STATIC struct Menu        *BufferMenuStrip;
  53.  
  54. STATIC BYTE             BufferSignal;
  55.  
  56. STATIC struct RastPort        *BPort;
  57. STATIC APTR             BufferVisualInfo;
  58.  
  59. STATIC LONG             NumBufferLines,
  60.                  NumBufferColumns,
  61.                  LastTopLine;
  62.  
  63. STATIC struct DrawInfo        *BufferDrawInfo;
  64. STATIC struct Image        *BufferAmigaGlyph,
  65.                 *BufferCheckGlyph;
  66.  
  67. STATIC BYTE             BufferTerminated;
  68.  
  69. STATIC WORD             LocalTextFontWidth,
  70.                  LocalTextFontHeight,
  71.                  LocalTextFontBase;
  72.  
  73. STATIC struct TTextAttr         LocalTextFont;
  74. STATIC UBYTE __far         LocalTextFontName[MAX_FILENAME_LENGTH];
  75.  
  76. STATIC struct TTextAttr         LocalUserFont;
  77. STATIC UBYTE __far         LocalUserFontName[MAX_FILENAME_LENGTH];
  78.  
  79. STATIC LONG             TopLine = -1,
  80.                  DisplayedLines;
  81.  
  82. STATIC BYTE             SearchForward    = TRUE,
  83.                  IgnoreCase    = TRUE,
  84.                  WholeWords    = FALSE;
  85.  
  86. STATIC struct Gadget        *Scroller,
  87.                 *UpArrow,
  88.                 *DownArrow;
  89.  
  90. STATIC struct Image        *UpImage,
  91.                 *DownImage;
  92.  
  93. STATIC UWORD            *BufferLineWidths,
  94.                 *BufferLineOffsets,
  95.                 *BufferColumnOffsets;
  96.  
  97. STATIC ULONG             ArrowWidth,
  98.                  ArrowHeight;
  99.  
  100.     /* DeleteScroller(VOID):
  101.      *
  102.      *    Delete scroller and arrow objects.
  103.      */
  104.  
  105. STATIC VOID
  106. DeleteScroller(VOID)
  107. {
  108.     if(Scroller)
  109.     {
  110.         DisposeObject(Scroller);
  111.  
  112.         Scroller = NULL;
  113.     }
  114.  
  115.     if(UpArrow)
  116.     {
  117.         DisposeObject(UpArrow);
  118.  
  119.         UpArrow = NULL;
  120.     }
  121.  
  122.     if(DownArrow)
  123.     {
  124.         DisposeObject(DownArrow);
  125.  
  126.         DownArrow = NULL;
  127.     }
  128.  
  129.     if(UpImage)
  130.     {
  131.         DisposeObject(UpImage);
  132.  
  133.         UpImage = NULL;
  134.     }
  135.  
  136.     if(DownImage)
  137.     {
  138.         DisposeObject(DownImage);
  139.  
  140.         DownImage = NULL;
  141.     }
  142. }
  143.  
  144.     /* CreateScroller(LONG Height):
  145.      *
  146.      *    Create scroller and arrow objects.
  147.      */
  148.  
  149. STATIC BYTE __regargs
  150. CreateScroller(LONG Height)
  151. {
  152.     struct DrawInfo    *DrawInfo;
  153.     BYTE         Result = FALSE;
  154.  
  155.     if(DrawInfo = GetScreenDrawInfo(BufferScreen))
  156.     {
  157.         if(UpImage = (struct Image *)NewObject(NULL,"sysiclass",
  158.             SYSIA_Size,    SYSISIZE_MEDRES,
  159.             SYSIA_Which,    UPIMAGE,
  160.             SYSIA_DrawInfo,    DrawInfo,
  161.         TAG_DONE))
  162.         {
  163.             if(DownImage = (struct Image *)NewObject(NULL,"sysiclass",
  164.                 SYSIA_Size,    SYSISIZE_MEDRES,
  165.                 SYSIA_Which,    DOWNIMAGE,
  166.                 SYSIA_DrawInfo,    DrawInfo,
  167.             TAG_DONE))
  168.             {
  169.                 LONG ScrollerHeight,LeftEdge;
  170.  
  171.                 ArrowWidth    = ARROW_WIDTH;
  172.                 ArrowHeight    = ARROW_HEIGHT;
  173.  
  174.                 GetAttr(IA_Height,    UpImage,&ArrowHeight);
  175.                 GetAttr(IA_Width,    UpImage,&ArrowWidth);
  176.  
  177.                 ScrollerHeight = Height - 2 * ArrowHeight;
  178.  
  179.                 LeftEdge = BufferScreen -> Width - ArrowWidth;
  180.  
  181.                 if(Scroller = NewObject(NULL,"propgclass",
  182.                     GA_ID,        GAD_SCROLLER,
  183.  
  184.                     GA_Top,        0,
  185.                     GA_Left,    LeftEdge,
  186.                     GA_Width,    ArrowWidth,
  187.                     GA_Height,    ScrollerHeight,
  188.                     GA_Immediate,    TRUE,
  189.                     GA_FollowMouse,    TRUE,
  190.                     GA_RelVerify,    TRUE,
  191.  
  192.                     PGA_Freedom,    FREEVERT,
  193.                     PGA_NewLook,    TRUE,
  194.  
  195.                     PGA_Visible,    1,
  196.                     PGA_Total,    1,
  197.                 TAG_DONE))
  198.                 {
  199.                     STATIC struct TagItem ArrowMappings[] = { GA_ID,GA_ID,TAG_END };
  200.  
  201.                     if(UpArrow = NewObject(NULL,"buttongclass",
  202.                         GA_ID,        GAD_UP,
  203.                         GA_Image,    UpImage,
  204.                         GA_Left,    LeftEdge,
  205.                         GA_Top,        ScrollerHeight,
  206.                         GA_Height,    ArrowHeight,
  207.                         GA_Width,    ArrowWidth,
  208.                         GA_Immediate,    TRUE,
  209.                         GA_RelVerify,    TRUE,
  210.                         GA_Previous,    Scroller,
  211.  
  212.                         ICA_TARGET,    ICTARGET_IDCMP,
  213.                         ICA_MAP,    ArrowMappings,
  214.                     TAG_DONE))
  215.                     {
  216.                         if(DownArrow = NewObject(NULL,"buttongclass",
  217.                             GA_ID,        GAD_DOWN,
  218.                             GA_Image,    DownImage,
  219.                             GA_Left,    LeftEdge,
  220.                             GA_Top,        ScrollerHeight + ArrowHeight,
  221.                             GA_Height,    ArrowHeight,
  222.                             GA_Width,    ArrowWidth,
  223.                             GA_Immediate,    TRUE,
  224.                             GA_RelVerify,    TRUE,
  225.                             GA_Previous,    UpArrow,
  226.  
  227.                             ICA_TARGET,    ICTARGET_IDCMP,
  228.                             ICA_MAP,    ArrowMappings,
  229.                         TAG_DONE))
  230.                             Result = TRUE;
  231.                     }
  232.                 }
  233.             }
  234.         }
  235.  
  236.         FreeScreenDrawInfo(BufferScreen,DrawInfo);
  237.     }
  238.  
  239.     if(!Result)
  240.         DeleteScroller();
  241.  
  242.     return(Result);
  243. }
  244.  
  245.     /* PrintLine(STRPTR Buffer,LONG LineNumber):
  246.      *
  247.      *    Print a line at a given line number in the displayed area.
  248.      */
  249.  
  250. STATIC VOID __regargs
  251. PrintLine(STRPTR Buffer,LONG LineNumber)
  252. {
  253.     WORD Length = Buffer[-1];
  254.  
  255.         /* Print the text. */
  256.  
  257.     if(Length)
  258.     {
  259.         Move(BPort,0,BufferLineOffsets[LineNumber] + LocalTextFontBase);
  260.  
  261.         if(Length > NumBufferColumns)
  262.             Length = NumBufferColumns;
  263.  
  264.         Text(BPort,Buffer,Length);
  265.     }
  266.  
  267.         /* The line doesn't exactly fill the displayed line,
  268.          * so erase the remaining columns.
  269.          */
  270.  
  271.     if(Length < BufferLineWidths[LineNumber])
  272.     {
  273.         SetAPen(BPort,0);
  274.         RectFill(BPort,BufferColumnOffsets[Length],BufferLineOffsets[LineNumber],BufferColumnOffsets[BufferLineWidths[LineNumber]] - 1,BufferLineOffsets[LineNumber + 1] - 1);
  275.         SetAPen(BPort,1);
  276.     }
  277.  
  278.     BufferLineWidths[LineNumber] = Length;
  279. }
  280.  
  281.     /* RedrawScreen(LONG FirstLine):
  282.      *
  283.      *    Redraw the contents of the entire screen and return the
  284.      *    number of lines actually drawn.
  285.      */
  286.  
  287. STATIC LONG __regargs
  288. RedrawScreen(LONG FirstLine)
  289. {
  290.     LONG i,Last,Line = 0,Result;
  291.  
  292.     ObtainSemaphore(BufferSemaphore);
  293.  
  294.         /* Determine last line to display. */
  295.  
  296.     if((Last = FirstLine + NumBufferLines) >= Lines)
  297.         Last = Lines;
  298.  
  299.     Result = Last - FirstLine;
  300.  
  301.     if(Lines)
  302.     {
  303.         if(LastTopLine != -1)
  304.         {
  305.             LONG Delta = FirstLine - LastTopLine;
  306.  
  307.             if(ABS(Delta) < NumBufferLines)
  308.             {
  309.                     /* No change? */
  310.  
  311.                 if(!Delta)
  312.                 {
  313.                     ReleaseSemaphore(BufferSemaphore);
  314.  
  315.                     return(Result);
  316.                 }
  317.                 else
  318.                 {
  319.                     LastTopLine = FirstLine;
  320.  
  321.                         /* Scrolled up? */
  322.  
  323.                     if(Delta < 0)
  324.                     {
  325.                         for(i = NumBufferLines - 1 ; i >= -Delta ; i--)
  326.                             BufferLineWidths[i] = BufferLineWidths[i + Delta];
  327.  
  328.                         ClipBlit(BPort,0,0,BPort,0,BufferLineOffsets[-Delta],BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines + Delta],MINTERM_COPY);
  329.  
  330.                         Last = FirstLine - Delta;
  331.                     }
  332.                     else
  333.                     {
  334.                         for(i = Delta ; i < NumBufferLines ; i++)
  335.                             BufferLineWidths[i - Delta] = BufferLineWidths[i];
  336.  
  337.                             /* Scrolled down. */
  338.  
  339.                         ClipBlit(BPort,0,BufferLineOffsets[Delta],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - Delta],MINTERM_COPY);
  340.  
  341.                         FirstLine += NumBufferLines - Delta;
  342.  
  343.                         Line = NumBufferLines - Delta;
  344.                     }
  345.                 }
  346.             }
  347.             else
  348.                 LastTopLine = FirstLine;
  349.         }
  350.         else
  351.             LastTopLine = FirstLine;
  352.  
  353.         if(BufferLines)
  354.         {
  355.             for(i = FirstLine ; i < Last ; i++)
  356.                 PrintLine(BufferLines[i],Line++);
  357.         }
  358.     }
  359.  
  360.     ReleaseSemaphore(BufferSemaphore);
  361.  
  362.         /* We didn't fill the whole screen, so clear the rest. */
  363.  
  364.     if(Result < NumBufferLines)
  365.     {
  366.         WORD i;
  367.  
  368.         for(i = Result ; i < NumBufferLines ; i++)
  369.             BufferLineWidths[i] = 0;
  370.  
  371.         SetAPen(BPort,0);
  372.         RectFill(BPort,0,BufferLineOffsets[Result],BufferColumnOffsets[NumBufferColumns] - 1,BufferLineOffsets[NumBufferLines] - 1);
  373.         SetAPen(BPort,1);
  374.     }
  375.  
  376.     return(Result);
  377. }
  378.  
  379.     /* MarkArea(LONG Column,LONG Line,LONG Length):
  380.      *
  381.      *    Mark an area in the term Buffer window.
  382.      */
  383.  
  384. STATIC VOID __regargs
  385. MarkArea(LONG Column,LONG Line,LONG Length)
  386. {
  387.     STATIC LONG OldColumn = -1,OldLine = -1,OldLength = -1;
  388.  
  389.     if(OldColumn != -1)
  390.         ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[OldColumn],BufferLineOffsets[OldLine],BufferColumnOffsets[OldLength],LocalTextFontHeight,MINTERM_NOT_C);
  391.  
  392.     if(Column != -1)
  393.     {
  394.         if(OldColumn != Column || OldLine != Line || OldLength != Length)
  395.             ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[Column],BufferLineOffsets[Line],BufferColumnOffsets[Length],LocalTextFontHeight,MINTERM_NOT_C);
  396.     }
  397.  
  398.     OldColumn    = Column;
  399.     OldLine        = Line;
  400.     OldLength    = Length;
  401. }
  402.  
  403.     /* BufferClipPage(struct BlockMarker *Marker):
  404.      *
  405.      *    Send the marked area to the clipboard.
  406.      */
  407.  
  408. STATIC VOID __inline
  409. BufferClipPage(struct BlockMarker *Marker)
  410. {
  411.     if(BufferLines)
  412.     {
  413.         struct IFFHandle *Handle;
  414.  
  415.         if(Handle = AllocIFF())
  416.         {
  417.             if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
  418.             {
  419.                 InitIFFasClip(Handle);
  420.  
  421.                 if(!OpenIFF(Handle,IFFF_WRITE))
  422.                 {
  423.                     if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
  424.                     {
  425.                         if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
  426.                         {
  427.                             LONG    Lines = Marker -> LastLine - Marker -> FirstLine - 1,
  428.                                 i;
  429.  
  430.                             if(LINE_WIDTH(BufferLines[Marker -> FirstLine]) > Marker -> FirstColumn)
  431.                                 WriteTrimmedString(Handle,&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],LINE_WIDTH(BufferLines[Marker -> FirstLine]) - Marker -> FirstColumn);
  432.  
  433.                             WriteChunkBytes(Handle,"\n",1);
  434.  
  435.                             if(Lines > 0)
  436.                             {
  437.                                 for(i = 0 ; i < Lines ; i++)
  438.                                 {
  439.                                     if(LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]))
  440.                                         WriteTrimmedString(Handle,BufferLines[Marker -> FirstLine + 1 + i],LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]));
  441.  
  442.                                     WriteChunkBytes(Handle,"\n",1);
  443.                                 }
  444.                             }
  445.  
  446.                             if(Marker -> LastColumn > LINE_WIDTH(BufferLines[Marker -> LastLine]))
  447.                                 WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],LINE_WIDTH(BufferLines[Marker -> LastLine]));
  448.                             else
  449.                                 WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],Marker -> LastColumn);
  450.  
  451.                             WriteChunkBytes(Handle,"\n",1);
  452.  
  453.                             PopChunk(Handle);
  454.                         }
  455.  
  456.                         PopChunk(Handle);
  457.                     }
  458.  
  459.                     CloseIFF(Handle);
  460.                 }
  461.  
  462.                 CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
  463.             }
  464.  
  465.             FreeIFF(Handle);
  466.         }
  467.     }
  468. }
  469.  
  470.     /* BufferClip(VOID):
  471.      *
  472.      *    Start buffer marking process.
  473.      */
  474.  
  475. STATIC VOID
  476. BufferClip(VOID)
  477. {
  478.     struct BlockMarker    *Marker;
  479.     LONG             FirstX = BufferWindow -> MouseX / LocalTextFontWidth,
  480.                  FirstY = BufferWindow -> MouseY / LocalTextFontHeight;
  481.  
  482.     if(Marker = BM_SetMark(BufferWindow -> RPort,ToggleSelect,ToggleSelect,NumBufferColumns,NumBufferLines,0,0,TopLine,Lines,BufferWindow -> MouseX / LocalTextFontWidth,BufferWindow -> MouseY / LocalTextFontHeight,LocalTextFontWidth,LocalTextFontHeight))
  483.     {
  484.         struct IntuiMessage    *Massage;
  485.         ULONG             Code,IClass;
  486.         BYTE             Done = FALSE,Aborted = FALSE;
  487.         LONG             PlusX = LocalTextFontWidth - 1,
  488.                      MouseX,MouseY,
  489.                      Delta = 0;
  490.  
  491.         ReportMouse(TRUE,BufferWindow);
  492.  
  493.         while(!Done)
  494.         {
  495.             WaitPort(BufferWindow -> UserPort);
  496.  
  497.             while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  498.             {
  499.                 IClass    = Massage -> Class;
  500.                 Code    = Massage -> Code;
  501.                 MouseX    = Massage -> MouseX;
  502.                 MouseY    = Massage -> MouseY;
  503.  
  504.                 ReplyMsg(Massage);
  505.  
  506.                 if(IClass == IDCMP_INACTIVEWINDOW)
  507.                 {
  508.                     Done = Aborted = TRUE;
  509.  
  510.                     break;
  511.                 }
  512.  
  513.                 if(IClass == IDCMP_INTUITICKS && Delta != 0)
  514.                 {
  515.                     if(BufferLines)
  516.                     {
  517.                         if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
  518.                         {
  519.                             if(Delta < 0)
  520.                             {
  521.                                 WORD i;
  522.  
  523.                                 for(i = NumBufferLines - 1 ; i > -Delta ; i--)
  524.                                     BufferLineWidths[i] = BufferLineWidths[i + Delta];
  525.  
  526.                                 if(DisplayedLines)
  527.                                     ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  528.  
  529.                                 BufferLineWidths[0] = NumBufferColumns;
  530.  
  531.                                 PrintLine(BufferLines[--TopLine],0);
  532.                             }
  533.                             else
  534.                             {
  535.                                 WORD i;
  536.  
  537.                                 for(i = Delta ; i < NumBufferLines ; i++)
  538.                                     BufferLineWidths[i - Delta] = BufferLineWidths[i];
  539.  
  540.                                 if(DisplayedLines)
  541.                                     ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  542.  
  543.                                 BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
  544.  
  545.                                 PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);
  546.  
  547.                                 TopLine++;
  548.                             }
  549.  
  550.                             Marker -> Top += Delta;
  551.                             Marker -> LastY -= Delta;
  552.  
  553.                             BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
  554.                         }
  555.                         else
  556.                             Delta = 0;
  557.                     }
  558.                 }
  559.  
  560.                 if(IClass == IDCMP_MOUSEBUTTONS && (Code & IECODE_UP_PREFIX))
  561.                 {
  562.                     BM_Draw(Marker,Marker -> Unselect);
  563.  
  564.                     Done = TRUE;
  565.  
  566.                     break;
  567.                 }
  568.  
  569.                 if(IClass == IDCMP_MOUSEMOVE)
  570.                 {
  571.                     BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,0);
  572.  
  573.                     if(MouseY < 1)
  574.                     {
  575.                         if(TopLine > 0)
  576.                             Delta = -1;
  577.                     }
  578.                     else
  579.                     {
  580.                         if(MouseY >= BufferWindow -> Height - 1 && TopLine + NumBufferLines < Lines)
  581.                             Delta = 1;
  582.                     }
  583.  
  584.                     while(Delta)
  585.                     {
  586.                         MouseX    = Window -> MouseX;
  587.                         MouseY    = Window -> MouseY;
  588.  
  589.                         if((Delta < 0 && MouseY > 0) || (Delta > 0 && MouseY < BufferWindow -> Height - 1))
  590.                             break;
  591.                         else
  592.                         {
  593.                             if(BufferLines)
  594.                             {
  595.                                 if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
  596.                                 {
  597.                                     if(Delta < 0)
  598.                                     {
  599.                                         WORD i;
  600.  
  601.                                         for(i = NumBufferLines - 1 ; i > -Delta ; i--)
  602.                                             BufferLineWidths[i] = BufferLineWidths[i + Delta];
  603.  
  604.                                         if(DisplayedLines)
  605.                                             ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  606.  
  607.                                         BufferLineWidths[0] = NumBufferColumns;
  608.  
  609.                                         PrintLine(BufferLines[--TopLine],0);
  610.                                     }
  611.                                     else
  612.                                     {
  613.                                         WORD i;
  614.  
  615.                                         for(i = Delta ; i < NumBufferLines ; i++)
  616.                                             BufferLineWidths[i - Delta] = BufferLineWidths[i];
  617.  
  618.                                         if(DisplayedLines)
  619.                                             ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  620.  
  621.                                         BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
  622.  
  623.                                         PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);
  624.  
  625.                                         TopLine++;
  626.                                     }
  627.  
  628.                                     Marker -> Top    += Delta;
  629.                                     Marker -> LastY    -= Delta;
  630.  
  631.                                     BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
  632.  
  633.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  634.                                         PGA_Top,TopLine,
  635.                                     TAG_DONE);
  636.                                 }
  637.                                 else
  638.                                     break;
  639.                             }
  640.                             else
  641.                                 break;
  642.                         }
  643.                     }
  644.  
  645.                     Delta = 0;
  646.                 }
  647.             }
  648.         }
  649.  
  650.         ReportMouse(FALSE,BufferWindow);
  651.  
  652.         while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  653.             ReplyMsg(Massage);
  654.  
  655.         if(!Aborted)
  656.         {
  657.             if(FirstX != BufferWindow -> MouseX / LocalTextFontWidth || FirstY != BufferWindow -> MouseY / LocalTextFontHeight)
  658.             {
  659.                 SetWait(BufferWindow);
  660.  
  661.                 if(Marker -> FirstColumn == Marker -> Width)
  662.                 {
  663.                     Marker -> FirstLine++;
  664.  
  665.                     Marker -> FirstColumn = 0;
  666.                 }
  667.  
  668.                 if(Marker -> LastColumn == 0)
  669.                 {
  670.                     Marker -> LastLine--;
  671.  
  672.                     Marker -> LastColumn = Marker -> Width;
  673.                 }
  674.  
  675.                 if(Marker -> FirstLine <= Marker -> LastLine)
  676.                 {
  677.                     if(Marker -> FirstLine != Marker -> LastLine || Marker -> FirstColumn != Marker -> LastColumn)
  678.                     {
  679.                         if(BufferLines)
  680.                         {
  681.                             if(Marker -> FirstLine == Marker -> LastLine)
  682.                                 SaveClip(&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],Marker -> LastColumn - Marker -> FirstColumn);
  683.                             else
  684.                                 BufferClipPage(Marker);
  685.                         }
  686.                     }
  687.                 }
  688.  
  689.                 ClrWait(BufferWindow);
  690.             }
  691.         }
  692.  
  693.         FreeVecPooled(Marker);
  694.     }
  695. }
  696.  
  697. STATIC VOID __regargs
  698. StartSearch(struct SearchInfo *SearchInfo,STRPTR SearchBuffer)
  699. {
  700.     LT_LockWindow(BufferWindow);
  701.  
  702.     if(Lines)
  703.     {
  704.         LONG LineNumber;
  705.  
  706.         ObtainSemaphore(BufferSemaphore);
  707.  
  708.         LineNumber = SearchTextBuffer(SearchInfo);
  709.  
  710.         ReleaseSemaphore(BufferSemaphore);
  711.  
  712.         if(LineNumber == -1)
  713.         {
  714.             MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_DID_NOT_FIND_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SearchBuffer);
  715.  
  716.             FlushMsg(BufferWindow);
  717.  
  718.             SearchInfo -> FoundY = -1;
  719.  
  720.             MarkArea(-1,-1,-1);
  721.         }
  722.         else
  723.         {
  724.             if(LineNumber < TopLine)
  725.             {
  726.                 MarkArea(-1,-1,-1);
  727.  
  728.                 DisplayedLines = RedrawScreen(TopLine = LineNumber);
  729.  
  730.                 SetGadgetAttrs(Scroller,BufferWindow,NULL,
  731.                     PGA_Top,TopLine,
  732.                 TAG_DONE);
  733.             }
  734.             else
  735.             {
  736.                 if(LineNumber > TopLine + DisplayedLines - 1)
  737.                 {
  738.                     MarkArea(-1,-1,-1);
  739.  
  740.                     if(LineNumber >= Lines - NumBufferLines)
  741.                     {
  742.                         LONG NewCurrentLine;
  743.  
  744.                         if((NewCurrentLine = Lines - NumBufferLines) < 0)
  745.                             NewCurrentLine = 0;
  746.  
  747.                         if(TopLine != NewCurrentLine)
  748.                             DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  749.                     }
  750.                     else
  751.                         DisplayedLines = RedrawScreen(TopLine = LineNumber);
  752.  
  753.                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  754.                         PGA_Top,TopLine,
  755.                     TAG_DONE);
  756.                 }
  757.             }
  758.  
  759.             MarkArea(SearchInfo -> FoundX,LineNumber - TopLine,SearchInfo -> PatternWidth);
  760.         }
  761.     }
  762.     else
  763.         MyEasyRequest(BufferWindow,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
  764.  
  765.     LT_UnlockWindow(BufferWindow);
  766. }
  767.  
  768. STATIC VOID __stdargs
  769. BufferDestructor(struct MsgItem *Item)
  770. {
  771.     Signal(BufferTask,1L << BufferSignal);
  772. }
  773.  
  774. STATIC BOOLEAN __regargs
  775. HandleBuffer(LONG TitleOffset)
  776. {
  777.     ULONG             LastSeconds    = 0,
  778.                  LastMicros    = 0,
  779.                  Seconds,
  780.                  Micros;
  781.     BOOLEAN             ClickAndActivate,
  782.                  UpdatePercent    = TRUE;
  783.  
  784.     ULONG             SignalSet;
  785.  
  786.     struct IntuiMessage    *Massage;
  787.     ULONG             MsgClass;
  788.     UWORD             MsgCode,MsgQualifier,LastQualifier = NULL;
  789.     WORD             MouseX,MouseY;
  790.  
  791.     UBYTE             Char,LastChar = 0;
  792.     LONG             LastWidth = 0;
  793.  
  794.     UBYTE             PercentBuffer[80];
  795.     UBYTE             SearchBuffer[256];
  796.  
  797.     struct TagItem        *TagList;
  798.  
  799.     STRPTR             PercentTemplate;
  800.  
  801.     BOOLEAN             RingBack = FALSE;
  802.  
  803.     struct SearchContext    *Context    = NULL;
  804.     struct SearchInfo    *SearchInfo    = NULL;
  805.  
  806.     struct Hook         HistoryHook;
  807.  
  808.     HistoryHook . h_Data = &TextBufferHistory;
  809.  
  810.     if(LocaleBase)
  811.         PercentTemplate = "%lD/%lD (%ld%%)";
  812.     else
  813.         PercentTemplate = "%ld/%ld (%ld%%)";
  814.  
  815.     do
  816.     {
  817.             /* Show where we are. */
  818.  
  819.         if(Lines && UpdatePercent)
  820.         {
  821.             LONG Width,Len;
  822.  
  823.             SetAPen(BufferScreen -> BarLayer -> rp,0);
  824.             SetBPen(BufferScreen -> BarLayer -> rp,1);
  825.             SetDrMd(BufferScreen -> BarLayer -> rp,JAM2);
  826.  
  827.             SPrintf(PercentBuffer,PercentTemplate,TopLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (TopLine + DisplayedLines)) / Lines);
  828.  
  829.             Len = strlen(PercentBuffer);
  830.  
  831.             Move(BufferScreen -> BarLayer -> rp,TitleOffset,BufferScreen -> BarLayer -> rp -> Font -> tf_Baseline + 1);
  832.             Text(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
  833.  
  834.             Width = TextLength(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
  835.  
  836.             if(LastWidth > Width)
  837.             {
  838.                 SetAPen(BufferScreen -> BarLayer -> rp,1);
  839.  
  840.                 RectFill(BufferScreen -> BarLayer -> rp,TitleOffset + Width,1,TitleOffset + LastWidth - 1,BufferScreen -> BarLayer -> rp -> Font -> tf_YSize);
  841.             }
  842.  
  843.             LastWidth = Width;
  844.  
  845.             UpdatePercent = FALSE;
  846.         }
  847.  
  848.         SignalSet = Wait(SIG_KILL | SIG_TOFRONT | SIG_UPDATE | SIG_MOVEUP | PORTMASK(BufferWindow -> UserPort));
  849.  
  850.             /* Leave the town? */
  851.  
  852.         if(SignalSet & SIG_KILL)
  853.             BufferTerminated = RingBack = TRUE;
  854.  
  855.             /* Bring our window to the front. */
  856.  
  857.         if(SignalSet & SIG_TOFRONT)
  858.         {
  859.             if(Context)
  860.                 LT_ShowWindow(Context -> SearchHandle,TRUE);
  861.  
  862.             BumpWindow(BufferWindow);
  863.         }
  864.  
  865.             /* We've got one more line in the
  866.              * buffer.
  867.              */
  868.  
  869.         if(SignalSet & SIG_UPDATE)
  870.         {
  871.             if(BufferLines && Lines)
  872.             {
  873.                 if(Lines - TopLine > DisplayedLines && DisplayedLines < NumBufferLines)
  874.                 {
  875.                     LONG i = TopLine + DisplayedLines;
  876.  
  877.                     do
  878.                         PrintLine(BufferLines[i++],DisplayedLines++);
  879.                     while(DisplayedLines < NumBufferLines && i < Lines);
  880.                 }
  881.             }
  882.  
  883.             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  884.                 PGA_Total,    Lines,
  885.                 PGA_Visible,    DisplayedLines,
  886.             TAG_DONE);
  887.  
  888.             UpdatePercent = TRUE;
  889.  
  890.             Signal(ThisProcess,SIG_HANDSHAKE);
  891.         }
  892.  
  893.             /* The contents of the buffer have moved
  894.              * up a line.
  895.              */
  896.  
  897.         if(SignalSet & SIG_MOVEUP)
  898.         {
  899.             if(TopLine > 0)
  900.             {
  901.                 LastTopLine = --TopLine;
  902.  
  903.                 SetGadgetAttrs(Scroller,BufferWindow,NULL,
  904.                     PGA_Top,TopLine,
  905.                 TAG_DONE);
  906.             }
  907.             else
  908.             {
  909.                 LONG i;
  910.  
  911.                 MarkArea(-1,-1,-1);
  912.  
  913.                 for(i = 0 ; i < NumBufferLines - 1 ; i++)
  914.                     BufferLineWidths[i] = BufferLineWidths[i + 1];
  915.  
  916.                 ClipBlit(BPort,0,BufferLineOffsets[1],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  917.  
  918.                 PrintLine(BufferLines[NumBufferLines - 1],NumBufferLines - 1);
  919.             }
  920.  
  921.             UpdatePercent = TRUE;
  922.  
  923.             Signal(ThisProcess,SIG_HANDSHAKE);
  924.         }
  925.  
  926.             /* Process the incoming window
  927.              * input.
  928.              */
  929.  
  930.         while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  931.         {
  932.             if(Context && Context -> SearchWindow == Massage -> IDCMPWindow)
  933.             {
  934.                 MsgClass = NULL;
  935.  
  936.                 if(HandleSearchMessage(Context,&Massage))
  937.                 {
  938.                     BOOLEAN Ok = Context -> Ok;
  939.  
  940.                     DeleteSearchContext(Context);
  941.  
  942.                     Context = NULL;
  943.  
  944.                     if(Ok)
  945.                     {
  946.                         if(SearchInfo)
  947.                             DeleteSearchInfo(SearchInfo);
  948.  
  949.                         if(SearchInfo = CreateSearchInfo(SearchBuffer,SearchForward,IgnoreCase,WholeWords))
  950.                             StartSearch(SearchInfo,SearchBuffer);
  951.                     }
  952.                     else
  953.                     {
  954.                         if(SearchInfo)
  955.                             DeleteSearchInfo(SearchInfo);
  956.  
  957.                         SearchInfo = NULL;
  958.                     }
  959.                 }
  960.             }
  961.             else
  962.             {
  963.                 MsgClass    = Massage -> Class;
  964.                 MsgCode        = Massage -> Code;
  965.                 MsgQualifier    = Massage -> Qualifier;
  966.                 MouseX        = Massage -> MouseX;
  967.                 MouseY        = Massage -> MouseY;
  968.                 TagList        = (struct TagItem *)Massage -> IAddress;
  969.                 Seconds        = Massage -> Seconds;
  970.                 Micros        = Massage -> Micros;
  971.  
  972.                 ClickAndActivate = FALSE;
  973.  
  974.                 if(Seconds == LastSeconds && Micros == LastMicros)
  975.                 {
  976.                     if(Massage -> Class == IDCMP_ACTIVEWINDOW || Massage -> Class == IDCMP_MOUSEBUTTONS)
  977.                         ClickAndActivate = TRUE;
  978.                 }
  979.  
  980.                 LastSeconds    = Seconds;
  981.                 LastMicros    = Micros;
  982.  
  983.                     /* This hack is necessary to obtain the
  984.                      * character codes generated for the cursor
  985.                      * keys. A control or alternate qualifier
  986.                      * would spoil the result (i.e. we would
  987.                      * not get a valid key code).
  988.                      */
  989.  
  990.                 Massage -> Qualifier = NULL;
  991.  
  992.                 Char = KeyConvert(Massage,NULL,NULL);
  993.  
  994.                     /* Just in case anybody needs it... */
  995.  
  996.                 Massage -> Qualifier = MsgQualifier;
  997.  
  998.                 ReplyMsg((struct Message *)Massage);
  999.             }
  1000.  
  1001.             if(MsgClass == IDCMP_ACTIVEWINDOW)
  1002.                 UpdatePercent = TRUE;
  1003.  
  1004.             if(MsgClass == IDCMP_IDCMPUPDATE)
  1005.             {
  1006.                 switch(GetTagData(GA_ID,0,TagList))
  1007.                 {
  1008.                     case GAD_UP:
  1009.  
  1010.                         if(TopLine > 0)
  1011.                         {
  1012.                             TopLine--;
  1013.  
  1014.                             MarkArea(-1,-1,-1);
  1015.  
  1016.                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1017.                                 PGA_Top,TopLine,
  1018.                             TAG_DONE);
  1019.  
  1020.                             DisplayedLines = RedrawScreen(TopLine);
  1021.  
  1022.                             UpdatePercent = TRUE;
  1023.                         }
  1024.  
  1025.                         break;
  1026.  
  1027.                     case GAD_DOWN:
  1028.  
  1029.                         if(TopLine + NumBufferLines < Lines)
  1030.                         {
  1031.                             TopLine++;
  1032.  
  1033.                             MarkArea(-1,-1,-1);
  1034.  
  1035.                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1036.                                 PGA_Top,TopLine,
  1037.                             TAG_DONE);
  1038.  
  1039.                             DisplayedLines = RedrawScreen(TopLine);
  1040.  
  1041.                             UpdatePercent = TRUE;
  1042.                         }
  1043.  
  1044.                         break;
  1045.                 }
  1046.             }
  1047.  
  1048.             if(MsgClass == IDCMP_MOUSEMOVE || MsgClass == IDCMP_GADGETDOWN || MsgClass == IDCMP_GADGETUP)
  1049.             {
  1050.                 LONG Position;
  1051.  
  1052.                 GetAttr(PGA_Top,Scroller,(ULONG *)&Position);
  1053.  
  1054.                 if(Position != TopLine)
  1055.                 {
  1056.                     MarkArea(-1,-1,-1);
  1057.  
  1058.                     DisplayedLines = RedrawScreen(TopLine = Position);
  1059.  
  1060.                     UpdatePercent = TRUE;
  1061.                 }
  1062.             }
  1063.  
  1064.             if(MsgClass == IDCMP_RAWKEY)
  1065.             {
  1066.                 if(MsgCode == HELP_CODE)
  1067.                     GuideDisplay(CONTEXT_TEXTBUFFER);
  1068.  
  1069.                 if(LastChar)
  1070.                 {
  1071.                     if((MsgCode & IECODE_UP_PREFIX) || !(LastQualifier & IEQUALIFIER_REPEAT))
  1072.                     {
  1073.                         SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1074.                             PGA_Top,TopLine,
  1075.                         TAG_DONE);
  1076.  
  1077.                         UpdatePercent = TRUE;
  1078.                     }
  1079.                 }
  1080.  
  1081.                 if(LastChar = Char)
  1082.                 {
  1083.                         /* Use the numeric keypad keys to
  1084.                          * move through the buffer.
  1085.                          */
  1086.  
  1087.                     if(MsgQualifier & IEQUALIFIER_NUMERICPAD)
  1088.                     {
  1089.                             /* Remove the numpad qualifier. */
  1090.  
  1091.                         MsgQualifier &= ~IEQUALIFIER_NUMERICPAD;
  1092.  
  1093.                         switch(Char - '0')
  1094.                         {
  1095.                                 /* Jump to bottom. */
  1096.  
  1097.                             case 1: Char = CDN;
  1098.                                 MsgQualifier |= IEQUALIFIER_CONTROL;
  1099.                                 break;
  1100.  
  1101.                                 /* Jump to top. */
  1102.  
  1103.                             case 7: Char = CUP;
  1104.                                 MsgQualifier |= IEQUALIFIER_CONTROL;
  1105.                                 break;
  1106.  
  1107.                                 /* Move one page down. */
  1108.  
  1109.                             case 3: Char = CDN;
  1110.                                 MsgQualifier |= IEQUALIFIER_LSHIFT;
  1111.                                 break;
  1112.  
  1113.                                 /* Move one page up. */
  1114.  
  1115.                             case 9: Char = CUP;
  1116.                                 MsgQualifier |= IEQUALIFIER_LSHIFT;
  1117.                                 break;
  1118.  
  1119.                                 /* Move one line down. */
  1120.  
  1121.                             case 2: Char = CDN;
  1122.                                 break;
  1123.  
  1124.                                 /* Move one line up. */
  1125.  
  1126.                             case 8: Char = CUP;
  1127.                                 break;
  1128.                         }
  1129.                     }
  1130.  
  1131.                         /* Check cursor keys. */
  1132.  
  1133.                     switch(Char)
  1134.                     {
  1135.                             /* Scroll the buffer up. */
  1136.  
  1137.                         case CUP:
  1138.  
  1139.                             if(MsgQualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  1140.                             {
  1141.                                 MarkArea(-1,-1,-1);
  1142.  
  1143.                                 if(TopLine)
  1144.                                 {
  1145.                                     DisplayedLines = RedrawScreen(TopLine = 0);
  1146.  
  1147.                                     LastChar = 0;
  1148.  
  1149.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1150.                                         PGA_Top,TopLine,
  1151.                                     TAG_DONE);
  1152.  
  1153.                                     UpdatePercent = TRUE;
  1154.                                 }
  1155.  
  1156.                                 break;
  1157.                             }
  1158.  
  1159.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1160.                             {
  1161.                                 LONG NewCurrentLine;
  1162.  
  1163.                                 if((NewCurrentLine = TopLine - NumBufferLines) < 0)
  1164.                                     NewCurrentLine = 0;
  1165.  
  1166.                                 MarkArea(-1,-1,-1);
  1167.  
  1168.                                 if(NewCurrentLine != TopLine)
  1169.                                 {
  1170.                                     DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1171.  
  1172.                                     LastChar = 0;
  1173.  
  1174.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1175.                                         PGA_Top,TopLine,
  1176.                                     TAG_DONE);
  1177.  
  1178.                                     UpdatePercent = TRUE;
  1179.                                 }
  1180.  
  1181.                                 break;
  1182.                             }
  1183.  
  1184.                             if(TopLine)
  1185.                             {
  1186.                                 MarkArea(-1,-1,-1);
  1187.  
  1188.                                 DisplayedLines = RedrawScreen(--TopLine);
  1189.  
  1190.                                 UpdatePercent = TRUE;
  1191.                             }
  1192.  
  1193.                             break;
  1194.  
  1195.                             /* Scroll the buffer down. */
  1196.  
  1197.                         case CDN:
  1198.  
  1199.                             if(MsgQualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  1200.                             {
  1201.                                 LONG NewCurrentLine;
  1202.  
  1203.                                 if((NewCurrentLine = Lines - NumBufferLines) < 0)
  1204.                                     NewCurrentLine = 0;
  1205.  
  1206.                                 MarkArea(-1,-1,-1);
  1207.  
  1208.                                 if(TopLine != NewCurrentLine)
  1209.                                 {
  1210.                                     DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1211.  
  1212.                                     LastChar = 0;
  1213.  
  1214.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1215.                                         PGA_Top,TopLine,
  1216.                                     TAG_DONE);
  1217.  
  1218.                                     UpdatePercent = TRUE;
  1219.                                 }
  1220.  
  1221.                                 break;
  1222.                             }
  1223.  
  1224.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1225.                             {
  1226.                                 LONG NewCurrentLine;
  1227.  
  1228.                                 if((NewCurrentLine = TopLine + (2 * NumBufferLines)) > Lines)
  1229.                                     NewCurrentLine = Lines;
  1230.  
  1231.                                 if((NewCurrentLine = NewCurrentLine - NumBufferLines) < 0)
  1232.                                     NewCurrentLine = 0;
  1233.  
  1234.                                 MarkArea(-1,-1,-1);
  1235.  
  1236.                                 if(NewCurrentLine != TopLine)
  1237.                                 {
  1238.                                     DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1239.  
  1240.                                     LastChar = 0;
  1241.  
  1242.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1243.                                         PGA_Top,TopLine,
  1244.                                     TAG_DONE);
  1245.  
  1246.                                     UpdatePercent = TRUE;
  1247.                                 }
  1248.  
  1249.                                 break;
  1250.                             }
  1251.  
  1252.                             if(TopLine + NumBufferLines < Lines)
  1253.                             {
  1254.                                 MarkArea(-1,-1,-1);
  1255.  
  1256.                                 DisplayedLines = RedrawScreen(++TopLine);
  1257.  
  1258.                                 UpdatePercent = TRUE;
  1259.                             }
  1260.  
  1261.                             break;
  1262.                     }
  1263.  
  1264.                     LastQualifier = MsgQualifier;
  1265.                 }
  1266.                 else
  1267.                     LastQualifier = NULL;
  1268.  
  1269.                 continue;
  1270.             }
  1271.  
  1272.                 /* User hit a mouse button. */
  1273.  
  1274.             if(MsgClass == IDCMP_MOUSEBUTTONS && (!ClickAndActivate || MsgCode != SELECTDOWN) && !(MsgCode & IECODE_UP_PREFIX))
  1275.             {
  1276.                 MarkArea(-1,-1,-1);
  1277.  
  1278.                     /* Reasonable dimensions? */
  1279.  
  1280.                 if(MouseY / LocalTextFontHeight < DisplayedLines && MouseX / LocalTextFontWidth < NumBufferColumns)
  1281.                 {
  1282.                     ObtainSemaphore(BufferSemaphore);
  1283.  
  1284.                     BufferClip();
  1285.  
  1286.                     UpdatePercent = TRUE;
  1287.  
  1288.                     LastTopLine = TopLine;
  1289.  
  1290.                     ReleaseSemaphore(BufferSemaphore);
  1291.  
  1292.                     if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1293.                     {
  1294.                         struct DataMsg Msg;
  1295.  
  1296.                         InitMsgItem(&Msg,BufferDestructor);
  1297.  
  1298.                         Msg . Type = DATAMSGTYPE_WRITECLIP;
  1299.                         Msg . Size = Config -> ClipConfig -> ClipboardUnit;
  1300.  
  1301.                         Forbid();
  1302.  
  1303.                         ClrSignal(1L << BufferSignal);
  1304.  
  1305.                         PutMsgItem(SpecialQueue,(struct MsgItem *)&Msg);
  1306.  
  1307.                         Wait(1L << BufferSignal);
  1308.  
  1309.                         Permit();
  1310.                     }
  1311.  
  1312.                     break;
  1313.                 }
  1314.             }
  1315.  
  1316.             if(MsgClass == IDCMP_MENUHELP)
  1317.                 GuideDisplay(CONTEXT_BUFFER_MENU);
  1318.  
  1319.             if(MsgClass == IDCMP_MENUPICK)
  1320.             {
  1321.                 struct MenuItem *MenuItem;
  1322.  
  1323.                 while(MsgCode != MENUNULL)
  1324.                 {
  1325.                     MenuItem = ItemAddress(BufferMenuStrip,MsgCode);
  1326.  
  1327.                     switch((ULONG)GTMENUITEM_USERDATA(MenuItem))
  1328.                     {
  1329.                         case MEN_SEARCH:
  1330.  
  1331.                             if(Context)
  1332.                                 LT_ShowWindow(Context -> SearchHandle,TRUE);
  1333.                             else
  1334.                                 Context = CreateSearchContext(BufferWindow,SearchBuffer,&HistoryHook,&SearchForward,&IgnoreCase,&WholeWords);
  1335.  
  1336.                             UpdatePercent = TRUE;
  1337.  
  1338.                             break;
  1339.  
  1340.                         case MEN_REPEAT:
  1341.  
  1342.                             if(Context)
  1343.                                 LT_ShowWindow(Context -> SearchHandle,TRUE);
  1344.                             else
  1345.                             {
  1346.                                 if(SearchInfo)
  1347.                                     StartSearch(SearchInfo,SearchBuffer);
  1348.                                 else
  1349.                                     Context = CreateSearchContext(BufferWindow,SearchBuffer,&HistoryHook,&SearchForward,&IgnoreCase,&WholeWords);
  1350.                             }
  1351.  
  1352.                             UpdatePercent = TRUE;
  1353.  
  1354.                             break;
  1355.  
  1356.                         case MEN_GOTO:
  1357.  
  1358.                             if(Window)
  1359.                                 BumpWindow(Window);
  1360.  
  1361.                             break;
  1362.  
  1363.                         case MEN_QUITBUF:
  1364.  
  1365.                             BufferTerminated = TRUE;
  1366.                             break;
  1367.  
  1368.                         case MEN_CLEARBUF_CONTENTS:
  1369.  
  1370.                             if(Lines)
  1371.                             {
  1372.                                 UpdatePercent = TRUE;
  1373.  
  1374.                                 LT_LockWindow(BufferWindow);
  1375.  
  1376.                                 if(MsgQualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1377.                                 {
  1378.                                     FreeBuffer();
  1379.  
  1380.                                     LT_UnlockWindow(BufferWindow);
  1381.  
  1382.                                     FlushMsg(BufferWindow);
  1383.  
  1384.                                     DisplayedLines = RedrawScreen(TopLine = 0);
  1385.  
  1386.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1387.                                         PGA_Top,    TopLine,
  1388.                                         PGA_Total,    Lines,
  1389.                                         PGA_Visible,    NumBufferLines,
  1390.                                     TAG_DONE);
  1391.  
  1392.                                     continue;
  1393.                                 }
  1394.                                 else
  1395.                                 {
  1396.                                     if(MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Lines))
  1397.                                     {
  1398.                                         FreeBuffer();
  1399.  
  1400.                                         LT_UnlockWindow(BufferWindow);
  1401.  
  1402.                                         FlushMsg(BufferWindow);
  1403.  
  1404.                                         DisplayedLines = RedrawScreen(TopLine = 0);
  1405.  
  1406.                                         SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1407.                                             PGA_Top,    TopLine,
  1408.                                             PGA_Total,    Lines,
  1409.                                             PGA_Visible,    NumBufferLines,
  1410.                                         TAG_DONE);
  1411.  
  1412.                                         continue;
  1413.                                     }
  1414.                                 }
  1415.  
  1416.                                 LT_UnlockWindow(BufferWindow);
  1417.  
  1418.                                 FlushMsg(BufferWindow);
  1419.                             }
  1420.  
  1421.                             break;
  1422.                     }
  1423.  
  1424.                     MsgCode = MenuItem -> NextSelect;
  1425.                 }
  1426.             }
  1427.  
  1428.         }
  1429.     }
  1430.     while(!BufferTerminated);
  1431.  
  1432.     if(Context)
  1433.         DeleteSearchContext(Context);
  1434.  
  1435.     if(SearchInfo)
  1436.         DeleteSearchInfo(SearchInfo);
  1437.  
  1438.     return(RingBack);
  1439. }
  1440.  
  1441.     /* BufferServer():
  1442.      *
  1443.      *    Asynchronous task to display the data stored in the
  1444.      *    scrollback display buffer.
  1445.      */
  1446.  
  1447. STATIC VOID __saveds
  1448. BufferServer(VOID)
  1449. {
  1450.     BOOLEAN             Defaults;
  1451.  
  1452.     struct ColorSpec     ColorSpec[3];
  1453.  
  1454.     LONG             Width,Height;
  1455.     ULONG             DisplayMode;
  1456.  
  1457.     struct Rectangle     DisplayClip;
  1458.     struct DimensionInfo     DimensionInfo;
  1459.  
  1460.     struct TextFont        *LocalFont;
  1461.  
  1462.     struct Task        *Father;
  1463.     BOOLEAN             RingBack = TRUE;
  1464.  
  1465.     Father = (struct Task *)SysBase -> ThisTask -> tc_UserData;
  1466.  
  1467.         /* Clone the global font data. */
  1468.  
  1469.     LocalTextFontWidth    = TextFontWidth;
  1470.     LocalTextFontHeight    = TextFontHeight;
  1471.     LocalTextFontBase    = TextFontBase;
  1472.  
  1473.     memcpy(&LocalTextFont,&TextAttr,sizeof(struct TTextAttr));
  1474.  
  1475.     LocalTextFont . tta_Name = LocalTextFontName;
  1476.  
  1477.     strcpy(LocalTextFontName,TextAttr . tta_Name);
  1478.  
  1479.     memcpy(&LocalUserFont,&UserFont,sizeof(struct TTextAttr));
  1480.  
  1481.     LocalUserFont . tta_Name = LocalUserFontName;
  1482.  
  1483.     strcpy(LocalUserFontName,UserFont . tta_Name);
  1484.  
  1485.         /* Reset top line index. */
  1486.  
  1487.     LastTopLine = -1;
  1488.  
  1489.         /* Up and running... */
  1490.  
  1491.     BufferTerminated = FALSE;
  1492.  
  1493.     Forbid();
  1494.  
  1495.     if(Window && DrawInfo)
  1496.     {
  1497.         UWORD Colour;
  1498.  
  1499.             /* Set up the startup colours for our buffer screen. */
  1500.  
  1501.         ColorSpec[0] . ColorIndex = 0;
  1502.         Colour = GetRGB4(Window -> WScreen -> ViewPort . ColorMap,DrawInfo -> dri_Pens[BACKGROUNDPEN]);
  1503.  
  1504.         ColorSpec[0] . Red        = (Colour >> 8) & 0xF;
  1505.         ColorSpec[0] . Green        = (Colour >> 4) & 0xF;
  1506.         ColorSpec[0] . Blue        = (Colour     ) & 0xF;
  1507.  
  1508.         ColorSpec[1] . ColorIndex = 1;
  1509.         Colour = GetRGB4(Window -> WScreen -> ViewPort . ColorMap,DrawInfo -> dri_Pens[TEXTPEN]);
  1510.  
  1511.         ColorSpec[1] . Red        = (Colour >> 8) & 0xF;
  1512.         ColorSpec[1] . Green        = (Colour >> 4) & 0xF;
  1513.         ColorSpec[1] . Blue        = (Colour     ) & 0xF;
  1514.  
  1515.         ColorSpec[2] . ColorIndex = -1;
  1516.  
  1517.         Defaults = FALSE;
  1518.     }
  1519.     else
  1520.         Defaults = TRUE;
  1521.  
  1522.     Permit();
  1523.  
  1524.         /* We'll use a fixed screen width, only the
  1525.          * height is adapted from the main screen.
  1526.          */
  1527.  
  1528.     DisplayMode = Config -> CaptureConfig -> BufferScreenMode;
  1529.  
  1530.     if(ModeNotAvailable(DisplayMode))
  1531.         DisplayMode = Config -> ScreenConfig -> DisplayMode;
  1532.  
  1533.     if(ModeNotAvailable(DisplayMode))
  1534.     {
  1535.         struct Screen *PubScreen = LockPubScreen(NULL);
  1536.  
  1537.         if(PubScreen)
  1538.         {
  1539.             DisplayMode = GetVPModeID(&PubScreen -> ViewPort);
  1540.  
  1541.             UnlockPubScreen(NULL,PubScreen);
  1542.         }
  1543.         else
  1544.             DisplayMode = DEFAULT_MONITOR_ID | HIRES_KEY;
  1545.     }
  1546.  
  1547.         /* Set up the actual width of the screen we want. */
  1548.  
  1549.     Width = Config -> CaptureConfig -> BufferWidth * LocalTextFontWidth + ArrowWidth + 1;
  1550.  
  1551.     if((BufferSignal = AllocSignal(-1)) != -1)
  1552.     {
  1553.             /* Get the mode dimension info. */
  1554.  
  1555.         if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,DisplayMode))
  1556.         {
  1557.                 /* Determine maximum text overscan width. */
  1558.  
  1559.             LONG TextWidth = DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1;
  1560.  
  1561.                 /* Too small? */
  1562.  
  1563.             if(Width < DimensionInfo . MinRasterWidth)
  1564.                 Width = DimensionInfo . MinRasterWidth;
  1565.  
  1566.                 /* Far too large? */
  1567.  
  1568.             if(Width > DimensionInfo . MaxRasterWidth)
  1569.                 Width = DimensionInfo . MaxRasterWidth;
  1570.  
  1571.                 /* A bit too large? */
  1572.  
  1573.             if(Width > TextWidth)
  1574.                 Width = TextWidth;
  1575.  
  1576.             if(LocalFont = OpenFont(&LocalTextFont))
  1577.             {
  1578.                     /* Inquire the text overscan dimensions. */
  1579.  
  1580.                 if(QueryOverscan(DisplayMode,&DisplayClip,OSCAN_TEXT))
  1581.                 {
  1582.                         /* Centre the buffer screen. */
  1583.  
  1584.                     if(DisplayClip . MaxX - DisplayClip . MinX + 1 > Width)
  1585.                     {
  1586.                         LONG Differ = (DisplayClip . MaxX - DisplayClip . MinX + 1 - Width) / 2;
  1587.  
  1588.                         switch(Config -> CaptureConfig -> BufferScreenPosition)
  1589.                         {
  1590.                             case SCREEN_LEFT:
  1591.  
  1592.                                 DisplayClip . MaxX = DisplayClip . MinX + Width;
  1593.                                 break;
  1594.  
  1595.                             case SCREEN_RIGHT:
  1596.  
  1597.                                 DisplayClip . MinX = DisplayClip . MaxX - Width;
  1598.                                 break;
  1599.  
  1600.                             case SCREEN_CENTRE:
  1601.  
  1602.                                 DisplayClip . MinX += Differ;
  1603.                                 DisplayClip . MaxX -= Differ;
  1604.  
  1605.                                 break;
  1606.                         }
  1607.                     }
  1608.  
  1609.                         /* Open a single bitplane clone of the main screen. */
  1610.  
  1611.                     if(BufferScreen = (struct Screen *)OpenScreenTags(NULL,
  1612.                         SA_Title,    LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),
  1613.                         SA_Depth,    1,
  1614.                         SA_DClip,    &DisplayClip,
  1615.                         SA_DisplayID,    DisplayMode,
  1616.                         SA_Font,    &LocalUserFont,
  1617.                         SA_Behind,    TRUE,
  1618.                         SA_AutoScroll,    TRUE,
  1619.  
  1620.                         Defaults ? TAG_IGNORE : SA_Colors,ColorSpec,
  1621.                     TAG_END))
  1622.                     {
  1623.                         if(BufferVisualInfo = GetVisualInfo(BufferScreen,TAG_DONE))
  1624.                         {
  1625.                             LocalizeMenu(BufferMenu,MSG_TERMBUFFER_PROJECT_MEN);
  1626.  
  1627.                             if(BufferMenuStrip = CreateMenus(BufferMenu,TAG_DONE))
  1628.                             {
  1629.                                 if(BufferDrawInfo = GetScreenDrawInfo(BufferScreen))
  1630.                                 {
  1631.                                     if(!CreateMenuGlyphs(BufferScreen,BufferDrawInfo,&BufferAmigaGlyph,&BufferCheckGlyph))
  1632.                                     {
  1633.                                         FreeScreenDrawInfo(BufferScreen,BufferDrawInfo);
  1634.  
  1635.                                         BufferDrawInfo = NULL;
  1636.                                     }
  1637.                                 }
  1638.  
  1639.                                 if(LayoutMenus(BufferMenuStrip,BufferVisualInfo,
  1640.                                     BufferAmigaGlyph ? GTMN_AmigaKey :  TAG_IGNORE, BufferAmigaGlyph,
  1641.                                     BufferCheckGlyph ? GTMN_Checkmark : TAG_IGNORE, BufferCheckGlyph,
  1642.  
  1643.                                     GTMN_TextAttr,        &LocalUserFont,
  1644.                                     GTMN_NewLookMenus,    TRUE,
  1645.                                 TAG_DONE))
  1646.                                 {
  1647.                                     Height = (BufferScreen -> Height - (BufferScreen -> BarHeight + 2)) / LocalTextFontHeight;
  1648.  
  1649.                                         /* Open a cute window on our buffer screen. */
  1650.  
  1651.                                     if(BufferWindow = OpenWindowTags(NULL,
  1652.                                         WA_Top,        BufferScreen -> BarHeight + 2,
  1653.                                         WA_Left,    0,
  1654.                                         WA_Width,    BufferScreen -> Width,
  1655.                                         WA_Height,    Height * LocalTextFontHeight,
  1656.                                         WA_Backdrop,    TRUE,
  1657.                                         WA_Borderless,    TRUE,
  1658.                                         WA_SmartRefresh,FALSE,
  1659.                                         WA_CustomScreen,BufferScreen,
  1660.                                         WA_RMBTrap,    TRUE,
  1661.                                         WA_NewLookMenus,TRUE,
  1662.                                         WA_RptQueue,    1,
  1663.                                         WA_IDCMP,    IDCMP_IDCMPUPDATE | IDCMP_RAWKEY | IDCMP_INACTIVEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_MENUPICK | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE | IDCMP_MENUHELP,
  1664.                                         WA_MenuHelp,    TRUE,
  1665.  
  1666.                                         BufferAmigaGlyph ? WA_AmigaKey  : TAG_IGNORE, BufferAmigaGlyph,
  1667.                                         BufferCheckGlyph ? WA_Checkmark : TAG_IGNORE, BufferCheckGlyph,
  1668.                                     TAG_DONE))
  1669.                                     {
  1670.                                         if(BufferLineWidths = (UWORD *)AllocVecPooled(2 * sizeof(UWORD) * (BufferWindow -> Height / LocalTextFontHeight + 1) + sizeof(UWORD) * (BufferWindow -> Width / LocalTextFontWidth + 1),MEMF_ANY | MEMF_CLEAR))
  1671.                                         {
  1672.                                             UWORD    Index;
  1673.                                             WORD    i;
  1674.  
  1675.                                             BufferLineOffsets    = &BufferLineWidths[BufferWindow -> Height / LocalTextFontHeight + 1];
  1676.                                             BufferColumnOffsets    = &BufferLineOffsets[BufferWindow -> Height / LocalTextFontHeight + 1];
  1677.  
  1678.                                             for(i = Index = 0 ; i < BufferWindow -> Height / LocalTextFontHeight + 1 ; i++)
  1679.                                             {
  1680.                                                 BufferLineOffsets[i] = Index;
  1681.  
  1682.                                                 Index += LocalTextFontHeight;
  1683.                                             }
  1684.  
  1685.                                             for(i = Index = 0 ; i < BufferWindow -> Width / LocalTextFontWidth + 1 ; i++)
  1686.                                             {
  1687.                                                 BufferColumnOffsets[i] = Index;
  1688.  
  1689.                                                 Index += LocalTextFontWidth;
  1690.                                             }
  1691.  
  1692.                                             if(CreateScroller(BufferWindow -> Height))
  1693.                                             {
  1694.                                                 ObtainSemaphore(&BufferTaskSemaphore);
  1695.  
  1696.                                                 BufferTask = SysBase -> ThisTask;
  1697.  
  1698.                                                 ReleaseSemaphore(&BufferTaskSemaphore);
  1699.  
  1700.                                                     /* Signal our father process that
  1701.                                                      * we're running.
  1702.                                                      */
  1703.  
  1704.                                                 Signal(Father,SIG_HANDSHAKE);
  1705.  
  1706.                                                 Father = NULL;
  1707.  
  1708.                                                 SetMenuStrip(BufferWindow,BufferMenuStrip);
  1709.  
  1710.                                                 AddGList(BufferWindow,Scroller,(UWORD)-1,(UWORD)-1,NULL);
  1711.                                                 RefreshGList(Scroller,BufferWindow,NULL,(UWORD)-1);
  1712.  
  1713.                                                     /* Determine maximum dimensions of
  1714.                                                      * the buffer screen (in rows and
  1715.                                                      * columns).
  1716.                                                      */
  1717.  
  1718.                                                 NumBufferColumns    = (BufferWindow -> Width - (ArrowWidth + 1)) / LocalTextFontWidth;
  1719.                                                 NumBufferLines        = BufferWindow -> Height / LocalTextFontHeight;
  1720.  
  1721.                                                 if(TopLine == -1 || !Config -> CaptureConfig -> RememberBufferScreen)
  1722.                                                 {
  1723.                                                     switch(Config -> CaptureConfig -> OpenBufferScreen)
  1724.                                                     {
  1725.                                                         case BUFFER_TOP:
  1726.  
  1727.                                                             TopLine = 0;
  1728.                                                             break;
  1729.  
  1730.                                                         case BUFFER_END:
  1731.  
  1732.                                                             if((TopLine = Lines - NumBufferLines) < 0)
  1733.                                                                 TopLine = 0;
  1734.  
  1735.                                                             break;
  1736.  
  1737.                                                         default:
  1738.  
  1739.                                                             TopLine = 0;
  1740.                                                             break;
  1741.                                                     }
  1742.                                                 }
  1743.  
  1744.                                                 if(TopLine > Lines - NumBufferLines)
  1745.                                                     TopLine = 0;
  1746.  
  1747.                                                 BPort = BufferWindow -> RPort;
  1748.  
  1749.                                                 SetFont(BPort,LocalFont);
  1750.  
  1751.                                                     /* Bring the screen to the front. */
  1752.  
  1753.                                                 BumpWindow(BufferWindow);
  1754.  
  1755.                                                     /* Set the drawing pens for the window. */
  1756.  
  1757.                                                 SetAPen(BPort,1);
  1758.                                                 SetBPen(BPort,0);
  1759.                                                 SetDrMd(BPort,JAM2);
  1760.  
  1761.                                                     /* Initial creation of the buffer display. */
  1762.  
  1763.                                                 DisplayedLines = RedrawScreen(TopLine);
  1764.  
  1765.                                                 SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1766.                                                     PGA_Top,    TopLine,
  1767.                                                     PGA_Total,    Lines,
  1768.                                                     PGA_Visible,    NumBufferLines,
  1769.                                                 TAG_DONE);
  1770.  
  1771.                                                 BufferWindow -> Flags &= ~WFLG_RMBTRAP;
  1772.  
  1773.                                                 RingBack = HandleBuffer(TextLength(BufferScreen -> BarLayer -> rp,LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),strlen(LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT))) + TextLength(BufferScreen -> BarLayer -> rp," ",1) + 4);
  1774.  
  1775.                                                 RemoveGList(BufferWindow,Scroller,(UWORD)-1);
  1776.  
  1777.                                                 DeleteScroller();
  1778.                                             }
  1779.  
  1780.                                             FreeVecPooled(BufferLineWidths);
  1781.                                         }
  1782.  
  1783.                                         if(Window)
  1784.                                             BumpWindow(Window);
  1785.  
  1786.                                         MarkArea(-1,-1,-1);
  1787.  
  1788.                                         ScreenToBack(BufferScreen);
  1789.  
  1790.                                         BufferWindow -> Flags |= WFLG_RMBTRAP;
  1791.  
  1792.                                         ClearMenuStrip(BufferWindow);
  1793.  
  1794.                                         LT_DeleteWindowLock(BufferWindow);
  1795.  
  1796.                                         CloseWindow(BufferWindow);
  1797.                                     }
  1798.                                 }
  1799.  
  1800.                                 DisposeObject(BufferAmigaGlyph);
  1801.                                 DisposeObject(BufferCheckGlyph);
  1802.  
  1803.                                 FreeScreenDrawInfo(BufferScreen,BufferDrawInfo);
  1804.  
  1805.                                 FreeMenus(BufferMenuStrip);
  1806.                             }
  1807.  
  1808.                             FreeVisualInfo(BufferVisualInfo);
  1809.                         }
  1810.  
  1811.                         CloseScreen(BufferScreen);
  1812.                     }
  1813.                 }
  1814.  
  1815.                 CloseFont(LocalFont);
  1816.             }
  1817.         }
  1818.  
  1819.         FreeSignal(BufferSignal);
  1820.     }
  1821.  
  1822.     ObtainSemaphore(&BufferTaskSemaphore);
  1823.  
  1824.     BufferTask = NULL;
  1825.  
  1826.     ReleaseSemaphore(&BufferTaskSemaphore);
  1827.  
  1828.     Forbid();
  1829.  
  1830.     if(RingBack)
  1831.     {
  1832.         if(Father)
  1833.             Signal(Father,SIG_HANDSHAKE);
  1834.         else
  1835.             Signal(ThisProcess,SIG_HANDSHAKE);
  1836.     }
  1837. }
  1838.  
  1839.     /* LaunchBuffer():
  1840.      *
  1841.      *    Launch the buffer process.
  1842.      */
  1843.  
  1844. BYTE
  1845. LaunchBuffer()
  1846. {
  1847.     ObtainSemaphore(&BufferTaskSemaphore);
  1848.  
  1849.         /* Is the buffer process already running? */
  1850.  
  1851.     if(BufferTask)
  1852.     {
  1853.             /* Tell it to bring its screen to the front. */
  1854.  
  1855.         Signal(BufferTask,SIG_TOFRONT);
  1856.  
  1857.         ReleaseSemaphore(&BufferTaskSemaphore);
  1858.  
  1859.             /* Return success. */
  1860.  
  1861.         return(TRUE);
  1862.     }
  1863.     else
  1864.     {
  1865.         struct Task    *Child;
  1866.         BYTE         Result = FALSE;
  1867.  
  1868.         ReleaseSemaphore(&BufferTaskSemaphore);
  1869.  
  1870.         Forbid();
  1871.  
  1872.             /* Launch the buffer process. */
  1873.  
  1874.         if(Child = (struct Task *)CreateNewProcTags(
  1875.             NP_Entry,    BufferServer,
  1876.             NP_Name,    "term Buffer Process",
  1877.             NP_Priority,    SysBase -> ThisTask -> tc_Node . ln_Pri,
  1878.             NP_StackSize,    4000,
  1879.             NP_WindowPtr,    -1,
  1880.         TAG_END))
  1881.         {
  1882.             Child -> tc_UserData = SysBase -> ThisTask;
  1883.  
  1884.             ClrSignal(SIG_HANDSHAKE);
  1885.  
  1886.             Wait(SIG_HANDSHAKE);
  1887.  
  1888.             ObtainSemaphore(&BufferTaskSemaphore);
  1889.  
  1890.             if(BufferTask)
  1891.                 Result = TRUE;
  1892.  
  1893.             ReleaseSemaphore(&BufferTaskSemaphore);
  1894.         }
  1895.  
  1896.         Permit();
  1897.  
  1898.             /* Return the result. */
  1899.  
  1900.         return(Result);
  1901.     }
  1902. }
  1903.  
  1904.     /* TerminateBuffer():
  1905.      *
  1906.      *    Terminate the buffer process.
  1907.      */
  1908.  
  1909. VOID
  1910. TerminateBuffer()
  1911. {
  1912.     ObtainSemaphore(&BufferTaskSemaphore);
  1913.  
  1914.     if(BufferTask)
  1915.     {
  1916.         Forbid();
  1917.  
  1918.         Signal(BufferTask,SIG_KILL);
  1919.  
  1920.         ReleaseSemaphore(&BufferTaskSemaphore);
  1921.  
  1922.         ClrSignal(SIG_HANDSHAKE);
  1923.  
  1924.         Wait(SIG_HANDSHAKE);
  1925.  
  1926.         Permit();
  1927.     }
  1928.     else
  1929.         ReleaseSemaphore(&BufferTaskSemaphore);
  1930.  
  1931.     LastTopLine = -1;
  1932. }
  1933.