Kernel - Fixed screen not updating in VT framebuffer mode
[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': {
74                 int line = write_pos / Term->TextWidth;
75                 write_pos %= Term->TextWidth;
76                 do {
77                         buffer[ write_pos ].Ch = '\0';
78                         buffer[ write_pos ].Colour = Term->CurColour;
79                         write_pos ++;
80                 } while(write_pos & 7);
81                 write_pos += line * Term->TextWidth;
82                 break; }
83         
84         case '\b':
85                 // Backspace is invalid at Offset 0
86                 if(write_pos == 0)      break;
87                 
88                 write_pos --;
89                 // Single Character
90                 if(buffer[ write_pos ].Ch != '\0') {
91                         buffer[ write_pos ].Ch = 0;
92                         buffer[ write_pos ].Colour = Term->CurColour;
93                         break;
94                 }
95                 // Tab
96                 i = 7;  // Limit it to 8
97                 do {
98                         buffer[ write_pos ].Ch = 0;
99                         buffer[ write_pos ].Colour = Term->CurColour;
100                         write_pos --;
101                 } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
102                 if(buffer[ write_pos ].Ch != '\0')
103                         write_pos ++;
104                 break;
105         
106         default:
107                 buffer[ write_pos ].Ch = Ch;
108                 buffer[ write_pos ].Colour = Term->CurColour;
109                 // Update the line before wrapping
110                 if( (write_pos + 1) % Term->TextWidth == 0 )
111                         VT_int_UpdateScreen( Term, 0 );
112                 write_pos ++;
113                 break;
114         }
115         
116         if(Term->Flags & VT_FLAG_ALTBUF)
117         {
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->WritePos = write_pos;
130                 // Move Screen
131                 // - Check if we need to scroll the entire scrollback buffer
132                 if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
133                 {
134                          int    base;
135                         
136                         // Update view position
137                         base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
138                         if(Term->ViewPos < base)
139                                 Term->ViewPos += Term->Width;
140                         if(Term->ViewPos > base)
141                                 Term->ViewPos = base;
142                         
143                         VT_int_ScrollText(Term, 1);
144                         Term->WritePos -= Term->TextWidth;
145                 }
146                 // Ok, so we only need to scroll the screen
147                 else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
148                 {
149                         VT_int_ScrollFramebuffer( Term, 1 );
150                         
151                         Term->ViewPos += Term->TextWidth;
152                 }
153         }
154         
155         //LEAVE('-');
156 }
157
158 void VT_int_ScrollText(tVTerm *Term, int Count)
159 {
160         tVT_Char        *buf;
161          int    height, init_write_pos;
162          int    len, i;
163          int    scroll_top, scroll_height;
164
165         // Get buffer pointer and attributes    
166         if( Term->Flags & VT_FLAG_ALTBUF )
167         {
168                 buf = Term->AltBuf;
169                 height = Term->TextHeight;
170                 init_write_pos = Term->AltWritePos;
171                 scroll_top = Term->ScrollTop;
172                 scroll_height = Term->ScrollHeight;
173         }
174         else
175         {
176                 buf = Term->Text;
177                 height = Term->TextHeight*(giVT_Scrollback+1);
178                 init_write_pos = Term->WritePos;
179                 scroll_top = 0;
180                 scroll_height = height;
181         }
182
183         // Scroll text upwards (more space at bottom)
184         if( Count > 0 )
185         {
186                  int    base;
187         
188                 // Set up
189                 if(Count > scroll_height)       Count = scroll_height;
190                 base = Term->TextWidth*(scroll_top + scroll_height - Count);
191                 len = Term->TextWidth*(scroll_height - Count);
192                 
193                 // Scroll terminal cache
194                 memmove(
195                         &buf[Term->TextWidth*scroll_top],
196                         &buf[Term->TextWidth*(scroll_top+Count)],
197                         len*sizeof(tVT_Char)
198                         );
199                 // Clear last rows
200                 for( i = 0; i < Term->TextWidth*Count; i ++ )
201                 {
202                         buf[ base + i ].Ch = 0;
203                         buf[ base + i ].Colour = Term->CurColour;
204                 }
205                 
206                 // Update Screen
207                 VT_int_ScrollFramebuffer( Term, Count );
208                 if( Term->Flags & VT_FLAG_ALTBUF )
209                         Term->AltWritePos = base;
210                 else
211                         Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
212                 for( i = 0; i < Count; i ++ )
213                 {
214                         VT_int_UpdateScreen( Term, 0 );
215                         if( Term->Flags & VT_FLAG_ALTBUF )
216                                 Term->AltWritePos += Term->TextWidth;
217                         else
218                                 Term->WritePos += Term->TextWidth;
219                 }
220         }
221         else
222         {
223                 Count = -Count;
224                 if(Count > scroll_height)       Count = scroll_height;
225                 
226                 len = Term->TextWidth*(scroll_height - Count);
227                 
228                 // Scroll terminal cache
229                 memmove(
230                         &buf[Term->TextWidth*(scroll_top+Count)],
231                         &buf[Term->TextWidth*scroll_top],
232                         len*sizeof(tVT_Char)
233                         );
234                 // Clear preceding rows
235                 for( i = 0; i < Term->TextWidth*Count; i ++ )
236                 {
237                         buf[ i ].Ch = 0;
238                         buf[ i ].Colour = Term->CurColour;
239                 }
240                 
241                 VT_int_ScrollFramebuffer( Term, -Count );
242                 if( Term->Flags & VT_FLAG_ALTBUF )
243                         Term->AltWritePos = Term->TextWidth*scroll_top;
244                 else
245                         Term->WritePos = Term->ViewPos;
246                 for( i = 0; i < Count; i ++ )
247                 {
248                         VT_int_UpdateScreen( Term, 0 );
249                         if( Term->Flags & VT_FLAG_ALTBUF )
250                                 Term->AltWritePos += Term->TextWidth;
251                         else
252                                 Term->WritePos += Term->TextWidth;
253                 }
254         }
255         
256         if( Term->Flags & VT_FLAG_ALTBUF )
257                 Term->AltWritePos = init_write_pos;
258         else
259                 Term->WritePos = init_write_pos;
260 }
261
262 /**
263  * \brief Clears a line in a virtual terminal
264  * \param Term  Terminal to modify
265  * \param Num   Line number to clear
266  */
267 void VT_int_ClearLine(tVTerm *Term, int Num)
268 {
269          int    i;
270         tVT_Char        *cell;
271         
272         if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) )        return ;
273         
274         cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
275         cell = &cell[ Num*Term->TextWidth ];
276         
277         for( i = Term->TextWidth; i--; )
278         {
279                 cell[ i ].Ch = 0;
280                 cell[ i ].Colour = Term->CurColour;
281         }
282 }
283
284 /**
285  * \brief Update the screen mode
286  * \param Term  Terminal to update
287  * \param NewMode       New mode to set
288  * \param NewWidth      New framebuffer width
289  * \param NewHeight     New framebuffer height
290  */
291 void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
292 {
293          int    oldW = Term->Width;
294          int    oldTW = Term->TextWidth;
295          int    oldH = Term->Height;
296          int    oldTH = Term->TextHeight;
297         tVT_Char        *oldTBuf = Term->Text;
298         Uint32  *oldFB = Term->Buffer;
299          int    w, h, i;
300         
301         // TODO: Increase RealWidth/RealHeight when this happens
302         if(NewWidth > giVT_RealWidth)   NewWidth = giVT_RealWidth;
303         if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
304         
305         Term->Mode = NewMode;
306
307         // Fast exit if no resolution change
308         if(NewWidth == Term->Width && NewHeight == Term->Height)
309                 return ;
310         
311         // Calculate new dimensions
312         Term->Width = NewWidth;
313         Term->Height = NewHeight;
314         Term->TextWidth = NewWidth / giVT_CharWidth;
315         Term->TextHeight = NewHeight / giVT_CharHeight;
316         Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
317         
318         // Allocate new buffers
319         // - Text
320         Term->Text = calloc(
321                 Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
322                 sizeof(tVT_Char)
323                 );
324         if(oldTBuf) {
325                 // Copy old buffer
326                 w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
327                 h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
328                 h *= giVT_Scrollback + 1;
329                 for( i = 0; i < h; i ++ )
330                 {
331                         memcpy(
332                                 &Term->Text[i*Term->TextWidth],
333                                 &oldTBuf[i*oldTW],
334                                 w*sizeof(tVT_Char)
335                                 );      
336                 }
337                 free(oldTBuf);
338         }
339         
340         // - Alternate Text
341         Term->AltBuf = realloc(
342                 Term->AltBuf,
343                 Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
344                 );
345         
346         // - Framebuffer
347         if(oldFB) {
348                 Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
349                 // Copy old buffer
350                 w = (oldW > Term->Width) ? Term->Width : oldW;
351                 h = (oldH > Term->Height) ? Term->Height : oldH;
352                 for( i = 0; i < h; i ++ )
353                 {
354                         memcpy(
355                                 &Term->Buffer[i*Term->Width],
356                                 &oldFB[i*oldW],
357                                 w*sizeof(Uint32)
358                                 );
359                 }
360                 free(oldFB);
361         }
362         
363         // Debug
364         #if 0
365         switch(NewMode)
366         {
367         case TERM_MODE_TEXT:
368                 Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
369                         Term, Term->TextWidth, Term->TextHeight);
370                 break;
371         case TERM_MODE_FB:
372                 Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
373                         Term, Term->Width, Term->Height);
374                 break;
375         //case TERM_MODE_2DACCEL:
376         //case TERM_MODE_3DACCEL:
377         //      return;
378         }
379         #endif
380 }
381
382
383 void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
384 {       
385         if(Enabled)
386                 Term->Flags |= VT_FLAG_ALTBUF;
387         else
388                 Term->Flags &= ~VT_FLAG_ALTBUF;
389         VT_int_UpdateScreen(Term, 1);
390 }
391

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