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)
21 for( i = 0; i < Count; i++ )
23 // Handle escape sequences
24 if( Buffer[i] == 0x1B && Count - i > 1 )
26 int ret = VT_int_ParseEscape(Term, (const char*)&Buffer[i+1], Count-(i+1));
34 // Fast check for non UTF-8
35 if( Buffer[i] < 128 ) // Plain ASCII
36 VT_int_PutChar(Term, Buffer[i]);
39 i += ReadUTF8(&Buffer[i], &val) - 1;
40 VT_int_PutChar(Term, val);
44 VT_int_UpdateScreen( Term, 0 );
48 * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
49 * \brief Write a single character to a VTerm
51 void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
57 if(Term->Flags & VT_FLAG_ALTBUF) {
58 buffer = Term->AltBuf;
59 write_pos = Term->AltWritePos;
63 write_pos = Term->WritePos;
68 case '\0': return; // Ignore NULL byte
70 VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
71 write_pos += Term->TextWidth;
73 write_pos -= write_pos % Term->TextWidth;
77 int line = write_pos / Term->TextWidth;
78 write_pos %= Term->TextWidth;
80 buffer[ write_pos ].Ch = '\0';
81 buffer[ write_pos ].Colour = Term->CurColour;
83 } while(write_pos & 7);
84 write_pos += line * Term->TextWidth;
88 // Backspace is invalid at Offset 0
89 if(write_pos == 0) break;
93 if(buffer[ write_pos ].Ch != '\0') {
94 buffer[ write_pos ].Ch = 0;
95 buffer[ write_pos ].Colour = Term->CurColour;
99 i = 7; // Limit it to 8
101 buffer[ write_pos ].Ch = 0;
102 buffer[ write_pos ].Colour = Term->CurColour;
104 } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
105 if(buffer[ write_pos ].Ch != '\0')
110 buffer[ write_pos ].Ch = Ch;
111 buffer[ write_pos ].Colour = Term->CurColour;
112 // Update the line before wrapping
113 if( (write_pos + 1) % Term->TextWidth == 0 )
114 VT_int_UpdateScreen( Term, 0 );
119 if(Term->Flags & VT_FLAG_ALTBUF)
121 Term->AltWritePos = write_pos;
123 if(Term->AltWritePos >= Term->TextWidth*Term->TextHeight)
125 Term->AltWritePos -= Term->TextWidth;
126 VT_int_ScrollText(Term, 1);
132 Term->WritePos = write_pos;
134 // - Check if we need to scroll the entire scrollback buffer
135 if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1))
139 // Update view position
140 base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
141 if(Term->ViewPos < base)
142 Term->ViewPos += Term->Width;
143 if(Term->ViewPos > base)
144 Term->ViewPos = base;
146 VT_int_ScrollText(Term, 1);
147 Term->WritePos -= Term->TextWidth;
149 // Ok, so we only need to scroll the screen
150 else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
152 VT_int_ScrollFramebuffer( Term, 1 );
154 Term->ViewPos += Term->TextWidth;
161 void VT_int_ScrollText(tVTerm *Term, int Count)
164 int height, init_write_pos;
166 int scroll_top, scroll_height;
168 // Get buffer pointer and attributes
169 if( Term->Flags & VT_FLAG_ALTBUF )
172 height = Term->TextHeight;
173 init_write_pos = Term->AltWritePos;
174 scroll_top = Term->ScrollTop;
175 scroll_height = Term->ScrollHeight;
180 height = Term->TextHeight*(giVT_Scrollback+1);
181 init_write_pos = Term->WritePos;
183 scroll_height = height;
186 // Scroll text upwards (more space at bottom)
192 if(Count > scroll_height) Count = scroll_height;
193 base = Term->TextWidth*(scroll_top + scroll_height - Count);
194 len = Term->TextWidth*(scroll_height - Count);
196 // Scroll terminal cache
198 &buf[Term->TextWidth*scroll_top],
199 &buf[Term->TextWidth*(scroll_top+Count)],
203 for( i = 0; i < Term->TextWidth*Count; i ++ )
205 buf[ base + i ].Ch = 0;
206 buf[ base + i ].Colour = Term->CurColour;
210 VT_int_ScrollFramebuffer( Term, Count );
211 if( Term->Flags & VT_FLAG_ALTBUF )
212 Term->AltWritePos = base;
214 Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
215 for( i = 0; i < Count; i ++ )
217 VT_int_UpdateScreen( Term, 0 );
218 if( Term->Flags & VT_FLAG_ALTBUF )
219 Term->AltWritePos += Term->TextWidth;
221 Term->WritePos += Term->TextWidth;
227 if(Count > scroll_height) Count = scroll_height;
229 len = Term->TextWidth*(scroll_height - Count);
231 // Scroll terminal cache
233 &buf[Term->TextWidth*(scroll_top+Count)],
234 &buf[Term->TextWidth*scroll_top],
237 // Clear preceding rows
238 for( i = 0; i < Term->TextWidth*Count; i ++ )
241 buf[ i ].Colour = Term->CurColour;
244 VT_int_ScrollFramebuffer( Term, -Count );
245 if( Term->Flags & VT_FLAG_ALTBUF )
246 Term->AltWritePos = Term->TextWidth*scroll_top;
248 Term->WritePos = Term->ViewPos;
249 for( i = 0; i < Count; i ++ )
251 VT_int_UpdateScreen( Term, 0 );
252 if( Term->Flags & VT_FLAG_ALTBUF )
253 Term->AltWritePos += Term->TextWidth;
255 Term->WritePos += Term->TextWidth;
259 if( Term->Flags & VT_FLAG_ALTBUF )
260 Term->AltWritePos = init_write_pos;
262 Term->WritePos = init_write_pos;
266 * \brief Clears a line in a virtual terminal
267 * \param Term Terminal to modify
268 * \param Num Line number to clear
270 void VT_int_ClearLine(tVTerm *Term, int Num)
275 if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) ) return ;
277 cell = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltBuf : Term->Text;
278 cell = &cell[ Num*Term->TextWidth ];
280 for( i = Term->TextWidth; i--; )
283 cell[ i ].Colour = Term->CurColour;
288 * \brief Update the screen mode
289 * \param Term Terminal to update
290 * \param NewMode New mode to set
291 * \param NewWidth New framebuffer width
292 * \param NewHeight New framebuffer height
294 void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
296 int oldW = Term->Width;
297 int oldTW = Term->TextWidth;
298 int oldH = Term->Height;
299 int oldTH = Term->TextHeight;
300 tVT_Char *oldTBuf = Term->Text;
301 Uint32 *oldFB = Term->Buffer;
304 // TODO: Increase RealWidth/RealHeight when this happens
305 if(NewWidth > giVT_RealWidth) NewWidth = giVT_RealWidth;
306 if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
308 Term->Mode = NewMode;
310 // Fast exit if no resolution change
311 if(NewWidth == Term->Width && NewHeight == Term->Height)
314 // Calculate new dimensions
315 Term->Width = NewWidth;
316 Term->Height = NewHeight;
317 Term->TextWidth = NewWidth / giVT_CharWidth;
318 Term->TextHeight = NewHeight / giVT_CharHeight;
319 Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
321 // Allocate new buffers
324 Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
329 w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
330 h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
331 h *= giVT_Scrollback + 1;
332 for( i = 0; i < h; i ++ )
335 &Term->Text[i*Term->TextWidth],
344 Term->AltBuf = realloc(
346 Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
351 Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
353 w = (oldW > Term->Width) ? Term->Width : oldW;
354 h = (oldH > Term->Height) ? Term->Height : oldH;
355 for( i = 0; i < h; i ++ )
358 &Term->Buffer[i*Term->Width],
371 Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
372 Term, Term->TextWidth, Term->TextHeight);
375 Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
376 Term, Term->Width, Term->Height);
378 //case TERM_MODE_2DACCEL:
379 //case TERM_MODE_3DACCEL:
386 void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
389 Term->Flags |= VT_FLAG_ALTBUF;
391 Term->Flags &= ~VT_FLAG_ALTBUF;
392 VT_int_UpdateScreen(Term, 1);