Sorting source tree a bit
[tpg/acess2.git] / KernelLand / Kernel / drv / vterm_termbuf.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * drv/vterm_termbuf.c
6  * - Virtual Terminal - Terminal buffer manipulation
7  */
8 #include "vterm.h"
9
10 // === CODE ===
11
12 /**
13  * \fn void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
14  * \brief Print a string to the Virtual Terminal
15  */
16 void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
17 {
18         Uint32  val;
19          int    i;
20         
21         // Iterate
22         for( i = 0; i < Count; i++ )
23         {
24                 // Handle escape sequences
25                 if( Buffer[i] == 0x1B )
26                 {
27                         i ++;
28                         i += VT_int_ParseEscape(Term, (const char*)&Buffer[i]) - 1;
29                         continue;
30                 }
31                 
32                 // Fast check for non UTF-8
33                 if( Buffer[i] < 128 )   // Plain ASCII
34                         VT_int_PutChar(Term, Buffer[i]);
35                 else {  // UTF-8
36                         i += ReadUTF8(&Buffer[i], &val) - 1;
37                         VT_int_PutChar(Term, val);
38                 }
39         }
40         // Update Screen
41         VT_int_UpdateScreen( Term, 0 );
42 }
43
44 /**
45  * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
46  * \brief Write a single character to a VTerm
47  */
48 void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
49 {
50          int    i;
51         tVT_Char        *buffer;
52          int    write_pos;
53         
54         if(Term->Flags & VT_FLAG_ALTBUF) {
55                 buffer = Term->AltBuf;
56                 write_pos = Term->AltWritePos;
57         }
58         else {
59                 buffer = Term->Text;
60                 write_pos = Term->WritePos;
61         }
62         
63         switch(Ch)
64         {
65         case '\0':      return; // Ignore NULL byte
66         case '\n':
67                 VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
68                 write_pos += Term->TextWidth;
69         case '\r':
70                 write_pos -= write_pos % Term->TextWidth;
71                 break;
72         
73         case '\t': { int tmp = write_pos / Term->TextWidth;
74                 write_pos %= Term->TextWidth;
75                 do {
76                         buffer[ write_pos ].Ch = '\0';
77                         buffer[ write_pos ].Colour = Term->CurColour;
78                         write_pos ++;
79                 } while(write_pos & 7);
80                 write_pos += tmp * Term->TextWidth;
81                 break; }
82         
83         case '\b':
84                 // Backspace is invalid at Offset 0
85                 if(write_pos == 0)      break;
86                 
87                 write_pos --;
88                 // Singe Character
89                 if(buffer[ write_pos ].Ch != '\0') {
90                         buffer[ write_pos ].Ch = 0;
91                         buffer[ write_pos ].Colour = Term->CurColour;
92                         break;
93                 }
94                 // Tab
95                 i = 7;  // Limit it to 8
96                 do {
97                         buffer[ write_pos ].Ch = 0;
98                         buffer[ write_pos ].Colour = Term->CurColour;
99                         write_pos --;
100                 } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
101                 if(buffer[ write_pos ].Ch != '\0')
102                         write_pos ++;
103                 break;
104         
105         default:
106                 buffer[ write_pos ].Ch = Ch;
107                 buffer[ write_pos ].Colour = Term->CurColour;
108                 // Update the line before wrapping
109                 if( (write_pos + 1) % Term->TextWidth == 0 )
110                         VT_int_UpdateScreen( Term, 0 );
111                 write_pos ++;
112                 break;
113         }
114         
115         if(Term->Flags & VT_FLAG_ALTBUF)
116         {
117                 Term->AltBuf = buffer;
118                 Term->AltWritePos = write_pos;
119                 
120                 if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
121                 {
122                         Term->AltWritePos -= Term->TextWidth;
123                         VT_int_ScrollText(Term, 1);
124                 }
125                 
126         }
127         else
128         {
129                 Term->Text = buffer;
130                 Term->WritePos = write_pos;
131                 // Move Screen
132                 // - Check if we need to scroll the entire scrollback buffer
133                 if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
134                 {
135                          int    base;
136                         
137                         // Update previous line
138                         Term->WritePos -= Term->TextWidth;
139                         VT_int_UpdateScreen( Term, 0 );
140                         
141                         // Update view position
142                         base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
143                         if(Term->ViewPos < base)
144                                 Term->ViewPos += Term->Width;
145                         if(Term->ViewPos > base)
146                                 Term->ViewPos = base;
147                         
148                         VT_int_ScrollText(Term, 1);
149                 }
150                 // Ok, so we only need to scroll the screen
151                 else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
152                 {
153                         // Update the last line
154                         Term->WritePos -= Term->TextWidth;
155                         VT_int_UpdateScreen( Term, 0 );
156                         Term->WritePos += Term->TextWidth;
157                         
158                         VT_int_ScrollText(Term, 1);
159                         
160                         Term->ViewPos += Term->TextWidth;
161                 }
162         }
163         
164         //LEAVE('-');
165 }
166
167 void VT_int_ScrollText(tVTerm *Term, int Count)
168 {
169         tVT_Char        *buf;
170          int    height, init_write_pos;
171          int    len, i;
172          int    scroll_top, scroll_height;
173
174         // Get buffer pointer and attributes    
175         if( Term->Flags & VT_FLAG_ALTBUF )
176         {
177                 buf = Term->AltBuf;
178                 height = Term->TextHeight;
179                 init_write_pos = Term->AltWritePos;
180                 scroll_top = Term->ScrollTop;
181                 scroll_height = Term->ScrollHeight;
182         }
183         else
184         {
185                 buf = Term->Text;
186                 height = Term->TextHeight*(giVT_Scrollback+1);
187                 init_write_pos = Term->WritePos;
188                 scroll_top = 0;
189                 scroll_height = height;
190         }
191
192         // Scroll text downwards        
193         if( Count > 0 )
194         {
195                  int    base;
196         
197                 // Set up
198                 if(Count > scroll_height)       Count = scroll_height;
199                 base = Term->TextWidth*(scroll_top + scroll_height - Count);
200                 len = Term->TextWidth*(scroll_height - Count);
201                 
202                 // Scroll terminal cache
203                 memmove(
204                         &buf[Term->TextWidth*scroll_top],
205                         &buf[Term->TextWidth*(scroll_top+Count)],
206                         len*sizeof(tVT_Char)
207                         );
208                 // Clear last rows
209                 for( i = 0; i < Term->TextWidth*Count; i ++ )
210                 {
211                         buf[ base + i ].Ch = 0;
212                         buf[ base + i ].Colour = Term->CurColour;
213                 }
214                 
215                 // Update Screen
216                 VT_int_ScrollFramebuffer( Term, Count );
217                 if( Term->Flags & VT_FLAG_ALTBUF )
218                         Term->AltWritePos = base;
219                 else
220                         Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
221                 for( i = 0; i < Count; i ++ )
222                 {
223                         VT_int_UpdateScreen( Term, 0 );
224                         if( Term->Flags & VT_FLAG_ALTBUF )
225                                 Term->AltWritePos += Term->TextWidth;
226                         else
227                                 Term->WritePos += Term->TextWidth;
228                 }
229         }
230         else
231         {
232                 Count = -Count;
233                 if(Count > scroll_height)       Count = scroll_height;
234                 
235                 len = Term->TextWidth*(scroll_height - Count);
236                 
237                 // Scroll terminal cache
238                 memmove(
239                         &buf[Term->TextWidth*(scroll_top+Count)],
240                         &buf[Term->TextWidth*scroll_top],
241                         len*sizeof(tVT_Char)
242                         );
243                 // Clear preceding rows
244                 for( i = 0; i < Term->TextWidth*Count; i ++ )
245                 {
246                         buf[ i ].Ch = 0;
247                         buf[ i ].Colour = Term->CurColour;
248                 }
249                 
250                 VT_int_ScrollFramebuffer( Term, -Count );
251                 if( Term->Flags & VT_FLAG_ALTBUF )
252                         Term->AltWritePos = Term->TextWidth*scroll_top;
253                 else
254                         Term->WritePos = Term->ViewPos;
255                 for( i = 0; i < Count; i ++ )
256                 {
257                         VT_int_UpdateScreen( Term, 0 );
258                         if( Term->Flags & VT_FLAG_ALTBUF )
259                                 Term->AltWritePos += Term->TextWidth;
260                         else
261                                 Term->WritePos += Term->TextWidth;
262                 }
263         }
264         
265         if( Term->Flags & VT_FLAG_ALTBUF )
266                 Term->AltWritePos = init_write_pos;
267         else
268                 Term->WritePos = init_write_pos;
269 }
270
271 /**
272  * \brief Clears a line in a virtual terminal
273  * \param Term  Terminal to modify
274  * \param Num   Line number to clear
275  */
276 void VT_int_ClearLine(tVTerm *Term, int Num)
277 {
278          int    i;
279         tVT_Char        *cell;
280         
281         if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) )        return ;
282         
283         cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
284         cell = &cell[ Num*Term->TextWidth ];
285         
286         for( i = Term->TextWidth; i--; )
287         {
288                 cell[ i ].Ch = 0;
289                 cell[ i ].Colour = Term->CurColour;
290         }
291 }
292
293 /**
294  * \brief Update the screen mode
295  * \param Term  Terminal to update
296  * \param NewMode       New mode to set
297  * \param NewWidth      New framebuffer width
298  * \param NewHeight     New framebuffer height
299  */
300 void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
301 {
302          int    oldW = Term->Width;
303          int    oldTW = Term->TextWidth;
304          int    oldH = Term->Height;
305          int    oldTH = Term->TextHeight;
306         tVT_Char        *oldTBuf = Term->Text;
307         Uint32  *oldFB = Term->Buffer;
308          int    w, h, i;
309         
310         // TODO: Increase RealWidth/RealHeight when this happens
311         if(NewWidth > giVT_RealWidth)   NewWidth = giVT_RealWidth;
312         if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
313         
314         Term->Mode = NewMode;
315
316         // Fast exit if no resolution change
317         if(NewWidth == Term->Width && NewHeight == Term->Height)
318                 return ;
319         
320         // Calculate new dimensions
321         Term->Width = NewWidth;
322         Term->Height = NewHeight;
323         Term->TextWidth = NewWidth / giVT_CharWidth;
324         Term->TextHeight = NewHeight / giVT_CharHeight;
325         Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
326         
327         // Allocate new buffers
328         // - Text
329         Term->Text = calloc(
330                 Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
331                 sizeof(tVT_Char)
332                 );
333         if(oldTBuf) {
334                 // Copy old buffer
335                 w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
336                 h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
337                 h *= giVT_Scrollback + 1;
338                 for( i = 0; i < h; i ++ )
339                 {
340                         memcpy(
341                                 &Term->Text[i*Term->TextWidth],
342                                 &oldTBuf[i*oldTW],
343                                 w*sizeof(tVT_Char)
344                                 );      
345                 }
346                 free(oldTBuf);
347         }
348         
349         // - Alternate Text
350         Term->AltBuf = realloc(
351                 Term->AltBuf,
352                 Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
353                 );
354         
355         // - Framebuffer
356         if(oldFB) {
357                 Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
358                 // Copy old buffer
359                 w = (oldW > Term->Width) ? Term->Width : oldW;
360                 h = (oldH > Term->Height) ? Term->Height : oldH;
361                 for( i = 0; i < h; i ++ )
362                 {
363                         memcpy(
364                                 &Term->Buffer[i*Term->Width],
365                                 &oldFB[i*oldW],
366                                 w*sizeof(Uint32)
367                                 );
368                 }
369                 free(oldFB);
370         }
371         
372         // Debug
373         switch(NewMode)
374         {
375         case TERM_MODE_TEXT:
376                 Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
377                         Term, Term->TextWidth, Term->TextHeight);
378                 break;
379         case TERM_MODE_FB:
380                 Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
381                         Term, Term->Width, Term->Height);
382                 break;
383         //case TERM_MODE_2DACCEL:
384         //case TERM_MODE_3DACCEL:
385         //      return;
386         }
387 }
388
389
390 void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
391 {       
392         if(Enabled)
393                 Term->Flags |= VT_FLAG_ALTBUF;
394         else
395                 Term->Flags &= ~VT_FLAG_ALTBUF;
396         VT_int_UpdateScreen(Term, 1);
397 }
398

UCC git Repository :: git.ucc.asn.au