3 * - By John Hodge (thePowersGang)
6 * - Virtual Terminal - Terminal buffer manipulation
13 * \fn void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
14 * \brief Print a string to the Virtual Terminal
16 void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
22 for( i = 0; i < Count; i++ )
24 // Handle escape sequences
25 if( Buffer[i] == 0x1B )
28 i += VT_int_ParseEscape(Term, (const char*)&Buffer[i]) - 1;
32 // Fast check for non UTF-8
33 if( Buffer[i] < 128 ) // Plain ASCII
34 VT_int_PutChar(Term, Buffer[i]);
36 i += ReadUTF8(&Buffer[i], &val) - 1;
37 VT_int_PutChar(Term, val);
41 VT_int_UpdateScreen( Term, 0 );
45 * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
46 * \brief Write a single character to a VTerm
48 void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
54 if(Term->Flags & VT_FLAG_ALTBUF) {
55 buffer = Term->AltBuf;
56 write_pos = Term->AltWritePos;
60 write_pos = Term->WritePos;
65 case '\0': return; // Ignore NULL byte
67 VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
68 write_pos += Term->TextWidth;
70 write_pos -= write_pos % Term->TextWidth;
74 int line = write_pos / Term->TextWidth;
75 write_pos %= Term->TextWidth;
77 buffer[ write_pos ].Ch = '\0';
78 buffer[ write_pos ].Colour = Term->CurColour;
80 } while(write_pos & 7);
81 write_pos += line * Term->TextWidth;
85 // Backspace is invalid at Offset 0
86 if(write_pos == 0) break;
90 if(buffer[ write_pos ].Ch != '\0') {
91 buffer[ write_pos ].Ch = 0;
92 buffer[ write_pos ].Colour = Term->CurColour;
96 i = 7; // Limit it to 8
98 buffer[ write_pos ].Ch = 0;
99 buffer[ write_pos ].Colour = Term->CurColour;
101 } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
102 if(buffer[ write_pos ].Ch != '\0')
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 );
116 if(Term->Flags & VT_FLAG_ALTBUF)
118 Term->AltWritePos = write_pos;
120 if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
122 Term->AltWritePos -= Term->TextWidth;
123 VT_int_ScrollText(Term, 1);
129 Term->WritePos = write_pos;
131 // - Check if we need to scroll the entire scrollback buffer
132 if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
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;
143 VT_int_ScrollText(Term, 1);
144 Term->WritePos -= Term->TextWidth;
146 // Ok, so we only need to scroll the screen
147 else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
149 VT_int_ScrollFramebuffer( Term, 1 );
151 Term->ViewPos += Term->TextWidth;
158 void VT_int_ScrollText(tVTerm *Term, int Count)
161 int height, init_write_pos;
163 int scroll_top, scroll_height;
165 // Get buffer pointer and attributes
166 if( Term->Flags & VT_FLAG_ALTBUF )
169 height = Term->TextHeight;
170 init_write_pos = Term->AltWritePos;
171 scroll_top = Term->ScrollTop;
172 scroll_height = Term->ScrollHeight;
177 height = Term->TextHeight*(giVT_Scrollback+1);
178 init_write_pos = Term->WritePos;
180 scroll_height = height;
183 // Scroll text upwards (more space at bottom)
189 if(Count > scroll_height) Count = scroll_height;
190 base = Term->TextWidth*(scroll_top + scroll_height - Count);
191 len = Term->TextWidth*(scroll_height - Count);
193 // Scroll terminal cache
195 &buf[Term->TextWidth*scroll_top],
196 &buf[Term->TextWidth*(scroll_top+Count)],
200 for( i = 0; i < Term->TextWidth*Count; i ++ )
202 buf[ base + i ].Ch = 0;
203 buf[ base + i ].Colour = Term->CurColour;
207 VT_int_ScrollFramebuffer( Term, Count );
208 if( Term->Flags & VT_FLAG_ALTBUF )
209 Term->AltWritePos = base;
211 Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
212 for( i = 0; i < Count; i ++ )
214 VT_int_UpdateScreen( Term, 0 );
215 if( Term->Flags & VT_FLAG_ALTBUF )
216 Term->AltWritePos += Term->TextWidth;
218 Term->WritePos += Term->TextWidth;
224 if(Count > scroll_height) Count = scroll_height;
226 len = Term->TextWidth*(scroll_height - Count);
228 // Scroll terminal cache
230 &buf[Term->TextWidth*(scroll_top+Count)],
231 &buf[Term->TextWidth*scroll_top],
234 // Clear preceding rows
235 for( i = 0; i < Term->TextWidth*Count; i ++ )
238 buf[ i ].Colour = Term->CurColour;
241 VT_int_ScrollFramebuffer( Term, -Count );
242 if( Term->Flags & VT_FLAG_ALTBUF )
243 Term->AltWritePos = Term->TextWidth*scroll_top;
245 Term->WritePos = Term->ViewPos;
246 for( i = 0; i < Count; i ++ )
248 VT_int_UpdateScreen( Term, 0 );
249 if( Term->Flags & VT_FLAG_ALTBUF )
250 Term->AltWritePos += Term->TextWidth;
252 Term->WritePos += Term->TextWidth;
256 if( Term->Flags & VT_FLAG_ALTBUF )
257 Term->AltWritePos = init_write_pos;
259 Term->WritePos = init_write_pos;
263 * \brief Clears a line in a virtual terminal
264 * \param Term Terminal to modify
265 * \param Num Line number to clear
267 void VT_int_ClearLine(tVTerm *Term, int Num)
272 if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) ) return ;
274 cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
275 cell = &cell[ Num*Term->TextWidth ];
277 for( i = Term->TextWidth; i--; )
280 cell[ i ].Colour = Term->CurColour;
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
291 void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
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;
301 // TODO: Increase RealWidth/RealHeight when this happens
302 if(NewWidth > giVT_RealWidth) NewWidth = giVT_RealWidth;
303 if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
305 Term->Mode = NewMode;
307 // Fast exit if no resolution change
308 if(NewWidth == Term->Width && NewHeight == Term->Height)
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;
318 // Allocate new buffers
321 Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
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 ++ )
332 &Term->Text[i*Term->TextWidth],
341 Term->AltBuf = realloc(
343 Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
348 Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
350 w = (oldW > Term->Width) ? Term->Width : oldW;
351 h = (oldH > Term->Height) ? Term->Height : oldH;
352 for( i = 0; i < h; i ++ )
355 &Term->Buffer[i*Term->Width],
367 Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
368 Term, Term->TextWidth, Term->TextHeight);
371 Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
372 Term, Term->Width, Term->Height);
374 //case TERM_MODE_2DACCEL:
375 //case TERM_MODE_3DACCEL:
381 void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
384 Term->Flags |= VT_FLAG_ALTBUF;
386 Term->Flags &= ~VT_FLAG_ALTBUF;
387 VT_int_UpdateScreen(Term, 1);