X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fdrv%2Fvterm.c;h=d8689232078cd9eca8d4c7148446a6f70bb11f36;hb=321d008781422b7d7137e9acc1ba0e84dec79ff1;hp=0e66601a2c2d8fcb388091a84d284c542aca7c9c;hpb=7514bb8053931759b99f77d3f9ad70446b0625ac;p=tpg%2Facess2.git diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c index 0e66601a..d8689232 100644 --- a/Kernel/drv/vterm.c +++ b/Kernel/drv/vterm.c @@ -1,7 +1,7 @@ /* * Acess2 Virtual Terminal Driver */ -#define DEBUG 1 +#define DEBUG 0 #include #include #include @@ -18,12 +18,12 @@ #define NUM_VTS 8 #define MAX_INPUT_CHARS32 64 #define MAX_INPUT_CHARS8 (MAX_INPUT_CHARS32*4) -#define VT_SCROLLBACK 1 // 2 Screens of text -#define DEFAULT_OUTPUT "VGA" //#define DEFAULT_OUTPUT "BochsGA" +#define DEFAULT_OUTPUT "Vesa" #define DEFAULT_INPUT "PS2Keyboard" -#define DEFAULT_WIDTH 80 -#define DEFAULT_HEIGHT 25 +#define DEFAULT_WIDTH 640 +#define DEFAULT_HEIGHT 480 +#define DEFAULT_SCROLLBACK 2 // 2 Screens of text + current screen #define DEFAULT_COLOUR (VT_COL_BLACK|(0xAAA<<16)) #define VT_FLAG_HIDECSR 0x01 @@ -41,13 +41,10 @@ typedef struct { int Flags; //!< Flags (see VT_FLAG_*) short Width; //!< Virtual Width short Height; //!< Virtual Height - short RealWidth; //!< Real Width - short RealHeight; //!< Real Height int ViewPos; //!< View Buffer Offset (Text Only) int WritePos; //!< Write Buffer Offset (Text Only) Uint32 CurColour; //!< Current Text Colour - char Name[2]; //!< Name of the terminal int InputRead; //!< Input buffer read position int InputWrite; //!< Input buffer write position @@ -56,6 +53,7 @@ typedef struct { tVT_Char *Text; Uint32 *Buffer; }; + char Name[2]; //!< Name of the terminal tVFS_Node Node; } tVTerm; @@ -64,22 +62,29 @@ extern void Debug_SetKTerminal(char *File); // === PROTOTYPES === int VT_Install(char **Arguments); +void VT_InitOutput(void); +void VT_InitInput(void); char *VT_ReadDir(tVFS_Node *Node, int Pos); tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name); int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data); Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data); +void VT_SetResolution(int Width, int Height); +void VT_SetMode(int Mode); void VT_SetTerminal(int ID); void VT_KBCallBack(Uint32 Codepoint); void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count); int VT_int_ParseEscape(tVTerm *Term, char *Buffer); void VT_int_PutChar(tVTerm *Term, Uint32 Ch); +void VT_int_ScrollFramebuffer( tVTerm *Term ); void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ); void VT_int_ChangeMode(tVTerm *Term, int NewMode); // === CONSTANTS === const Uint16 caVT100Colours[] = { + // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray + // Same again, but bright VT_COL_BLACK, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0xAAA, VT_COL_GREY, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, VT_COL_WHITE }; @@ -101,6 +106,11 @@ tDevFS_Driver gVT_DrvInfo = { // --- Terminals --- tVTerm gVT_Terminals[NUM_VTS]; int giVT_CurrentTerminal = 0; +tVTerm *gpVT_CurTerm = &gVT_Terminals[0]; +// --- Video State --- +short giVT_RealWidth = DEFAULT_WIDTH; //!< Screen Width +short giVT_RealHeight = DEFAULT_HEIGHT; //!< Screen Height + int giVT_Scrollback = DEFAULT_SCROLLBACK; // --- Driver Handles --- char *gsVT_OutputDevice = NULL; char *gsVT_InputDevice = NULL; @@ -118,37 +128,35 @@ char *gsVT_InputDevice = NULL; */ int VT_Install(char **Arguments) { - char **args = Arguments; - char *arg; int i; // Scan Arguments if(Arguments) { + char **args = Arguments; + char *arg, *opt, *val; for( ; (arg = *args); args++ ) { - if(arg[0] != '-') continue; + Log_Debug("VTerm", "Argument '%s'", arg); + opt = arg; + val = arg + strpos(arg, '='); *val++ = '\0'; - switch(arg[1]) - { - // Set output device - case 'o': - if(args[1] == NULL) break; + if( strcmp(opt, "Video") == 0 ) { if(gsVT_OutputDevice) free(gsVT_OutputDevice); - gsVT_OutputDevice = malloc(strlen(args[1])+1); - strcpy(gsVT_OutputDevice, args[1]); - args ++; - break; - - // Set input device - case 'i': - if(args[1] == NULL) break; + gsVT_OutputDevice = strdup(val); + } + else if( strcmp(opt, "Input") == 0 ) { if(gsVT_InputDevice) free(gsVT_InputDevice); - gsVT_InputDevice = malloc(strlen(args[1])+1); - strcpy(gsVT_InputDevice, args[1]); - args ++; - break; - + gsVT_InputDevice = strdup(val); + } + else if( strcmp(opt, "Width") == 0 ) { + giVT_RealWidth = atoi( val ); + } + else if( strcmp(opt, "Height") == 0 ) { + giVT_RealHeight = atoi( val ); + } + else if( strcmp(opt, "Scrollback") == 0 ) { + giVT_Scrollback = atoi( val ); } } } @@ -157,21 +165,24 @@ int VT_Install(char **Arguments) if(!gsVT_OutputDevice) gsVT_OutputDevice = "/Devices/"DEFAULT_OUTPUT; if(!gsVT_InputDevice) gsVT_InputDevice = "/Devices/"DEFAULT_INPUT; - LOG("Using '%s' as output", gsVT_OutputDevice); - LOG("Using '%s' as input", gsVT_InputDevice); + Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice); + Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice); // Create Nodes for( i = 0; i < NUM_VTS; i++ ) { gVT_Terminals[i].Mode = TERM_MODE_TEXT; gVT_Terminals[i].Flags = 0; - gVT_Terminals[i].Width = DEFAULT_WIDTH; - gVT_Terminals[i].Height = DEFAULT_HEIGHT; + gVT_Terminals[i].Width = giVT_RealWidth/giVT_CharWidth; + gVT_Terminals[i].Height = giVT_RealHeight/giVT_CharHeight; gVT_Terminals[i].CurColour = DEFAULT_COLOUR; gVT_Terminals[i].WritePos = 0; gVT_Terminals[i].ViewPos = 0; - gVT_Terminals[i].Buffer = calloc( DEFAULT_WIDTH*DEFAULT_HEIGHT*VT_SCROLLBACK, sizeof(tVT_Char) ); + gVT_Terminals[i].Buffer = calloc( + gVT_Terminals[i].Width*gVT_Terminals[i].Height*(giVT_Scrollback+1), + sizeof(tVT_Char) + ); gVT_Terminals[i].Name[0] = '0'+i; gVT_Terminals[i].Name[1] = '\0'; @@ -187,10 +198,14 @@ int VT_Install(char **Arguments) // Add to DevFS DevFS_AddDevice( &gVT_DrvInfo ); + VT_InitOutput(); + VT_InitInput(); + // Set kernel output to VT0 Debug_SetKTerminal("/Devices/VTerm/0"); - return MODULE_INIT_SUCCESS; + Log_Log("VTerm", "Returning %i", MODULE_ERR_OK); + return MODULE_ERR_OK; } /** @@ -200,7 +215,13 @@ int VT_Install(char **Arguments) void VT_InitOutput() { giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE); + if(giVT_InputDevHandle == -1) { + Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice); + return ; + } + VT_SetResolution(giVT_RealWidth, giVT_RealHeight); VT_SetTerminal( 0 ); + VT_SetMode( VIDEO_BUFFMT_TEXT ); } /** @@ -233,7 +254,7 @@ tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name) { int num; - //ENTER("pNode sName", Node, Name); + ENTER("pNode sName", Node, Name); // Open the input and output files if needed if(giVT_OutputDevHandle == -2) VT_InitOutput(); @@ -251,7 +272,7 @@ tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name) return NULL; } // Return node - //LEAVE('p', &gVT_Terminals[num].Node); + LEAVE('p', &gVT_Terminals[num].Node); return &gVT_Terminals[num].Node; } @@ -317,8 +338,8 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) } break; - case TERM_MODE_FB: - case TERM_MODE_OPENGL: + //case TERM_MODE_FB: + default: while(pos < Length) { while(term->InputRead == term->InputWrite) Threads_Yield(); @@ -339,8 +360,7 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) { tVTerm *term = &gVT_Terminals[ Node->Inode ]; - - //ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + int size; // Write switch( term->Mode ) @@ -348,9 +368,58 @@ Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) case TERM_MODE_TEXT: VT_int_PutString(term, Buffer, Length); break; + case TERM_MODE_FB: + size = term->Width*term->Height*4; + if( Offset > size ) { + Log_Notice("VTerm", "VT_Write: Offset (0x%llx) > FBSize (0x%x)", + Offset, size); + return 0; + } + + if( Offset + Length > size ) { + Log_Notice("VTerm", "VT_Write: Offset+Length (0x%llx) > FBSize (0x%x)", + Offset+Length, size); + Length = size - Offset; + } + + memcpy( (void*)((Uint)term->Buffer + (Uint)Offset), Buffer, Length ); + + if( Node->Inode == giVT_CurrentTerminal ) + { + if( giVT_RealWidth > term->Width || giVT_RealHeight > term->Height ) + { + int x, y, w, h; + 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; + while(h--) + { + VFS_WriteAt( giVT_OutputDevHandle, + (x + y * giVT_RealWidth)*4, + term->Width * 4, + Buffer + ); + Buffer = (void*)( (Uint)Buffer + term->Width*4 ); + y ++; + } + return 0; + } + else { + return VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer ); + } + } + + case TERM_MODE_2DACCEL: + //case TERM_MODE_3DACCEL: + if( Node->Inode == giVT_CurrentTerminal ) + { + VFS_Write( giVT_OutputDevHandle, Length, Buffer ); + } + break; } - //LEAVE('i', 0); return 0; } @@ -364,8 +433,15 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) tVTerm *term = Node->ImplPtr; ENTER("pNode iId pData", Node, Id, Data); + if(Id >= DRV_IOCTL_LOOKUP) { + // Only root can fiddle with graphics modes + // TODO: Remove this and replace with user ownership + if( Threads_GetUID() != 0 ) return -1; + } + switch(Id) { + // --- Core Defined case DRV_IOCTL_TYPE: LEAVE('i', DRV_TYPE_TERMINAL); return DRV_TYPE_TERMINAL; @@ -384,11 +460,18 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) case TERM_IOCTL_MODETYPE: if(Data != NULL) { + if( CheckMem(Data, sizeof(int)) == 0 ) { + LEAVE('i', -1); + return -1; + } + Log_Log("VTerm", "VTerm %i mode set to %i", (int)Node->Inode, *iData); + + // Update mode if needed if(term->Mode != *iData) VT_int_ChangeMode(term, *iData); // Update the screen dimensions - if(giVT_CurrentTerminal == Node->Inode) + if(Node->Inode == giVT_CurrentTerminal) VT_SetTerminal( giVT_CurrentTerminal ); } LEAVE('i', term->Mode); @@ -396,55 +479,117 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) // Get/set the terminal width case TERM_IOCTL_WIDTH: - if(Data != NULL) term->Width = *iData; + if(Data != NULL) { + if( CheckMem(Data, sizeof(int)) == 0 ) { + LEAVE('i', -1); + return -1; + } + term->Width = *iData; + } Log("VT_Terminal_IOCtl - RETURN term->Width = %i", term->Width); LEAVE('i', term->Width); return term->Width; // Get/set the terminal height case TERM_IOCTL_HEIGHT: - if(Data != NULL) term->Height = *iData; + if(Data != NULL) { + if( CheckMem(Data, sizeof(int)) == 0 ) { + LEAVE('i', -1); + return -1; + } + term->Height = *iData; + } Log("VT_Terminal_IOCtl - RETURN term->Height = %i", term->Height); LEAVE('i', term->Height); return term->Height; + + case TERM_IOCTL_FORCESHOW: + Log_Log("VTerm", "Thread %i forced VTerm %i to be shown", + Threads_GetTID(), (int)Node->Inode); + VT_SetTerminal( Node->Inode ); + LEAVE('i', 1); + return 1; } LEAVE('i', -1); return -1; } -/** - * \fn void VT_SetTerminal(int ID) - * \brief Set the current terminal - */ -void VT_SetTerminal(int ID) +void VT_SetResolution(int Width, int Height) { tVideo_IOCtl_Mode mode = {0}; - int modeNum; + int tmp; + int i; // Create the video mode - mode.width = gVT_Terminals[ ID ].Width; - mode.height = gVT_Terminals[ ID ].Height; - // - Text Mode - if(gVT_Terminals[ ID ].Mode == TERM_MODE_TEXT) { - mode.bpp = 12; - mode.flags = VIDEO_FLAG_TEXT; - } - // - Framebuffer or 3D - else { - mode.bpp = 32; - mode.flags = 0; - } + mode.width = Width; + mode.height = Height; + mode.bpp = 32; + mode.flags = 0; // Set video mode VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode ); - modeNum = mode.id; - gVT_Terminals[ ID ].RealWidth = mode.width; - gVT_Terminals[ ID ].RealHeight = mode.height; - VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &modeNum ); + tmp = mode.id; + if( Width != mode.width || Height != mode.height ) + { + Log_Warning("VTerm", + "Selected resolution (%ix%i is not supported) by the device, using (%ix%i)", + giVT_RealWidth, giVT_RealHeight, + mode.width, mode.height + ); + } + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp ); + // Resize text terminals if needed + if( giVT_RealWidth != mode.width || giVT_RealHeight != mode.height ) + { + int newBufSize = (giVT_RealWidth/giVT_CharWidth) + *(giVT_RealHeight/giVT_CharHeight) + *(giVT_Scrollback+1); + //tVT_Char *tmp; + // Resize the text terminals + giVT_RealWidth = mode.width; + giVT_RealHeight = mode.height; + for( i = 0; i < NUM_VTS; i ++ ) + { + if( gVT_Terminals[i].Mode != TERM_MODE_TEXT ) continue; + + gVT_Terminals[i].Text = realloc( + gVT_Terminals[i].Text, + newBufSize*sizeof(tVT_Char) + ); + } + } +} + +void VT_SetMode(int Mode) +{ + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode ); +} + +/** + * \fn void VT_SetTerminal(int ID) + * \brief Set the current terminal + */ +void VT_SetTerminal(int ID) +{ // Update current terminal ID - Log("Changed terminal from %i to %i", giVT_CurrentTerminal, 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->Mode == TERM_MODE_TEXT && !(gpVT_CurTerm->Flags & VT_FLAG_HIDECSR) ) + { + tVideo_IOCtl_Pos pos; + pos.x = gpVT_CurTerm->WritePos % gpVT_CurTerm->Width; + pos.y = gpVT_CurTerm->WritePos / gpVT_CurTerm->Width; + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); + } + + if( gpVT_CurTerm->Mode == TERM_MODE_TEXT ) + VT_SetMode( VIDEO_BUFFMT_TEXT ); + else + VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER ); // Update the screen VT_int_UpdateScreen( &gVT_Terminals[ ID ], 1 ); @@ -453,6 +598,11 @@ void VT_SetTerminal(int ID) /** * \fn void VT_KBCallBack(Uint32 Codepoint) * \brief Called on keyboard interrupt + * \param Codepoint Pseudo-UTF32 character + * + * Handles a key press and sends the key code to the user's buffer. + * If the code creates a kernel-magic sequence, it is not passed to the + * user and is handled in-kernel. */ void VT_KBCallBack(Uint32 Codepoint) { @@ -520,8 +670,16 @@ void VT_KBCallBack(Uint32 Codepoint) case KEY_F11: VT_SetTerminal(10); return; case KEY_F12: VT_SetTerminal(11); return; case KEY_PGUP: + if( gpVT_CurTerm->ViewPos > gpVT_CurTerm->Width ) + gpVT_CurTerm->ViewPos -= gpVT_CurTerm->Width; + else + gpVT_CurTerm->ViewPos = 0; return; case KEY_PGDOWN: + if( gpVT_CurTerm->ViewPos < gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback-1) ) + gpVT_CurTerm->ViewPos += gpVT_CurTerm->Width; + else + gpVT_CurTerm->ViewPos = gpVT_CurTerm->Width*gpVT_CurTerm->Height*(giVT_Scrollback-1); return; } } @@ -606,41 +764,6 @@ void VT_KBCallBack(Uint32 Codepoint) } } -/** - * \fn void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) - * \brief Print a string to the Virtual Terminal - */ -void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) -{ - Uint32 val; - int i; - for( i = 0; i < Count; i++ ) - { - if( Buffer[i] == 0x1B ) // Escape Sequence - { - i ++; - i += VT_int_ParseEscape(Term, (char*)&Buffer[i]); - continue; - } - - if( Buffer[i] < 128 ) // Plain ASCII - VT_int_PutChar(Term, Buffer[i]); - else { // UTF-8 - i += ReadUTF8(&Buffer[i], &val); - VT_int_PutChar(Term, val); - } - } - - // Update cursor - if( !(Term->Flags & VT_FLAG_HIDECSR) ) - { - tVideo_IOCtl_Pos pos; - pos.x = Term->WritePos % Term->Width; - pos.y = Term->WritePos / Term->Width; - VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); - } -} - /** * \fn void VT_int_ClearLine(tVTerm *Term, int Num) * \brief Clears a line in a virtual terminal @@ -666,28 +789,37 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) char c; int argc = 0, j = 1; int tmp; - int args[4] = {0,0,0,0}; + int args[6] = {0,0,0,0}; - switch(Buffer[0]) { + switch(Buffer[0]) + { //Large Code case '[': // Get Arguments - c = Buffer[1]; - do { - while('0' <= c && c <= '9') { - args[argc] *= 10; - args[argc] += c-'0'; - c = Buffer[++j]; - } - if( j != 1 ) argc ++; - } while(c == ';'); + c = Buffer[j++]; + if( '0' <= c && c <= '9' ) + { + do { + if(c == ';') c = Buffer[j++]; + while('0' <= c && c <= '9') { + args[argc] *= 10; + args[argc] += c-'0'; + c = Buffer[j++]; + } + argc ++; + } while(c == ';'); + } + /* // Get string (what does this do?) if(c == '"') { - c = Buffer[++j]; + c = Buffer[j++]; while(c != '"') - c = Buffer[++j]; + c = Buffer[j++]; } + */ + + //Log_Debug("VTerm", "argc = %i", argc); // Get Command if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) @@ -723,7 +855,7 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) { case 2: { - int i = Term->Height * VT_SCROLLBACK; + int i = Term->Height * (giVT_Scrollback + 1); while( i-- ) VT_int_ClearLine(Term, i); Term->WritePos = 0; Term->ViewPos = 0; @@ -732,6 +864,11 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) break; } break; + // Set cursor position + case 'h': + Term->WritePos = args[0] + args[1]*Term->Width; + Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]); + break; // Set Font flags case 'm': for( ; argc--; ) @@ -758,15 +895,59 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) } } break; + default: + Log_Warning("VTerm", "Unknown control sequence"); + break; } } break; - default: - break; + default: break; } - return j + 1; + //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer); + return j; +} + +/** + * \fn void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) + * \brief Print a string to the Virtual Terminal + */ +void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) +{ + Uint32 val; + int i; + + // Iterate + for( i = 0; i < Count; i++ ) + { + // Handle escape sequences + if( Buffer[i] == 0x1B ) + { + i ++; + i += VT_int_ParseEscape(Term, (char*)&Buffer[i]) - 1; + continue; + } + + // Fast check for non UTF-8 + if( Buffer[i] < 128 ) // Plain ASCII + VT_int_PutChar(Term, Buffer[i]); + else { // UTF-8 + i += ReadUTF8(&Buffer[i], &val) - 1; + VT_int_PutChar(Term, val); + } + } + // Update Screen + VT_int_UpdateScreen( Term, 0 ); + + // Update cursor + if( Term == gpVT_CurTerm && !(Term->Flags & VT_FLAG_HIDECSR) ) + { + tVideo_IOCtl_Pos pos; + pos.x = Term->WritePos % Term->Width; + pos.y = Term->WritePos / Term->Width; + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); + } } /** @@ -776,13 +957,12 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) void VT_int_PutChar(tVTerm *Term, Uint32 Ch) { int i; - //ENTER("pTerm xCh", Term, Ch); - //LOG("Term = {WritePos:%i, ViewPos:%i}", Term->WritePos, Term->ViewPos); - + switch(Ch) { case '\0': return; // Ignore NULL byte case '\n': + VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining Term->WritePos += Term->Width; case '\r': Term->WritePos -= Term->WritePos % Term->Width; @@ -824,27 +1004,33 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) Term->WritePos ++; break; } - // Move Screen - if(Term->WritePos >= Term->Width*Term->Height*VT_SCROLLBACK) + // - Check if we need to scroll the entire scrollback buffer + if(Term->WritePos >= Term->Width*Term->Height*(giVT_Scrollback+1)) { int base, i; + + //Debug("Scrolling entire buffer"); + + // Move back by one Term->WritePos -= Term->Width; + // Update the scren + VT_int_UpdateScreen( Term, 0 ); // Update view position - base = Term->Width*Term->Height*(VT_SCROLLBACK-1); - if(Term->ViewPos < base) Term->ViewPos += Term->Width; - if(Term->ViewPos > base) Term->ViewPos = base; + base = Term->Width*Term->Height*(giVT_Scrollback); + if(Term->ViewPos < base) + Term->ViewPos += Term->Width; + if(Term->ViewPos > base) + Term->ViewPos = base; // Scroll terminal cache - base = Term->Width*(Term->Height*VT_SCROLLBACK-1); - - // Scroll Back + base = Term->Width*(Term->Height*(giVT_Scrollback+1)-1); memcpy( Term->Text, &Term->Text[Term->Width], - Term->Width*(Term->Height-1)*VT_SCROLLBACK*sizeof(tVT_Char) + (Term->Width*Term->Height*(giVT_Scrollback+1)-Term->Width)*sizeof(tVT_Char) ); // Clear last row @@ -854,19 +1040,67 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) Term->Text[ base + i ].Colour = Term->CurColour; } - VT_int_UpdateScreen( Term, 1 ); + VT_int_ScrollFramebuffer( Term ); + VT_int_UpdateScreen( Term, 0 ); } - else if(Term->WritePos > Term->Width*Term->Height+Term->ViewPos) + // Ok, so we only need to scroll the screen + else if(Term->WritePos >= Term->ViewPos + Term->Width*Term->Height) { + //Debug("Term->WritePos (%i) >= %i", + // Term->WritePos, + // Term->ViewPos + Term->Width*Term->Height + // ); + //Debug("Scrolling screen only"); + + // Update the last line + Term->WritePos -= Term->Width; + VT_int_UpdateScreen( Term, 0 ); + Term->WritePos += Term->Width; + + // Scroll Term->ViewPos += Term->Width; - VT_int_UpdateScreen( Term, 1 ); - } - else + //Debug("Term->ViewPos = %i", Term->ViewPos); + VT_int_ScrollFramebuffer( Term ); VT_int_UpdateScreen( Term, 0 ); + } //LEAVE('-'); } +/** + * \fn void VT_int_ScrollFramebuffer( tVTerm *Term ) + * \note Scrolls the framebuffer by 1 text line + */ +void VT_int_ScrollFramebuffer( tVTerm *Term ) +{ + int tmp; + struct { + Uint8 Op; + Uint16 DstX, DstY; + Uint16 SrcX, SrcY; + Uint16 W, H; + } PACKED buf; + + // Only update if this is the current terminal + if( Term != gpVT_CurTerm ) return; + + // Switch to 2D Command Stream + tmp = VIDEO_BUFFMT_2DSTREAM; + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp); + + // BLIT from 0,0 to 0,giVT_CharHeight + buf.Op = VIDEO_2DOP_BLIT; + buf.DstX = 0; buf.DstY = 0; + buf.SrcX = 0; buf.SrcY = giVT_CharHeight; + buf.W = Term->Width * giVT_CharWidth; + buf.H = (Term->Height-1) * giVT_CharHeight; + VFS_WriteAt(giVT_OutputDevHandle, 0, sizeof(buf), &buf); + + // Restore old mode (this function is only called during text mode) + tmp = VIDEO_BUFFMT_TEXT; + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp); +} + /** * \fn void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) * \brief Updates the video framebuffer @@ -874,10 +1108,12 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) { // Only update if this is the current terminal - if( Term != &gVT_Terminals[giVT_CurrentTerminal] ) return; + if( Term != gpVT_CurTerm ) return; - if( Term->Mode == TERM_MODE_TEXT ) + switch( Term->Mode ) { + case TERM_MODE_TEXT: + // Re copy the entire screen? if(UpdateAll) { VFS_WriteAt( giVT_OutputDevHandle, @@ -885,7 +1121,9 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) Term->Width*Term->Height*sizeof(tVT_Char), &Term->Text[Term->ViewPos] ); - } else { + } + // Only copy the current line + else { int pos = Term->WritePos - Term->WritePos % Term->Width; VFS_WriteAt( giVT_OutputDevHandle, @@ -894,15 +1132,15 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) &Term->Text[pos] ); } - } - else - { + break; + case TERM_MODE_FB: VFS_WriteAt( giVT_OutputDevHandle, 0, Term->Width*Term->Height*sizeof(Uint32), - &Term->Buffer + Term->Buffer ); + break; } } @@ -915,15 +1153,20 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode) switch(NewMode) { case TERM_MODE_TEXT: + Log_Log("VTerm", "Set VT %p to text mode", Term); free(Term->Buffer); - Term->Text = calloc( Term->Width*Term->Height*VT_SCROLLBACK, sizeof(tVT_Char) ); + Term->Text = calloc( Term->Width*Term->Height*(giVT_Scrollback+1), sizeof(tVT_Char) ); break; case TERM_MODE_FB: + Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)", Term, + Term->Width, Term->Height); free(Term->Text); Term->Buffer = calloc( Term->Width*Term->Height, sizeof(Uint32) ); + Log_Debug("VTerm", "Term->Buffer = %p", Term->Buffer); break; - case TERM_MODE_OPENGL: - return; + //case TERM_MODE_2DACCEL: + //case TERM_MODE_3DACCEL: + // return; } Term->Mode = NewMode; @@ -944,7 +1187,7 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode) Uint8 *VT_Font_GetChar(Uint32 Codepoint); // === GLOBALS === -int giVT_CharWidth = FONT_WIDTH+1; +int giVT_CharWidth = FONT_WIDTH; int giVT_CharHeight = FONT_HEIGHT; // === CODE ===