X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fdrv%2Fvterm.c;h=2ae38ee894c602430190a667d7f050eaca3f6578;hb=7536e8afcc3018c4ca2a4aa8f8422cf86a6c188c;hp=9e1055ef99dc33eb86375977f2e66f84a4c798b8;hpb=3764c294f21229bdf700f436fa4884f5e76e0d3a;p=tpg%2Facess2.git diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c index 9e1055ef..2ae38ee8 100644 --- a/Kernel/drv/vterm.c +++ b/Kernel/drv/vterm.c @@ -2,105 +2,57 @@ * Acess2 Virtual Terminal Driver */ #define DEBUG 0 -#include +#include "vterm.h" #include #include -#include -#include -#include +#include +#include #include #include -#define USE_CTRL_ALT 1 - // === CONSTANTS === #define VERSION ((0<<8)|(50)) #define NUM_VTS 8 -#define MAX_INPUT_CHARS32 64 -#define MAX_INPUT_CHARS8 (MAX_INPUT_CHARS32*4) //#define DEFAULT_OUTPUT "BochsGA" #define DEFAULT_OUTPUT "Vesa" +#define FALLBACK_OUTPUT "x86_VGAText" #define DEFAULT_INPUT "PS2Keyboard" #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 -#define VT_FLAG_HASFB 0x10 //!< Set if the VTerm has requested the Framebuffer - -enum eVT_InModes { - VT_INMODE_TEXT8, // UTF-8 Text Mode (VT100/xterm Emulation) - VT_INMODE_TEXT32, // UTF-32 Text Mode (Acess Native) - NUM_VT_INMODES -}; +//#define DEFAULT_SCROLLBACK 0 // === TYPES === -typedef struct { - int Mode; //!< Current Mode (see ::eTplTerminal_Modes) - int Flags; //!< Flags (see VT_FLAG_*) - - short NewWidth; //!< Un-applied dimensions (Width) - short NewHeight; //!< Un-applied dimensions (Height) - short Width; //!< Virtual Width - short Height; //!< Virtual Height - short TextWidth; //!< Text Virtual Width - short TextHeight; //!< Text Virtual Height - - int ViewPos; //!< View Buffer Offset (Text Only) - int WritePos; //!< Write Buffer Offset (Text Only) - Uint32 CurColour; //!< Current Text Colour - - tMutex ReadingLock; //!< Lock the VTerm when a process is reading from it - tTID ReadingThread; //!< Owner of the lock - int InputRead; //!< Input buffer read position - int InputWrite; //!< Input buffer write position - char InputBuffer[MAX_INPUT_CHARS8]; -// tSemaphore InputSemaphore; - - tVT_Char *Text; - Uint32 *Buffer; - - char Name[2]; //!< Name of the terminal - tVFS_Node Node; -} tVTerm; // === IMPORTS === extern void Debug_SetKTerminal(const 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, const 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); +Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const 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); -void VT_int_ClearLine(tVTerm *Term, int Num); - 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, int NewWidth, int NewHeight); // === 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 - }; // === GLOBALS === -MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, DEFAULT_OUTPUT, DEFAULT_INPUT, NULL); +MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, DEFAULT_INPUT, NULL); +tVFS_NodeType gVT_RootNodeType = { + .TypeName = "VTerm Root", + .ReadDir = VT_ReadDir, + .FindDir = VT_FindDir, + .IOCtl = VT_Root_IOCtl + }; +tVFS_NodeType gVT_TermNodeType = { + .TypeName = "VTerm", + .Read = VT_Read, + .Write = VT_Write, + .IOCtl = VT_Terminal_IOCtl + }; tDevFS_Driver gVT_DrvInfo = { NULL, "VTerm", { @@ -108,9 +60,7 @@ tDevFS_Driver gVT_DrvInfo = { .Size = NUM_VTS, .Inode = -1, .NumACLs = 0, - .ReadDir = VT_ReadDir, - .FindDir = VT_FindDir, - .IOCtl = VT_Root_IOCtl + .Type = &gVT_RootNodeType } }; // --- Terminals --- @@ -126,10 +76,6 @@ char *gsVT_OutputDevice = NULL; char *gsVT_InputDevice = NULL; int giVT_OutputDevHandle = -2; int giVT_InputDevHandle = -2; -// --- Key States --- (Used for VT Switching/Magic Combos) - int gbVT_CtrlDown = 0; - int gbVT_AltDown = 0; - int gbVT_SysrqDown = 0; // === CODE === /** @@ -160,11 +106,11 @@ int VT_Install(char **Arguments) Log_Debug("VTerm", "Argument '%s'", arg); if( strcmp(opt, "Video") == 0 ) { - if( !gsVT_OutputDevice && Modules_InitialiseBuiltin( val ) == 0 ) + if( !gsVT_OutputDevice ) gsVT_OutputDevice = strdup(val); } else if( strcmp(opt, "Input") == 0 ) { - if( !gsVT_InputDevice && Modules_InitialiseBuiltin( val ) == 0 ) + if( !gsVT_InputDevice ) gsVT_InputDevice = strdup(val); } else if( strcmp(opt, "Width") == 0 ) { @@ -180,16 +126,25 @@ int VT_Install(char **Arguments) } // Apply Defaults - if(!gsVT_OutputDevice) gsVT_OutputDevice = strdup(DEFAULT_OUTPUT); - if(!gsVT_InputDevice) gsVT_InputDevice = strdup(DEFAULT_INPUT); + if(!gsVT_OutputDevice) gsVT_OutputDevice = (char*)DEFAULT_OUTPUT; + else if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)DEFAULT_OUTPUT; + if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)FALLBACK_OUTPUT; + if( Module_EnsureLoaded( gsVT_OutputDevice ) ) { + Log_Error("VTerm", "Fallback video '%s' is not avaliable, giving up", FALLBACK_OUTPUT); + return MODULE_ERR_MISC; + } + + if(!gsVT_InputDevice) gsVT_InputDevice = (char*)DEFAULT_INPUT; + else if( Module_EnsureLoaded( gsVT_InputDevice ) ) gsVT_InputDevice = (char*)DEFAULT_INPUT; - // Create paths + // Create device paths { char *tmp; tmp = malloc( 9 + strlen(gsVT_OutputDevice) + 1 ); strcpy(tmp, "/Devices/"); strcpy(&tmp[9], gsVT_OutputDevice); gsVT_OutputDevice = tmp; + tmp = malloc( 9 + strlen(gsVT_InputDevice) + 1 ); strcpy(tmp, "/Devices/"); strcpy(&tmp[9], gsVT_InputDevice); @@ -199,15 +154,21 @@ int VT_Install(char **Arguments) Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice); Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice); + VT_InitOutput(); + VT_InitInput(); + // Create Nodes for( i = 0; i < NUM_VTS; i++ ) { 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; gVT_Terminals[i].ViewPos = 0; gVT_Terminals[i].ReadingThread = -1; + gVT_Terminals[i].ScrollHeight = 0; // Initialise VT_int_ChangeMode( &gVT_Terminals[i], @@ -218,56 +179,20 @@ int VT_Install(char **Arguments) gVT_Terminals[i].Node.Inode = i; gVT_Terminals[i].Node.ImplPtr = &gVT_Terminals[i]; gVT_Terminals[i].Node.NumACLs = 0; // Only root can open virtual terminals - - gVT_Terminals[i].Node.Read = VT_Read; - gVT_Terminals[i].Node.Write = VT_Write; - gVT_Terminals[i].Node.IOCtl = VT_Terminal_IOCtl; + + gVT_Terminals[i].Node.Type = &gVT_TermNodeType; // Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name); } // Add to DevFS DevFS_AddDevice( &gVT_DrvInfo ); - VT_InitOutput(); - VT_InitInput(); - // Set kernel output to VT0 Debug_SetKTerminal("/Devices/VTerm/0"); - Log_Log("VTerm", "Returning %i", MODULE_ERR_OK); return MODULE_ERR_OK; } -/** - * \fn void VT_InitOutput() - * \brief Initialise Video Output - */ -void VT_InitOutput() -{ - giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE); - if(giVT_OutputDevHandle == -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 ); -} - -/** - * \fn void VT_InitInput() - * \brief Initialises the input - */ -void VT_InitInput() -{ - giVT_InputDevHandle = VFS_Open(gsVT_InputDevice, VFS_OPENFLAG_READ); - if(giVT_InputDevHandle == -1) { - Log_Warning("VTerm", "Can't open the input device '%s'", gsVT_InputDevice); - return ; - } - VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack); -} - /** * \brief Set the video resolution * \param Width New screen width @@ -295,25 +220,28 @@ 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 ); // Resize text terminals if needed - if( giVT_RealWidth != mode.width || giVT_RealHeight != mode.height ) + if( gVT_Terminals[0].Text && (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; + Log_Debug("VTerm", "Resizing terminals to %ix%i", + giVT_RealWidth/giVT_CharWidth, giVT_RealHeight/giVT_CharHeight); for( i = 0; i < NUM_VTS; i ++ ) { if( gVT_Terminals[i].Mode != TERM_MODE_TEXT ) continue; gVT_Terminals[i].TextWidth = giVT_RealWidth/giVT_CharWidth; gVT_Terminals[i].TextHeight = giVT_RealHeight/giVT_CharHeight; + gVT_Terminals[i].ScrollHeight = gVT_Terminals[i].TextHeight; gVT_Terminals[i].Text = realloc( gVT_Terminals[i].Text, @@ -323,14 +251,6 @@ void VT_SetResolution(int Width, int Height) } } -/** - * \brief Set video output buffer mode - */ -void VT_SetMode(int Mode) -{ - VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &Mode ); -} - /** * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos) * \brief Read from the VTerm Directory @@ -415,7 +335,6 @@ int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data) } /** - * \fn Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) * \brief Read from a virtual terminal */ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) @@ -433,6 +352,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; @@ -446,7 +367,8 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead]; pos ++; term->InputRead ++; - term->InputRead %= MAX_INPUT_CHARS8; + while(term->InputRead >= MAX_INPUT_CHARS8) + term->InputRead -= MAX_INPUT_CHARS8; } break; @@ -454,12 +376,13 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) // Other - UCS-4 default: VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UCS-4)"); - + 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; @@ -469,7 +392,8 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) codepoint_buf[pos] = codepoint_in[term->InputRead]; pos ++; term->InputRead ++; - term->InputRead %= MAX_INPUT_CHARS32; + while(term->InputRead >= MAX_INPUT_CHARS32) + term->InputRead -= MAX_INPUT_CHARS32; } pos *= 4; break; @@ -480,17 +404,19 @@ 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; } /** - * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer) * \brief Write to a virtual terminal */ -Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer) { tVTerm *term = &gVT_Terminals[ Node->Inode ]; int size; @@ -502,9 +428,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 ) { @@ -518,38 +444,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) @@ -610,9 +547,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 ) { @@ -678,908 +613,152 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) 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) -{ - // 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->Mode == TERM_MODE_TEXT && !(gpVT_CurTerm->Flags & VT_FLAG_HIDECSR) ) - { - tVideo_IOCtl_Pos pos; - pos.x = (gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos) % gpVT_CurTerm->TextWidth; - pos.y = (gpVT_CurTerm->WritePos - gpVT_CurTerm->ViewPos) / gpVT_CurTerm->TextWidth; - if( pos.x < gpVT_CurTerm->TextHeight ) - 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 ); -} - -/** - * \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) -{ - tVTerm *term = gpVT_CurTerm; - - // How the hell did we get a codepoint of zero? - if(Codepoint == 0) return; - - // Key Up - if( Codepoint & 0x80000000 ) - { - Codepoint &= 0x7FFFFFFF; - switch(Codepoint) - { - #if !USE_CTRL_ALT - case KEY_RSHIFT: gbVT_CtrlDown = 0; break; - case KEY_LSHIFT: gbVT_AltDown = 0; break; - #else - 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; - #endif - } - return; - } - - switch(Codepoint) - { - #if !USE_CTRL_ALT // HACK: Use both shifts instead of Ctrl-Alt - case KEY_RSHIFT: gbVT_CtrlDown = 1; break; - case KEY_LSHIFT: gbVT_AltDown = 1; break; - #else - 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; - #endif - - default: - if(!gbVT_AltDown || !gbVT_CtrlDown) - break; - switch(Codepoint) - { - case KEY_F1: VT_SetTerminal(0); return; - case KEY_F2: VT_SetTerminal(1); return; - case KEY_F3: VT_SetTerminal(2); return; - case KEY_F4: VT_SetTerminal(3); return; - case KEY_F5: VT_SetTerminal(4); return; - case KEY_F6: VT_SetTerminal(5); return; - case KEY_F7: VT_SetTerminal(6); return; - case KEY_F8: VT_SetTerminal(7); return; - case KEY_F9: VT_SetTerminal(8); return; - case KEY_F10: VT_SetTerminal(9); return; - case KEY_F11: VT_SetTerminal(10); return; - case KEY_F12: VT_SetTerminal(11); return; - // Scrolling - 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; - } - } - - // Encode key - if(term->Mode == TERM_MODE_TEXT) - { - Uint8 buf[6] = {0}; - int len = 0; - - // Ignore Modifer Keys - if(Codepoint > KEY_MODIFIERS) return; - - // Get UTF-8/ANSI Encoding - switch(Codepoint) + case TERM_IOCTL_GETSETCURSOR: + if(Data != NULL) { - case KEY_LEFT: - buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'D'; - len = 3; - break; - case KEY_RIGHT: - buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'C'; - len = 3; - break; - case KEY_UP: - buf[0] = '\x1B'; buf[1] = '['; buf[2] = 'A'; - len = 3; - break; - case KEY_DOWN: - 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 - break; - case KEY_PGDOWN: - len = 0; - break; - - // Attempt to encode in UTF-8 - default: - len = WriteUTF8( buf, Codepoint ); - if(len == 0) { - Warning("Codepoint (%x) is unrepresentable in UTF-8", Codepoint); + tVideo_IOCtl_Pos *pos = Data; + if( !CheckMem(Data, sizeof(*pos)) ) { + errno = -EINVAL; + LEAVE('i', -1); + return -1; } - break; - } - if(len == 0) { - // Unprintable / Don't Pass - return; - } - - // Write - if( MAX_INPUT_CHARS8 - term->InputWrite >= len ) - memcpy( &term->InputBuffer[term->InputWrite], buf, len ); - else { - memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite ); - memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) ); - } - // Roll the buffer over - term->InputWrite += len; - term->InputWrite %= MAX_INPUT_CHARS8; - if( (term->InputWrite - term->InputRead + MAX_INPUT_CHARS8)%MAX_INPUT_CHARS8 < len ) { - term->InputRead = term->InputWrite + 1; - term->InputRead %= MAX_INPUT_CHARS8; - } - } - else - { - // Encode the raw UTF-32 Key - Uint32 *raw_in = (void*)term->InputBuffer; - raw_in[ term->InputWrite ] = Codepoint; - term->InputWrite ++; - term->InputWrite %= MAX_INPUT_CHARS32; - if(term->InputRead == term->InputWrite) { - term->InputRead ++; - term->InputRead %= MAX_INPUT_CHARS32; - } - } - - VFS_MarkAvaliable(&term->Node, 1); - - // Wake up the thread waiting on us - //if( term->ReadingThread >= 0 ) { - // Threads_WakeTID(term->ReadingThread); - //} -} - -/** - * \fn void VT_int_ClearLine(tVTerm *Term, int Num) - * \brief Clears a line in a virtual terminal - */ -void VT_int_ClearLine(tVTerm *Term, int Num) -{ - int i; - tVT_Char *cell = &Term->Text[ Num*Term->TextWidth ]; - if( Num < 0 || Num >= Term->TextHeight * (giVT_Scrollback + 1) ) return ; - //ENTER("pTerm iNum", Term, Num); - for( i = Term->TextWidth; i--; ) - { - cell[ i ].Ch = 0; - cell[ i ].Colour = Term->CurColour; - } - //LEAVE('-'); -} - -/** - * \fn int VT_int_ParseEscape(tVTerm *Term, char *Buffer) - * \brief Parses a VT100 Escape code - */ -int VT_int_ParseEscape(tVTerm *Term, char *Buffer) -{ - char c; - int argc = 0, j = 1; - int tmp; - int args[6] = {0,0,0,0}; - - switch(Buffer[0]) - { - //Large Code - case '[': - // Get Arguments - 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 Command - if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) - { - switch(c) + if( term->Mode == TERM_MODE_TEXT ) { - // Left - case 'D': - if(argc == 1) tmp = args[0]; - else tmp = 1; - - if( Term->WritePos-(tmp-1) % Term->TextWidth == 0 ) - Term->WritePos -= Term->WritePos % Term->TextWidth; + if(term->Flags & VT_FLAG_ALTBUF) + term->AltWritePos = pos->x + pos->y * term->TextWidth; else - Term->WritePos -= tmp; - break; - - // Right - case 'C': - if(argc == 1) tmp = args[0]; - else tmp = 1; - if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) { - Term->WritePos -= Term->WritePos % Term->TextWidth; - Term->WritePos += Term->TextWidth - 1; - } else - Term->WritePos += tmp; - break; - - // Clear By Line - case 'J': - // Clear Screen - switch(args[0]) - { - case 2: - { - 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; - // Set cursor position - case 'h': - Term->WritePos = args[0] + args[1]*Term->TextWidth; - Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]); - 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; - default: - Log_Warning("VTerm", "Unknown control sequence"); - break; + 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); } } - break; - - default: break; - } - - //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->ViewPos) % Term->TextWidth; - pos.y = (Term->WritePos - Term->ViewPos) / Term->TextWidth; - VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); - } -} + ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos; + LEAVE('i', ret); + return ret; -/** - * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch) - * \brief Write a single character to a VTerm - */ -void VT_int_PutChar(tVTerm *Term, Uint32 Ch) -{ - int i; - - switch(Ch) - { - case '\0': return; // Ignore NULL byte - case '\n': - VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining - Term->WritePos += Term->TextWidth; - case '\r': - Term->WritePos -= Term->WritePos % Term->TextWidth; - break; - - case '\t': - do { - Term->Text[ Term->WritePos ].Ch = '\0'; - Term->Text[ Term->WritePos ].Colour = Term->CurColour; - Term->WritePos ++; - } while(Term->WritePos & 7); - break; - - case '\b': - // Backspace is invalid at Offset 0 - if(Term->WritePos == 0) break; - - Term->WritePos --; - // Singe Character - if(Term->Text[ Term->WritePos ].Ch != '\0') { - Term->Text[ Term->WritePos ].Ch = 0; - Term->Text[ Term->WritePos ].Colour = Term->CurColour; - break; - } - // Tab - i = 7; // Limit it to 8 - do { - Term->Text[ Term->WritePos ].Ch = 0; - Term->Text[ Term->WritePos ].Colour = Term->CurColour; - Term->WritePos --; - } while(Term->WritePos && i-- && Term->Text[ Term->WritePos ].Ch == '\0'); - if(Term->Text[ Term->WritePos ].Ch != '\0') - Term->WritePos ++; - break; - - default: - Term->Text[ Term->WritePos ].Ch = Ch; - Term->Text[ Term->WritePos ].Colour = Term->CurColour; - // Update the line before wrapping - if( (Term->WritePos + 1) % Term->TextWidth == 0 ) - VT_int_UpdateScreen( Term, 0 ); - Term->WritePos ++; - break; - } - - // Move Screen - // - Check if we need to scroll the entire scrollback buffer - if(Term->WritePos >= Term->TextWidth*Term->TextHeight*(giVT_Scrollback+1)) - { - int base; - - // Move back by one - Term->WritePos -= Term->TextWidth; - // Update the scren - VT_int_UpdateScreen( Term, 0 ); - - // Update view position - base = Term->TextWidth*Term->TextHeight*(giVT_Scrollback); - if(Term->ViewPos < base) - Term->ViewPos += Term->Width; - if(Term->ViewPos > base) - Term->ViewPos = base; - - // Scroll terminal cache - base = Term->TextWidth*(Term->TextHeight*(giVT_Scrollback+1)-1); - memcpy( - Term->Text, - &Term->Text[Term->TextWidth], - base*sizeof(tVT_Char) - ); - - // Clear last row - for( i = 0; i < Term->TextWidth; i ++ ) + case TERM_IOCTL_SETCURSORBITMAP: { + tVideo_IOCtl_Bitmap *bmp = Data; + if( Data == NULL ) { - Term->Text[ base + i ].Ch = 0; - Term->Text[ base + i ].Colour = Term->CurColour; + free( term->VideoCursor ); + term->VideoCursor = NULL; + LEAVE('i', 0); + return 0; } - - VT_int_ScrollFramebuffer( Term ); - VT_int_UpdateScreen( Term, 0 ); - } - // Ok, so we only need to scroll the screen - else if(Term->WritePos >= Term->ViewPos + Term->TextWidth*Term->TextHeight) - { - //Debug("Term->WritePos (%i) >= %i", - // Term->WritePos, - // Term->ViewPos + Term->TextWidth*Term->TextHeight - // ); - //Debug("Scrolling screen only"); - - // Update the last line - Term->WritePos -= Term->TextWidth; - VT_int_UpdateScreen( Term, 0 ); - Term->WritePos += Term->TextWidth; - VT_int_ClearLine(Term, Term->WritePos / Term->TextWidth); - - // Scroll - Term->ViewPos += Term->TextWidth; - //Debug("Term->ViewPos = %i", Term->ViewPos); - VT_int_ScrollFramebuffer( Term ); - VT_int_UpdateScreen( Term, 0 ); - - //VT_int_UpdateScreen( Term, 1 ); // HACK! - } - - //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->TextWidth * giVT_CharWidth; - buf.H = (Term->TextHeight-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 - */ -void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) -{ - // Only update if this is the current terminal - if( Term != gpVT_CurTerm ) return; - - switch( Term->Mode ) - { - case TERM_MODE_TEXT: - // Re copy the entire screen? - if(UpdateAll) { - VFS_WriteAt( - giVT_OutputDevHandle, - 0, - Term->TextWidth*Term->TextHeight*sizeof(tVT_Char), - &Term->Text[Term->ViewPos] - ); + // 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); } - // Only copy the current line - else { - int pos = Term->WritePos - Term->WritePos % Term->TextWidth; - VFS_WriteAt( - giVT_OutputDevHandle, - (pos - Term->ViewPos)*sizeof(tVT_Char), - Term->TextWidth*sizeof(tVT_Char), - &Term->Text[pos] - ); + 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); } - break; - case TERM_MODE_FB: - VFS_WriteAt( - giVT_OutputDevHandle, - 0, - Term->Width*Term->Height*sizeof(Uint32), - Term->Buffer - ); - break; - } -} -/** - * \brief Update the screen mode - * \param Term Terminal to update - * \param NewMode New mode to set - * \param NewWidth New framebuffer width - * \param NewHeight New framebuffer height - */ -void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight) -{ - int oldW = Term->Width; - int oldTW = oldW / giVT_CharWidth; - int oldH = Term->Height; - int oldTH = oldH / giVT_CharWidth; - 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; - - // Calculate new dimensions - Term->TextWidth = NewWidth / giVT_CharWidth; - Term->TextHeight = NewHeight / giVT_CharHeight; - Term->Width = NewWidth; - Term->Height = NewHeight; - Term->Mode = NewMode; - - // Allocate new buffers - // - Text - Term->Text = calloc( - Term->TextWidth * Term->TextHeight * (giVT_Scrollback+1), - sizeof(tVT_Char) - ); - if(oldTBuf) { - // Copy old buffer - w = oldTW; - if( w > Term->TextWidth ) w = Term->TextWidth; - h = oldTH; - if( h > Term->TextHeight ) h = Term->TextHeight; - h *= giVT_Scrollback + 1; - for( i = 0; i < h; i ++ ) + // Reallocate if needed + if(term->VideoCursor) { - memcpy( - &Term->Text[i*Term->TextWidth], - &oldTBuf[i*oldTW], - w*sizeof(tVT_Char) - ); - + if(bmp->W * bmp->H != term->VideoCursor->W * term->VideoCursor->H) { + free(term->VideoCursor); + term->VideoCursor = NULL; + } } - } - - // - Framebuffer - Term->Buffer = calloc( Term->Width * Term->Height, sizeof(Uint32) ); - if(oldFB) { - // Copy old buffer - w = oldW; - if( w > Term->Width ) w = Term->Width; - h = oldH; - if( h > Term->Height ) h = Term->Height; - for( i = 0; i < h; i ++ ) - { - memcpy( - &Term->Buffer[i*Term->Width], - &oldFB[i*oldW], - w*sizeof(Uint32) - ); + 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); - // 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; + LEAVE('i', 0); + return 0; } } + LEAVE('i', -1); + return -1; } -// --- -// Font Render -// --- -#define MONOSPACE_FONT 10816 - -#if MONOSPACE_FONT == 10808 // 8x8 -# include "vterm_font_8x8.h" -#elif MONOSPACE_FONT == 10816 // 8x16 -# include "vterm_font_8x16.h" -#endif - -// === PROTOTYPES === -Uint8 *VT_Font_GetChar(Uint32 Codepoint); - -// === GLOBALS === -int giVT_CharWidth = FONT_WIDTH; -int giVT_CharHeight = FONT_HEIGHT; - -// === CODE === /** - * \brief Render a font character + * \fn void VT_SetTerminal(int ID) + * \brief Set the current terminal */ -void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Depth, int Pitch, Uint32 BGC, Uint32 FGC) +void VT_SetTerminal(int ID) { - Uint8 *font; - int x, y; - - // 8-bpp and below - if( Depth <= 8 ) + // Copy the screen state + if( ID != giVT_CurrentTerminal && gpVT_CurTerm->Mode != TERM_MODE_TEXT ) { - Uint8 *buf = Buffer; - - font = VT_Font_GetChar(Codepoint); - - for(y = 0; y < FONT_HEIGHT; y ++) + if( !gpVT_CurTerm->Buffer ) + gpVT_CurTerm->Buffer = malloc( gpVT_CurTerm->Width*gpVT_CurTerm->Height*4 ); + if( gpVT_CurTerm->Width < giVT_RealWidth ) { - for(x = 0; x < FONT_WIDTH; x ++) + int line; + Uint ofs = 0; + Uint32 *dest = gpVT_CurTerm->Buffer; + // Slower scanline copy + for( line = 0; line < gpVT_CurTerm->Height; line ++ ) { - if(*font & (1 << (FONT_WIDTH-x-1))) - buf[x] = FGC; - else - buf[x] = BGC; + VFS_ReadAt(giVT_OutputDevHandle, ofs, gpVT_CurTerm->Width*4, dest); + ofs += giVT_RealWidth * 4; + dest += gpVT_CurTerm->Width; } - buf = (void*)( (tVAddr)buf + Pitch ); - font ++; } - } - // 16-bpp and below - else if( Depth <= 16 ) - { - Uint16 *buf = Buffer; - - font = VT_Font_GetChar(Codepoint); - - for(y = 0; y < FONT_HEIGHT; y ++) + else { - for(x = 0; x < FONT_WIDTH; x ++) - { - if(*font & (1 << (FONT_WIDTH-x-1))) - buf[x] = FGC; - else - buf[x] = BGC; - } - buf = (void*)( (tVAddr)buf + Pitch ); - font ++; + VFS_ReadAt(giVT_OutputDevHandle, + 0, gpVT_CurTerm->Height*giVT_RealWidth*4, + gpVT_CurTerm->Buffer + ); } } - // 24-bpp colour - // - Special handling to not overwrite the next pixel - //TODO: Endian issues here - else if( Depth == 24 ) + + // Update current terminal ID + Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID); + giVT_CurrentTerminal = ID; + gpVT_CurTerm = &gVT_Terminals[ID]; + + if( gpVT_CurTerm->Mode == TERM_MODE_TEXT ) { - Uint8 *buf = Buffer; - Uint8 bg_r = (BGC >> 16) & 0xFF; - Uint8 bg_g = (BGC >> 8) & 0xFF; - Uint8 bg_b = (BGC >> 0) & 0xFF; - Uint8 fg_r = (FGC >> 16) & 0xFF; - Uint8 fg_g = (FGC >> 8) & 0xFF; - Uint8 fg_b = (FGC >> 0) & 0xFF; - - font = VT_Font_GetChar(Codepoint); - - for(y = 0; y < FONT_HEIGHT; y ++) - { - for(x = 0; x < FONT_WIDTH; x ++) - { - Uint8 r, g, b; - - if(*font & (1 << (FONT_WIDTH-x-1))) { - r = fg_r; g = fg_g; b = fg_b; - } - else { - r = bg_r; g = bg_g; b = bg_b; - } - buf[x*3+0] = b; - buf[x*3+1] = g; - buf[x*3+2] = r; - } - buf = (void*)( (tVAddr)buf + Pitch ); - font ++; - } + VT_SetMode( VIDEO_BUFFMT_TEXT ); } - // 32-bpp colour (nice and easy) - else if( Depth == 32 ) + else { - Uint32 *buf = Buffer; - - font = VT_Font_GetChar(Codepoint); - - for(y = 0; y < FONT_HEIGHT; y ++) - { - for(x = 0; x < FONT_WIDTH; x ++) - { - if(*font & (1 << (FONT_WIDTH-x-1))) - buf[x] = FGC; - else - buf[x] = BGC; - } - buf = (Uint32*)( (tVAddr)buf + Pitch ); - font ++; - } + // Update the cursor image + if(gpVT_CurTerm->VideoCursor) + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, gpVT_CurTerm->VideoCursor); + VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER ); } -} - -/** - * \fn Uint32 VT_Colour12to24(Uint16 Col12) - * \brief Converts a 12-bit colour into 24 bits - */ -Uint32 VT_Colour12to24(Uint16 Col12) -{ - Uint32 ret; - int tmp; - tmp = Col12 & 0xF; - ret = (tmp << 0) | (tmp << 4); - tmp = (Col12 & 0xF0) >> 4; - ret |= (tmp << 8) | (tmp << 12); - tmp = (Col12 & 0xF00) >> 8; - ret |= (tmp << 16) | (tmp << 20); - return ret; -} -/** - * \brief Converts a 12-bit colour into 15 bits - */ -Uint16 VT_Colour12to15(Uint16 Col12) -{ - Uint32 ret; - int tmp; - tmp = Col12 & 0xF; - ret = (tmp << 1) | (tmp & 1); - tmp = (Col12 & 0xF0) >> 4; - ret |= ( (tmp << 1) | (tmp & 1) ) << 5; - tmp = (Col12 & 0xF00) >> 8; - ret |= ( (tmp << 1) | (tmp & 1) ) << 10; - return ret; -} - -/** - * \brief Converts a 12-bit colour into any other depth - * \param Col12 12-bit source colour - * \param Depth Desired bit deptj - * \note Green then blue get the extra avaliable bits (16:5-6-5, 14:4-5-5) - */ -Uint32 VT_Colour12toN(Uint16 Col12, int Depth) -{ - Uint32 ret; - Uint32 r, g, b; - int rSize, gSize, bSize; - - // Fast returns - if( Depth == 24 ) return VT_Colour12to24(Col12); - if( Depth == 15 ) return VT_Colour12to15(Col12); - // - 32 is a special case, it's usually 24-bit colour with an unused byte - if( Depth == 32 ) return VT_Colour12to24(Col12); - - // Bounds checks - if( Depth < 8 ) return 0; - if( Depth > 32 ) return 0; - - r = Col12 & 0xF; - g = (Col12 & 0xF0) >> 4; - b = (Col12 & 0xF00) >> 8; - - rSize = gSize = bSize = Depth / 3; - if( rSize + gSize + bSize < Depth ) // Depth % 3 == 1 - gSize ++; - if( rSize + gSize + bSize < Depth ) // Depth % 3 == 2 - bSize ++; - - // Expand - r <<= rSize - 4; g <<= gSize - 4; b <<= bSize - 4; - // Fill with the lowest bit - if( Col12 & 0x001 ) r |= (1 << (rSize - 4)) - 1; - if( Col12 & 0x010 ) r |= (1 << (gSize - 4)) - 1; - if( Col12 & 0x100 ) r |= (1 << (bSize - 4)) - 1; - - // Create output - ret = r; - ret |= g << rSize; - ret |= b << (rSize + gSize); - return ret; -} - -/** - * \fn Uint8 *VT_Font_GetChar(Uint32 Codepoint) - * \brief Gets an index into the font array given a Unicode Codepoint - * \note See http://en.wikipedia.org/wiki/CP437 - */ -Uint8 *VT_Font_GetChar(Uint32 Codepoint) -{ - int index = 0; - if(Codepoint < 128) - return &VTermFont[Codepoint*FONT_HEIGHT]; - switch(Codepoint) + if(gpVT_CurTerm->Buffer) { - case 0xC7: index = 128; break; // Ç - case 0xFC: index = 129; break; // ü - case 0xE9: index = 130; break; // é - case 0xE2: index = 131; break; // â - case 0xE4: index = 132; break; // ä - case 0xE0: index = 133; break; // à - case 0xE5: index = 134; break; // å - case 0xE7: index = 135; break; // ç - case 0xEA: index = 136; break; // ê - case 0xEB: index = 137; break; // ë - case 0xE8: index = 138; break; // è - case 0xEF: index = 139; break; // ï - case 0xEE: index = 140; break; // î - case 0xEC: index = 141; break; // ì - case 0xC4: index = 142; break; // Ä - case 0xC5: index = 143; break; // Å + // TODO: Handle non equal sized + VFS_WriteAt( + giVT_OutputDevHandle, + 0, + gpVT_CurTerm->Width*gpVT_CurTerm->Height*sizeof(Uint32), + gpVT_CurTerm->Buffer + ); } - return &VTermFont[index*FONT_HEIGHT]; + VT_int_UpdateCursor(gpVT_CurTerm, 1); + // Update the screen + VT_int_UpdateScreen(gpVT_CurTerm, 1); } - -EXPORTAS(&giVT_CharWidth, giVT_CharWidth); -EXPORTAS(&giVT_CharHeight, giVT_CharHeight); -EXPORT(VT_Font_Render); -EXPORT(VT_Colour12to24);