3 * - By John Hodge (thePowersGang)
6 * - Virtual Terminal - Terminal buffer manipulation
11 extern int Term_HandleVT100(tVTerm *Term, int Len, const char *Buf);
16 * \fn void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
17 * \brief Print a string to the Virtual Terminal
19 void VT_int_PutString(tVTerm *Term, const Uint8 *Buffer, Uint Count)
22 for( int ofs = 0; ofs < Count; )
24 int esc_len = Term_HandleVT100(Term, Count - ofs, (const void*)(Buffer + ofs));
27 //LOG("%i '%*C'", esc_len, esc_len, Buffer+ofs);
28 LOG("%i '%.*s'", esc_len, esc_len, Buffer+ofs);
29 VT_int_PutRawString(Term, Buffer + ofs, esc_len);
30 //Debug("Raw string '%.*s'", esc_len, Buffer+ofs);
33 //Debug("Escape code '%.*s'", esc_len, Buffer+ofs);
35 ASSERTCR(esc_len, >, 0, );
39 VT_int_UpdateScreen( Term, 1 );
42 void VT_int_PutRawString(tVTerm *Term, const Uint8 *String, size_t Bytes)
44 for( int i = 0; i < Bytes; ) {
46 i += ReadUTF8(String+i, &val);
47 VT_int_PutChar(Term, val);
52 * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
53 * \brief Write a single character to a VTerm
55 void VT_int_PutChar(tVTerm *Term, Uint32 Ch)
62 if(Term->Flags & VT_FLAG_ALTBUF) {
63 buffer = Term->AltBuf;
64 write_pos = Term->AltWritePos;
65 limit = Term->TextHeight * Term->TextWidth;
69 write_pos = Term->WritePos;
70 limit = Term->TextHeight*(giVT_Scrollback+1) * Term->TextWidth;
75 case '\0': return; // Ignore NULL byte
77 VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining
78 write_pos += Term->TextWidth;
80 write_pos -= write_pos % Term->TextWidth;
84 int line = write_pos / Term->TextWidth;
85 write_pos %= Term->TextWidth;
87 buffer[ write_pos ].Ch = '\0';
88 buffer[ write_pos ].Colour = Term->CurColour;
90 } while(write_pos & 7);
91 write_pos += line * Term->TextWidth;
95 // Backspace is invalid at Offset 0
96 if(write_pos == 0) break;
100 if(buffer[ write_pos ].Ch != '\0') {
101 buffer[ write_pos ].Ch = 0;
102 buffer[ write_pos ].Colour = Term->CurColour;
106 i = 7; // Limit it to 8
108 buffer[ write_pos ].Ch = 0;
109 buffer[ write_pos ].Colour = Term->CurColour;
111 } while(write_pos && i-- && buffer[ write_pos ].Ch == '\0');
112 if(buffer[ write_pos ].Ch != '\0')
117 ASSERTC(write_pos,<,limit);
118 buffer[ write_pos ].Ch = Ch;
119 buffer[ write_pos ].Colour = Term->CurColour;
120 // Update the line before wrapping
121 if( (write_pos + 1) % Term->TextWidth == 0 )
122 VT_int_UpdateScreen( Term, 0 );
127 if(Term->Flags & VT_FLAG_ALTBUF)
129 Term->AltWritePos = write_pos;
131 if(Term->AltWritePos >= limit)
133 Term->AltWritePos -= Term->TextWidth;
134 VT_int_ScrollText(Term, 1);
139 Term->WritePos = write_pos;
141 // - Check if we need to scroll the entire scrollback buffer
142 if(Term->WritePos >= limit)
146 // Update view position
147 base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback);
148 if(Term->ViewPos < base)
149 Term->ViewPos += Term->Width;
150 if(Term->ViewPos > base)
151 Term->ViewPos = base;
153 VT_int_ScrollText(Term, 1);
154 Term->WritePos -= Term->TextWidth;
156 // Ok, so we only need to scroll the screen
157 else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight)
159 VT_int_ScrollFramebuffer( Term, 1 );
161 Term->ViewPos += Term->TextWidth;
168 void VT_int_ScrollText(tVTerm *Term, int Count)
171 int height, init_write_pos;
173 int scroll_top, scroll_height;
175 // Get buffer pointer and attributes
176 if( Term->Flags & VT_FLAG_ALTBUF )
179 height = Term->TextHeight;
180 init_write_pos = Term->AltWritePos;
181 scroll_top = Term->ScrollTop;
182 scroll_height = Term->ScrollHeight;
187 height = Term->TextHeight*(giVT_Scrollback+1);
188 init_write_pos = Term->WritePos;
190 scroll_height = height;
193 // Scroll text upwards (more space at bottom)
199 if(Count > scroll_height) Count = scroll_height;
200 base = Term->TextWidth*(scroll_top + scroll_height - Count);
201 len = Term->TextWidth*(scroll_height - Count);
203 // Scroll terminal cache
205 &buf[Term->TextWidth*scroll_top],
206 &buf[Term->TextWidth*(scroll_top+Count)],
210 for( i = 0; i < Term->TextWidth*Count; i ++ )
212 buf[ base + i ].Ch = 0;
213 buf[ base + i ].Colour = Term->CurColour;
217 VT_int_ScrollFramebuffer( Term, Count );
218 if( Term->Flags & VT_FLAG_ALTBUF )
219 Term->AltWritePos = base;
221 Term->WritePos = Term->ViewPos + Term->TextWidth*(Term->TextHeight - Count);
222 for( i = 0; i < Count; i ++ )
224 VT_int_UpdateScreen( Term, 0 );
225 if( Term->Flags & VT_FLAG_ALTBUF )
226 Term->AltWritePos += Term->TextWidth;
228 Term->WritePos += Term->TextWidth;
234 if(Count > scroll_height) Count = scroll_height;
236 len = Term->TextWidth*(scroll_height - Count);
238 // Scroll terminal cache
240 &buf[Term->TextWidth*(scroll_top+Count)],
241 &buf[Term->TextWidth*scroll_top],
244 // Clear preceding rows
245 for( i = 0; i < Term->TextWidth*Count; i ++ )
248 buf[ i ].Colour = Term->CurColour;
251 VT_int_ScrollFramebuffer( Term, -Count );
252 if( Term->Flags & VT_FLAG_ALTBUF )
253 Term->AltWritePos = Term->TextWidth*scroll_top;
255 Term->WritePos = Term->ViewPos;
256 for( i = 0; i < Count; i ++ )
258 VT_int_UpdateScreen( Term, 0 );
259 if( Term->Flags & VT_FLAG_ALTBUF )
260 Term->AltWritePos += Term->TextWidth;
262 Term->WritePos += Term->TextWidth;
266 if( Term->Flags & VT_FLAG_ALTBUF )
267 Term->AltWritePos = init_write_pos;
269 Term->WritePos = init_write_pos;
273 * \brief Clears a line in a virtual terminal
274 * \param Term Terminal to modify
275 * \param Num Line number to clear
277 void VT_int_ClearLine(tVTerm *Term, int Num)
279 int limit = Term->TextHeight * (Term->Flags & VT_FLAG_ALTBUF ? 1 : giVT_Scrollback + 1);
280 tVT_Char *buffer = (Term->Flags & VT_FLAG_ALTBUF ? Term->AltBuf : Term->Text);
281 if( Num < 0 || Num >= limit ) return ;
283 tVT_Char *cell = &buffer[ Num*Term->TextWidth ];
285 for( int i = 0; i < Term->TextWidth; i ++ )
288 cell[ i ].Colour = Term->CurColour;
293 * \brief Update the screen mode
294 * \param Term Terminal to update
295 * \param NewMode New mode to set
296 * \param NewWidth New framebuffer width
297 * \param NewHeight New framebuffer height
299 void VT_int_Resize(tVTerm *Term, int NewWidth, int NewHeight)
301 int oldW = Term->Width;
302 int oldTW = Term->TextWidth;
303 int oldH = Term->Height;
304 int oldTH = Term->TextHeight;
305 tVT_Char *oldTBuf = Term->Text;
306 Uint32 *oldFB = Term->Buffer;
309 // TODO: Increase RealWidth/RealHeight when this happens
310 if(NewWidth > giVT_RealWidth) NewWidth = giVT_RealWidth;
311 if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight;
313 // Fast exit if no resolution change
314 if(NewWidth == Term->Width && NewHeight == Term->Height)
317 // Calculate new dimensions
318 Term->Width = NewWidth;
319 Term->Height = NewHeight;
320 Term->TextWidth = NewWidth / giVT_CharWidth;
321 Term->TextHeight = NewHeight / giVT_CharHeight;
322 Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop;
324 // Allocate new buffers
327 Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1),
332 w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW;
333 h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH;
334 h *= giVT_Scrollback + 1;
335 for( i = 0; i < h; i ++ )
338 &Term->Text[i*Term->TextWidth],
347 Term->AltBuf = realloc(
349 Term->TextWidth * Term->TextHeight * sizeof(tVT_Char)
354 Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) );
356 w = (oldW > Term->Width) ? Term->Width : oldW;
357 h = (oldH > Term->Height) ? Term->Height : oldH;
358 for( i = 0; i < h; i ++ )
361 &Term->Buffer[i*Term->Width],
374 Log_Log("VTerm", "Set VT %p to text mode (%ix%i)",
375 Term, Term->TextWidth, Term->TextHeight);
378 Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)",
379 Term, Term->Width, Term->Height);
381 //case TERM_MODE_2DACCEL:
382 //case TERM_MODE_3DACCEL:
389 void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled)
392 Term->Flags |= VT_FLAG_ALTBUF;
394 Term->Flags &= ~VT_FLAG_ALTBUF;
395 VT_int_UpdateScreen(Term, 1);