X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fdrv%2Fvterm.c;h=57ce0828e8a2e492b05565c939a2a71a3605356e;hb=784b6fc9ee5221ed58ed7a118c0c856d483a2ea7;hp=1be52ac119905dfd068f17813cd3c9d1f2e197a5;hpb=6017fe6e4bbe7852451ce2e717ff4c665a270f44;p=tpg%2Facess2.git diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c index 1be52ac1..57ce0828 100644 --- a/Kernel/drv/vterm.c +++ b/Kernel/drv/vterm.c @@ -31,6 +31,7 @@ #define VT_FLAG_ALTBUF 0x02 //!< Alternate screen buffer #define VT_FLAG_RAWIN 0x04 //!< Don't handle ^Z/^C/^V #define VT_FLAG_HASFB 0x10 //!< Set if the VTerm has requested the Framebuffer +#define VT_FLAG_SHOWCSR 0x20 //!< Always show the text cursor enum eVT_InModes { VT_INMODE_TEXT8, // UTF-8 Text Mode (VT100/xterm Emulation) @@ -60,6 +61,9 @@ typedef struct { int AltWritePos; //!< Alternate write position short ScrollTop; //!< Top of scrolling region (smallest) short ScrollHeight; //!< Length of scrolling region + + int VideoCursorX; + int VideoCursorY; tMutex ReadingLock; //!< Lock the VTerm when a process is reading from it tTID ReadingThread; //!< Owner of the lock @@ -69,6 +73,11 @@ typedef struct { // tSemaphore InputSemaphore; Uint32 *Buffer; + + // TODO: Do I need to keep this about? + // When should it be deallocated? on move to text mode, or some other time + // Call set again, it's freed, and if NULL it doesn't get reallocated. + tVideo_IOCtl_Bitmap *VideoCursor; char Name[2]; //!< Name of the terminal tVFS_Node Node; @@ -93,10 +102,12 @@ void VT_SetTerminal(int ID); void VT_KBCallBack(Uint32 Codepoint); void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count); void VT_int_ClearLine(tVTerm *Term, int Num); +void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args); int VT_int_ParseEscape(tVTerm *Term, char *Buffer); void VT_int_PutChar(tVTerm *Term, Uint32 Ch); void VT_int_ScrollText(tVTerm *Term, int Count); void VT_int_ScrollFramebuffer( tVTerm *Term, int Count ); +void VT_int_UpdateCursor( tVTerm *Term, int bShow ); void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ); void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight); void VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled); @@ -226,6 +237,7 @@ int VT_Install(char **Arguments) { gVT_Terminals[i].Mode = TERM_MODE_TEXT; gVT_Terminals[i].Flags = 0; +// gVT_Terminals[i].Flags = VT_FLAG_HIDECSR; //HACK - Stop all those memcpy calls gVT_Terminals[i].CurColour = DEFAULT_COLOUR; gVT_Terminals[i].WritePos = 0; gVT_Terminals[i].AltWritePos = 0; @@ -315,6 +327,8 @@ void VT_SetResolution(int Width, int Height) giVT_RealWidth, giVT_RealHeight, mode.width, mode.height ); + giVT_RealWidth = mode.width; + giVT_RealHeight = mode.height; } VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp ); @@ -326,8 +340,6 @@ void VT_SetResolution(int Width, int Height) *(giVT_Scrollback+1); //tVT_Char *tmp; // Resize the text terminals - giVT_RealWidth = mode.width; - giVT_RealHeight = mode.height; Log_Debug("VTerm", "Resizing terminals to %ix%i", giVT_RealWidth/giVT_CharWidth, giVT_RealHeight/giVT_CharHeight); for( i = 0; i < NUM_VTS; i ++ ) @@ -455,6 +467,8 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) { // Text Mode (UTF-8) case TERM_MODE_TEXT: + VT_int_UpdateCursor(term, 1); + VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UTF-8)"); avail = term->InputWrite - term->InputRead; @@ -468,7 +482,7 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead]; pos ++; term->InputRead ++; - while(term->InputRead > MAX_INPUT_CHARS8) + while(term->InputRead >= MAX_INPUT_CHARS8) term->InputRead -= MAX_INPUT_CHARS8; } break; @@ -481,8 +495,9 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) avail = term->InputWrite - term->InputRead; if(avail < 0) avail += MAX_INPUT_CHARS32; + Length /= 4; if(avail > Length - pos) - avail = Length/4 - pos; + avail = Length - pos; codepoint_in = (void*)term->InputBuffer; codepoint_buf = Buffer; @@ -492,7 +507,7 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) codepoint_buf[pos] = codepoint_in[term->InputRead]; pos ++; term->InputRead ++; - while(term->InputRead > MAX_INPUT_CHARS32) + while(term->InputRead >= MAX_INPUT_CHARS32) term->InputRead -= MAX_INPUT_CHARS32; } pos *= 4; @@ -504,7 +519,9 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) VFS_MarkAvaliable(&term->Node, 0); term->ReadingThread = -1; - + +// VT_int_UpdateCursor(term, term->Mode == TERM_MODE_TEXT); + Mutex_Release( &term->ReadingLock ); return pos; @@ -526,9 +543,9 @@ Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) case TERM_MODE_TEXT: VT_int_PutString(term, Buffer, Length); break; + // Framebuffer :) case TERM_MODE_FB: - // - Sanity Checking size = term->Width*term->Height*4; if( Offset > size ) { @@ -542,38 +559,49 @@ Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) Length = size - Offset; } - // Copy to the local cache - memcpy( (void*)((Uint)term->Buffer + (Uint)Offset), Buffer, Length ); - // Update screen if needed if( Node->Inode == giVT_CurrentTerminal ) { - // Fill entire screen? - if( giVT_RealWidth > term->Width || giVT_RealHeight > term->Height ) + if( giVT_RealHeight > term->Height ) + Offset += (giVT_RealHeight - term->Height) / 2 * term->Width * 4; + // Handle undersized virtual terminals + if( giVT_RealWidth > term->Width ) { // No? :( Well, just center it int x, y, w, h; + Uint dst_ofs; + // TODO: Fix to handle the final line correctly? x = Offset/4; y = x / term->Width; x %= term->Width; w = Length/4+x; h = w / term->Width; w %= term->Width; + // Center x += (giVT_RealWidth - term->Width) / 2; - y += (giVT_RealHeight - term->Height) / 2; + dst_ofs = (x + y * giVT_RealWidth) * 4; while(h--) { VFS_WriteAt( giVT_OutputDevHandle, - (x + y * giVT_RealWidth)*4, + dst_ofs, term->Width * 4, Buffer ); Buffer = (void*)( (Uint)Buffer + term->Width*4 ); - y ++; + dst_ofs += giVT_RealWidth * 4; } return 0; } - else { + else + { return VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer ); } } + else + { + if( !term->Buffer ) + term->Buffer = malloc( term->Width * term->Height * 4 ); + // Copy to the local cache + memcpy( (char*)term->Buffer + (Uint)Offset, Buffer, Length ); + } + break; // Just pass on (for now) // TODO: Handle locally too to ensure no information is lost on // VT Switch (and to isolate terminals from each other) @@ -634,9 +662,7 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) Log_Log("VTerm", "VTerm %i mode set to %i", (int)Node->Inode, *iData); // Update mode if needed - if( term->Mode != *iData - || term->NewWidth - || term->NewHeight) + if( term->Mode != *iData || term->NewWidth || term->NewHeight) { // Adjust for text mode if( *iData == TERM_MODE_TEXT ) { @@ -703,10 +729,84 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) LEAVE('i', 1); return 1; - case TERM_IOCTL_GETCURSOR: + case TERM_IOCTL_GETSETCURSOR: + if(Data != NULL) + { + tVideo_IOCtl_Pos *pos = Data; + if( !CheckMem(Data, sizeof(*pos)) ) { + errno = -EINVAL; + LEAVE('i', -1); + return -1; + } + + if( term->Mode == TERM_MODE_TEXT ) + { + if(term->Flags & VT_FLAG_ALTBUF) + term->AltWritePos = pos->x + pos->y * term->TextWidth; + else + term->WritePos = pos->x + pos->y * term->TextWidth + term->ViewPos; + VT_int_UpdateCursor(term, 0); + } + else + { + term->VideoCursorX = pos->x; + term->VideoCursorY = pos->y; + VT_int_UpdateCursor(term, 1); + } + } ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos; LEAVE('i', ret); return ret; + + case TERM_IOCTL_SETCURSORBITMAP: { + tVideo_IOCtl_Bitmap *bmp = Data; + if( Data == NULL ) + { + free( term->VideoCursor ); + term->VideoCursor = NULL; + LEAVE('i', 0); + return 0; + } + + // Sanity check bitmap + if( !CheckMem(bmp, sizeof(tVideo_IOCtl_Bitmap)) ) { + Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp); + errno = -EINVAL; + LEAVE_RET('i', -1); + } + if( !CheckMem(bmp->Data, bmp->W*bmp->H*sizeof(Uint32)) ) { + Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp); + errno = -EINVAL; + LEAVE_RET('i', -1); + } + + // Reallocate if needed + if(term->VideoCursor) + { + if(bmp->W * bmp->H != term->VideoCursor->W * term->VideoCursor->H) { + free(term->VideoCursor); + term->VideoCursor = NULL; + } + } + if(!term->VideoCursor) { + term->VideoCursor = malloc(sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32)); + if(!term->VideoCursor) { + Log_Error("VTerm", "Unable to allocate memory for cursor"); + errno = -ENOMEM; + LEAVE_RET('i', -1); + } + } + + memcpy(term->VideoCursor, bmp, sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32)); + + Log_Debug("VTerm", "Set VT%i's cursor to %p %ix%i", + (int)term->Node.Inode, bmp, bmp->W, bmp->H); + + if(gpVT_CurTerm == term) + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, term->VideoCursor); + + LEAVE('i', 0); + return 0; } } LEAVE('i', -1); return -1; @@ -717,30 +817,65 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) * \brief Set the current terminal */ void VT_SetTerminal(int ID) -{ +{ + // Copy the screen state + if( ID != giVT_CurrentTerminal && gpVT_CurTerm->Mode != TERM_MODE_TEXT ) + { + if( !gpVT_CurTerm->Buffer ) + gpVT_CurTerm->Buffer = malloc( gpVT_CurTerm->Width*gpVT_CurTerm->Height*4 ); + if( gpVT_CurTerm->Width < giVT_RealWidth ) + { + int line; + Uint ofs = 0; + Uint32 *dest = gpVT_CurTerm->Buffer; + // Slower scanline copy + for( line = 0; line < gpVT_CurTerm->Height; line ++ ) + { + VFS_ReadAt(giVT_OutputDevHandle, ofs, gpVT_CurTerm->Width*4, dest); + ofs += giVT_RealWidth * 4; + dest += gpVT_CurTerm->Width; + } + } + else + { + VFS_ReadAt(giVT_OutputDevHandle, + 0, gpVT_CurTerm->Height*giVT_RealWidth*4, + gpVT_CurTerm->Buffer + ); + } + } + // Update current terminal ID Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID); giVT_CurrentTerminal = ID; gpVT_CurTerm = &gVT_Terminals[ID]; - // Update cursor - if( gpVT_CurTerm->Text && gpVT_CurTerm->Mode == TERM_MODE_TEXT && !(gpVT_CurTerm->Flags & VT_FLAG_HIDECSR) ) - { - tVideo_IOCtl_Pos pos; - int offset = (gpVT_CurTerm->Flags & VT_FLAG_ALTBUF) ? gpVT_CurTerm->AltWritePos : gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos; - pos.x = offset % gpVT_CurTerm->TextWidth; - pos.y = offset / gpVT_CurTerm->TextWidth; - if( 0 <= pos.y && pos.y < gpVT_CurTerm->TextHeight ) - VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); - } - if( gpVT_CurTerm->Mode == TERM_MODE_TEXT ) + { VT_SetMode( VIDEO_BUFFMT_TEXT ); + } else + { + // Update the cursor image + if(gpVT_CurTerm->VideoCursor) + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, gpVT_CurTerm->VideoCursor); VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER ); + } + + if(gpVT_CurTerm->Buffer) + { + // TODO: Handle non equal sized + VFS_WriteAt( + giVT_OutputDevHandle, + 0, + gpVT_CurTerm->Width*gpVT_CurTerm->Height*sizeof(Uint32), + gpVT_CurTerm->Buffer + ); + } + VT_int_UpdateCursor(gpVT_CurTerm, 1); // Update the screen - VT_int_UpdateScreen( &gVT_Terminals[ ID ], 1 ); +// VT_int_UpdateScreen(gpVT_CurTerm, 1); } /** @@ -755,35 +890,32 @@ void VT_SetTerminal(int ID) void VT_KBCallBack(Uint32 Codepoint) { tVTerm *term = gpVT_CurTerm; - - // How the hell did we get a codepoint of zero? - if(Codepoint == 0) return; - - // Key Up - if( Codepoint & 0x80000000 ) + + // Catch VT binds + switch( Codepoint & KEY_ACTION_MASK ) { - Codepoint &= 0x7FFFFFFF; - switch(Codepoint) + case KEY_ACTION_RELEASE: + switch(Codepoint & KEY_CODEPOINT_MASK) { case KEY_LALT: gbVT_AltDown &= ~1; break; case KEY_RALT: gbVT_AltDown &= ~2; break; case KEY_LCTRL: gbVT_CtrlDown &= ~1; break; case KEY_RCTRL: gbVT_CtrlDown &= ~2; break; } - return; - } - - switch(Codepoint) - { - case KEY_LALT: gbVT_AltDown |= 1; break; - case KEY_RALT: gbVT_AltDown |= 2; break; - case KEY_LCTRL: gbVT_CtrlDown |= 1; break; - case KEY_RCTRL: gbVT_CtrlDown |= 2; break; + break; - default: + case KEY_ACTION_PRESS: + switch(Codepoint & KEY_CODEPOINT_MASK) + { + case KEY_LALT: gbVT_AltDown |= 1; break; + case KEY_RALT: gbVT_AltDown |= 2; break; + case KEY_LCTRL: gbVT_CtrlDown |= 1; break; + case KEY_RCTRL: gbVT_CtrlDown |= 2; break; + } + if(!gbVT_AltDown || !gbVT_CtrlDown) break; - switch(Codepoint) + switch(Codepoint & KEY_CODEPOINT_MASK) { case KEY_F1: VT_SetTerminal(0); return; case KEY_F2: VT_SetTerminal(1); return; @@ -797,24 +929,33 @@ void VT_KBCallBack(Uint32 Codepoint) case KEY_F10: VT_SetTerminal(9); return; case KEY_F11: VT_SetTerminal(10); return; case KEY_F12: VT_SetTerminal(11); return; + } + + // Scrolling is only valid in text mode + if(gpVT_CurTerm->Mode != TERM_MODE_TEXT) + break; + + switch(Codepoint & KEY_CODEPOINT_MASK) + { // Scrolling case KEY_PGUP: if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF ) return ; - if( gpVT_CurTerm->ViewPos > gpVT_CurTerm->Width ) - gpVT_CurTerm->ViewPos -= gpVT_CurTerm->Width; - else - gpVT_CurTerm->ViewPos = 0; + gpVT_CurTerm->ViewPos = MAX( + 0, + gpVT_CurTerm->ViewPos - gpVT_CurTerm->Width + ); return; case KEY_PGDOWN: if( gpVT_CurTerm->Flags & VT_FLAG_ALTBUF ) return ; - if( gpVT_CurTerm->ViewPos < gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback) ) - gpVT_CurTerm->ViewPos += gpVT_CurTerm->Width; - else - gpVT_CurTerm->ViewPos = gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback); + gpVT_CurTerm->ViewPos = MIN( + gpVT_CurTerm->ViewPos + gpVT_CurTerm->Width, + gpVT_CurTerm->Width * gpVT_CurTerm->Height*giVT_Scrollback + ); return; } + break; } // Encode key @@ -822,37 +963,49 @@ void VT_KBCallBack(Uint32 Codepoint) { Uint8 buf[6] = {0}; int len = 0; - + + // Ignore anything that isn't a press or refire + if( (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_PRESS + && (Codepoint & KEY_ACTION_MASK) != KEY_ACTION_REFIRE + ) + { + return ; + } + + Codepoint &= KEY_CODEPOINT_MASK; + // Ignore Modifer Keys if(Codepoint > KEY_MODIFIERS) return; // Get UTF-8/ANSI Encoding switch(Codepoint) { + // 0: No translation, don't send to user + case 0: break; case KEY_LEFT: - buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D'; + buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D'; len = 3; break; case KEY_RIGHT: - buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C'; + buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C'; len = 3; break; case KEY_UP: - buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A'; + buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A'; len = 3; break; case KEY_DOWN: - buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B'; + buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'B'; len = 3; break; case KEY_PGUP: - //buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; // Some overline also - //len = 4; // Commented out until I'm sure - len = 0; + buf[0] = '\x1B'; buf[1] = '['; buf[2] = '5'; buf[3] = '~'; + len = 4; break; case KEY_PGDOWN: - len = 0; + buf[0] = '\x1B'; buf[1] = '['; buf[2] = '6'; buf[3] = '~'; + len = 4; break; // Attempt to encode in UTF-8 @@ -899,23 +1052,37 @@ void VT_KBCallBack(Uint32 Codepoint) } else { - // Encode the raw UTF-32 Key + // Encode the raw key event Uint32 *raw_in = (void*)term->InputBuffer; + + #if 0 + // Drop new keys + if( term->InputWrite == term->InputRead ) + return ; + #endif + raw_in[ term->InputWrite ] = Codepoint; term->InputWrite ++; - term->InputWrite %= MAX_INPUT_CHARS32; + if(term->InputWrite >= MAX_INPUT_CHARS32) + term->InputWrite -= MAX_INPUT_CHARS32; + + #if 1 + // TODO: Should old or new be dropped? if(term->InputRead == term->InputWrite) { term->InputRead ++; - term->InputRead %= MAX_INPUT_CHARS32; + if( term->InputRead >= MAX_INPUT_CHARS32 ) + term->InputRead -= MAX_INPUT_CHARS32; } + #endif } VFS_MarkAvaliable(&term->Node, 1); } /** - * \fn void VT_int_ClearLine(tVTerm *Term, int Num) * \brief Clears a line in a virtual terminal + * \param Term Terminal to modify + * \param Num Line number to clear */ void VT_int_ClearLine(tVTerm *Term, int Num) { @@ -934,6 +1101,197 @@ void VT_int_ClearLine(tVTerm *Term, int Num) } } +/** + * \brief Handle a standard large escape code + * + * Handles any escape code of the form \x1B[n,...A where n is an integer + * and A is any letter. + */ +void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args) +{ + int tmp = 1; + switch(CmdChar) + { + // Left + case 'D': + tmp = -1; + // Right + case 'C': + if(argc == 1) tmp *= args[0]; + if( Term->Flags & VT_FLAG_ALTBUF ) + { + if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) { + Term->AltWritePos -= Term->AltWritePos % Term->TextWidth; + Term->AltWritePos += Term->TextWidth - 1; + } + else + Term->AltWritePos += tmp; + } + else + { + if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) { + Term->WritePos -= Term->WritePos % Term->TextWidth; + Term->WritePos += Term->TextWidth - 1; + } + else + Term->WritePos += tmp; + } + break; + + // Erase + case 'J': + switch(args[0]) + { + case 0: // Erase below + break; + case 1: // Erase above + break; + case 2: // Erase all + if( Term->Flags & VT_FLAG_ALTBUF ) + { + int i = Term->TextHeight; + while( i-- ) VT_int_ClearLine(Term, i); + Term->AltWritePos = 0; + VT_int_UpdateScreen(Term, 1); + } + else + { + int i = Term->TextHeight * (giVT_Scrollback + 1); + while( i-- ) VT_int_ClearLine(Term, i); + Term->WritePos = 0; + Term->ViewPos = 0; + VT_int_UpdateScreen(Term, 1); + } + break; + } + break; + + // Erase in line + case 'K': + switch(args[0]) + { + case 0: // Erase to right + if( Term->Flags & VT_FLAG_ALTBUF ) + { + int i, max; + max = Term->Width - Term->AltWritePos % Term->Width; + for( i = 0; i < max; i ++ ) + Term->AltBuf[Term->AltWritePos+i].Ch = 0; + } + else + { + int i, max; + max = Term->Width - Term->WritePos % Term->Width; + for( i = 0; i < max; i ++ ) + Term->Text[Term->WritePos+i].Ch = 0; + } + VT_int_UpdateScreen(Term, 0); + break; + case 1: // Erase to left + if( Term->Flags & VT_FLAG_ALTBUF ) + { + int i = Term->AltWritePos % Term->Width; + while( i -- ) + Term->AltBuf[Term->AltWritePos++].Ch = 0; + } + else + { + int i = Term->WritePos % Term->Width; + while( i -- ) + Term->Text[Term->WritePos++].Ch = 0; + } + VT_int_UpdateScreen(Term, 0); + break; + case 2: // Erase all + if( Term->Flags & VT_FLAG_ALTBUF ) + { + VT_int_ClearLine(Term, Term->AltWritePos / Term->Width); + } + else + { + VT_int_ClearLine(Term, Term->WritePos / Term->Width); + } + VT_int_UpdateScreen(Term, 0); + break; + } + break; + + // Set cursor position + case 'H': + if( Term->Flags & VT_FLAG_ALTBUF ) + Term->AltWritePos = args[0] + args[1]*Term->TextWidth; + else + Term->WritePos = args[0] + args[1]*Term->TextWidth; + //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]); + break; + + // Scroll up `n` lines + case 'S': + tmp = -1; + // Scroll down `n` lines + case 'T': + if(argc == 1) tmp *= args[0]; + if( Term->Flags & VT_FLAG_ALTBUF ) + VT_int_ScrollText(Term, tmp); + else + { + if(Term->ViewPos/Term->TextWidth + tmp < 0) + break; + if(Term->ViewPos/Term->TextWidth + tmp > Term->TextHeight * (giVT_Scrollback + 1)) + break; + + Term->ViewPos += Term->TextWidth*tmp; + } + break; + + // Set Font flags + case 'm': + for( ; argc--; ) + { + int colour_idx; + // Flags + if( 0 <= args[argc] && args[argc] <= 8) + { + switch(args[argc]) + { + case 0: Term->CurColour = DEFAULT_COLOUR; break; // Reset + case 1: Term->CurColour |= 0x80000000; break; // Bright + case 2: Term->CurColour &= ~0x80000000; break; // Dim + } + } + // Foreground Colour + else if(30 <= args[argc] && args[argc] <= 37) { + // Get colour index, accounting for bright bit + colour_idx = args[argc]-30 + ((Term->CurColour>>28) & 8); + Term->CurColour &= 0x8000FFFF; + Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16; + } + // Background Colour + else if(40 <= args[argc] && args[argc] <= 47) { + // Get colour index, accounting for bright bit + colour_idx = args[argc]-40 + ((Term->CurColour>>12) & 8); + Term->CurColour &= 0xFFFF8000; + Term->CurColour |= caVT100Colours[ colour_idx ]; + } + else { + Log_Warning("VTerm", "Unknown font flag %i", args[argc]); + } + } + break; + + // Set scrolling region + case 'r': + if( argc != 2 ) break; + Term->ScrollTop = args[0]; + Term->ScrollHeight = args[1] - args[0]; + break; + + default: + Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", CmdChar); + break; + } +} + /** * \fn int VT_int_ParseEscape(tVTerm *Term, char *Buffer) * \brief Parses a VT100 Escape code @@ -942,7 +1300,6 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) { char c; int argc = 0, j = 1; - int tmp; int args[6] = {0,0,0,0}; int bQuestionMark = 0; @@ -981,6 +1338,9 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) if(argc != 1) break; switch(args[0]) { + case 25: + Term->Flags &= ~VT_FLAG_HIDECSR; + break; case 1047: VT_int_ToggleAltBuffer(Term, 1); break; @@ -990,6 +1350,9 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) if(argc != 1) break; switch(args[0]) { + case 25: + Term->Flags |= VT_FLAG_HIDECSR; + break; case 1047: VT_int_ToggleAltBuffer(Term, 0); break; @@ -1002,184 +1365,14 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) } else { - tmp = 1; - switch(c) - { - // Left - case 'D': - tmp = -1; - // Right - case 'C': - if(argc == 1) tmp *= args[0]; - if( Term->Flags & VT_FLAG_ALTBUF ) - { - if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) { - Term->AltWritePos -= Term->AltWritePos % Term->TextWidth; - Term->AltWritePos += Term->TextWidth - 1; - } - else - Term->AltWritePos += tmp; - } - else - { - if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) { - Term->WritePos -= Term->WritePos % Term->TextWidth; - Term->WritePos += Term->TextWidth - 1; - } - else - Term->WritePos += tmp; - } - break; - - // Erase - case 'J': - switch(args[0]) - { - case 0: // Erase below - break; - case 1: // Erase above - break; - case 2: // Erase all - if( Term->Flags & VT_FLAG_ALTBUF ) - { - int i = Term->TextHeight; - while( i-- ) VT_int_ClearLine(Term, i); - Term->AltWritePos = 0; - VT_int_UpdateScreen(Term, 1); - } - else - { - int i = Term->TextHeight * (giVT_Scrollback + 1); - while( i-- ) VT_int_ClearLine(Term, i); - Term->WritePos = 0; - Term->ViewPos = 0; - VT_int_UpdateScreen(Term, 1); - } - break; - } - break; - - // Erase in line - case 'K': - switch(args[0]) - { - case 0: // Erase to right - if( Term->Flags & VT_FLAG_ALTBUF ) - { - int i, max; - max = Term->Width - Term->AltWritePos % Term->Width; - for( i = 0; i < max; i ++ ) - Term->AltBuf[Term->AltWritePos+i].Ch = 0; - } - else - { - int i, max; - max = Term->Width - Term->WritePos % Term->Width; - for( i = 0; i < max; i ++ ) - Term->Text[Term->WritePos+i].Ch = 0; - } - VT_int_UpdateScreen(Term, 0); - break; - case 1: // Erase to left - if( Term->Flags & VT_FLAG_ALTBUF ) - { - int i = Term->AltWritePos % Term->Width; - while( i -- ) - Term->AltBuf[Term->AltWritePos++].Ch = 0; - } - else - { - int i = Term->WritePos % Term->Width; - while( i -- ) - Term->Text[Term->WritePos++].Ch = 0; - } - VT_int_UpdateScreen(Term, 0); - break; - case 2: // Erase all - if( Term->Flags & VT_FLAG_ALTBUF ) - { - VT_int_ClearLine(Term, Term->AltWritePos / Term->Width); - } - else - { - VT_int_ClearLine(Term, Term->WritePos / Term->Width); - } - VT_int_UpdateScreen(Term, 0); - break; - } - break; - - // Set cursor position - case 'H': - if( Term->Flags & VT_FLAG_ALTBUF ) - Term->AltWritePos = args[0] + args[1]*Term->TextWidth; - else - Term->WritePos = args[0] + args[1]*Term->TextWidth; - //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]); - break; - - // Scroll up `n` lines - case 'S': - tmp = -1; - // Scroll down `n` lines - case 'T': - if(argc == 1) tmp *= args[0]; - if( Term->Flags & VT_FLAG_ALTBUF ) - VT_int_ScrollText(Term, tmp); - else - { - if(Term->ViewPos/Term->TextWidth + tmp < 0) - break; - if(Term->ViewPos/Term->TextWidth + tmp > Term->TextHeight * (giVT_Scrollback + 1)) - break; - - Term->ViewPos += Term->TextWidth*tmp; - } - break; - - // Set Font flags - case 'm': - for( ; argc--; ) - { - // Flags - if( 0 <= args[argc] && args[argc] <= 8) - { - switch(args[argc]) - { - case 0: Term->CurColour = DEFAULT_COLOUR; break; // Reset - case 1: Term->CurColour |= 0x80000000; break; // Bright - case 2: Term->CurColour &= ~0x80000000; break; // Dim - } - } - // Foreground Colour - else if(30 <= args[argc] && args[argc] <= 37) { - Term->CurColour &= 0xF000FFFF; - Term->CurColour |= (Uint32)caVT100Colours[ args[argc]-30+(Term->CurColour>>28) ] << 16; - } - // Background Colour - else if(40 <= args[argc] && args[argc] <= 47) { - Term->CurColour &= 0xFFFF8000; - Term->CurColour |= caVT100Colours[ args[argc]-40+((Term->CurColour>>12)&15) ]; - } - } - break; - - // Set scrolling region - case 'r': - if( argc != 2 ) break; - Term->ScrollTop = args[0]; - Term->ScrollHeight = args[1] - args[0]; - break; - - default: - Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", c); - break; - } + VT_int_ParseEscape_StandardLarge(Term, c, argc, args); } } break; - default: break; + default: + Log_Notice("VTerm", "TODO: Handle short escape codes"); + break; } //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer); @@ -1216,17 +1409,6 @@ void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) } // Update Screen VT_int_UpdateScreen( Term, 0 ); - - // Update cursor - if( Term == gpVT_CurTerm && !(Term->Flags & VT_FLAG_HIDECSR) ) - { - tVideo_IOCtl_Pos pos; - int offset = (gpVT_CurTerm->Flags & VT_FLAG_ALTBUF) ? gpVT_CurTerm->AltWritePos : gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos; - pos.x = offset % gpVT_CurTerm->TextWidth; - pos.y = offset / gpVT_CurTerm->TextWidth; - if( 0 <= pos.y && pos.y < gpVT_CurTerm->TextHeight ) - VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); - } } /** @@ -1504,6 +1686,50 @@ void VT_int_ScrollFramebuffer( tVTerm *Term, int Count ) VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp); } +void VT_int_UpdateCursor( tVTerm *Term, int bShow ) +{ + tVideo_IOCtl_Pos csr_pos; + + if( Term != gpVT_CurTerm ) return ; + + if( !bShow ) + { + csr_pos.x = -1; + csr_pos.y = -1; + } + else if( Term->Mode == TERM_MODE_TEXT ) + { + int offset; + +// if( !(Term->Flags & VT_FLAG_SHOWCSR) +// && ( (Term->Flags & VT_FLAG_HIDECSR) || !Term->Node.ReadThreads) +// ) + if( !Term->Text || Term->Flags & VT_FLAG_HIDECSR ) + { + csr_pos.x = -1; + csr_pos.y = -1; + } + else + { + if(Term->Flags & VT_FLAG_ALTBUF) + offset = Term->AltWritePos; + else + offset = Term->WritePos - Term->ViewPos; + + csr_pos.x = offset % Term->TextWidth; + csr_pos.y = offset / Term->TextWidth; + if( 0 > csr_pos.y || csr_pos.y >= Term->TextHeight ) + csr_pos.y = -1, csr_pos.x = -1; + } + } + else + { + csr_pos.x = Term->VideoCursorX; + csr_pos.y = Term->VideoCursorY; + } + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &csr_pos); +} + /** * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) * \brief Updates the video framebuffer @@ -1542,14 +1768,10 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) } break; case TERM_MODE_FB: - VFS_WriteAt( - giVT_OutputDevHandle, - 0, - Term->Width*Term->Height*sizeof(Uint32), - Term->Buffer - ); break; } + + VT_int_UpdateCursor(Term, 1); } /** @@ -1561,90 +1783,91 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) */ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) { + int oldW = Term->Width; + int oldTW = Term->TextWidth; + int oldH = Term->Height; + int oldTH = Term->TextHeight; + tVT_Char *oldTBuf = Term->Text; + Uint32 *oldFB = Term->Buffer; + int w, h, i; + // TODO: Increase RealWidth/RealHeight when this happens if(NewWidth > giVT_RealWidth) NewWidth = giVT_RealWidth; if(NewHeight > giVT_RealHeight) NewHeight = giVT_RealHeight; Term->Mode = NewMode; - if(NewWidth != Term->Width || NewHeight != Term->Height) - { - int oldW = Term->Width; - int oldTW = Term->TextWidth; - int oldH = Term->Height; - int oldTH = Term->TextHeight; - tVT_Char *oldTBuf = Term->Text; - Uint32 *oldFB = Term->Buffer; - int w, h, i; - // Calculate new dimensions - Term->Width = NewWidth; - Term->Height = NewHeight; - Term->TextWidth = NewWidth / giVT_CharWidth; - Term->TextHeight = NewHeight / giVT_CharHeight; - Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop; - - // Allocate new buffers - // - Text - Term->Text = calloc( - Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1), - sizeof(tVT_Char) - ); - if(oldTBuf) { - // Copy old buffer - w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW; - h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH; - h *= giVT_Scrollback + 1; - for( i = 0; i < h; i ++ ) - { - memcpy( - &Term->Text[i*Term->TextWidth], - &oldTBuf[i*oldTW], - w*sizeof(tVT_Char) - ); - } - free(oldTBuf); + // Fast exit if no resolution change + if(NewWidth == Term->Width && NewHeight == Term->Height) + return ; + + // Calculate new dimensions + Term->Width = NewWidth; + Term->Height = NewHeight; + Term->TextWidth = NewWidth / giVT_CharWidth; + Term->TextHeight = NewHeight / giVT_CharHeight; + Term->ScrollHeight = Term->TextHeight - (oldTH - Term->ScrollHeight) - Term->ScrollTop; + + // Allocate new buffers + // - Text + Term->Text = calloc( + Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1), + sizeof(tVT_Char) + ); + if(oldTBuf) { + // Copy old buffer + w = (oldTW > Term->TextWidth) ? Term->TextWidth : oldTW; + h = (oldTH > Term->TextHeight) ? Term->TextHeight : oldTH; + h *= giVT_Scrollback + 1; + for( i = 0; i < h; i ++ ) + { + memcpy( + &Term->Text[i*Term->TextWidth], + &oldTBuf[i*oldTW], + w*sizeof(tVT_Char) + ); } - - // - Alternate Text - Term->AltBuf = realloc( - Term->AltBuf, - Term->TextWidth * Term->TextHeight * sizeof(tVT_Char) - ); - - // - Framebuffer + free(oldTBuf); + } + + // - Alternate Text + Term->AltBuf = realloc( + Term->AltBuf, + Term->TextWidth * Term->TextHeight * sizeof(tVT_Char) + ); + + // - Framebuffer + if(oldFB) { Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) ); - if(oldFB) { - // Copy old buffer - w = (oldW > Term->Width) ? Term->Width : oldW; - h = (oldH > Term->Height) ? Term->Height : oldH; - for( i = 0; i < h; i ++ ) - { - memcpy( - &Term->Buffer[i*Term->Width], - &oldFB[i*oldW], - w*sizeof(Uint32) - ); - } - free(oldFB); - } - - // Debug - switch(NewMode) + // Copy old buffer + w = (oldW > Term->Width) ? Term->Width : oldW; + h = (oldH > Term->Height) ? Term->Height : oldH; + for( i = 0; i < h; i ++ ) { - case TERM_MODE_TEXT: - Log_Log("VTerm", "Set VT %p to text mode (%ix%i)", - Term, Term->TextWidth, Term->TextHeight); - break; - case TERM_MODE_FB: - Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)", - Term, Term->Width, Term->Height); - break; - //case TERM_MODE_2DACCEL: - //case TERM_MODE_3DACCEL: - // return; + memcpy( + &Term->Buffer[i*Term->Width], + &oldFB[i*oldW], + w*sizeof(Uint32) + ); } + free(oldFB); } + // Debug + switch(NewMode) + { + case TERM_MODE_TEXT: + Log_Log("VTerm", "Set VT %p to text mode (%ix%i)", + Term, Term->TextWidth, Term->TextHeight); + break; + case TERM_MODE_FB: + Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)", + Term, Term->Width, Term->Height); + break; + //case TERM_MODE_2DACCEL: + //case TERM_MODE_3DACCEL: + // return; + } }