+ int *iData = Data;
+ int ret;
+ 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;
+ case DRV_IOCTL_IDENT:
+ memcpy(Data, "VT\0\0", 4);
+ LEAVE('i', 0);
+ return 0;
+ case DRV_IOCTL_VERSION:
+ LEAVE('x', VERSION);
+ return VERSION;
+ case DRV_IOCTL_LOOKUP:
+ LEAVE('i', 0);
+ return 0;
+
+ // Get/Set the mode (and apply any changes)
+ 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
+ || term->NewWidth
+ || term->NewHeight)
+ {
+ // Adjust for text mode
+ if( *iData == TERM_MODE_TEXT ) {
+ term->NewHeight *= giVT_CharHeight;
+ term->NewWidth *= giVT_CharWidth;
+ }
+ // Fill unchanged dimensions
+ if(term->NewHeight == 0) term->NewHeight = term->Height;
+ if(term->NewWidth == 0) term->NewWidth = term->Width;
+ // Set new mode
+ VT_int_ChangeMode(term, *iData, term->NewWidth, term->NewHeight);
+ // Clear unapplied dimensions
+ term->NewWidth = 0;
+ term->NewHeight = 0;
+ }
+
+ // Update the screen dimensions
+ if(Node->Inode == giVT_CurrentTerminal)
+ VT_SetTerminal( giVT_CurrentTerminal );
+ }
+ LEAVE('i', term->Mode);
+ return term->Mode;
+
+ // Get/set the terminal width
+ case TERM_IOCTL_WIDTH:
+ if(Data != NULL) {
+ if( CheckMem(Data, sizeof(int)) == 0 ) {
+ LEAVE('i', -1);
+ return -1;
+ }
+ term->NewWidth = *iData;
+ }
+ if( term->NewWidth )
+ ret = term->NewWidth;
+ else if( term->Mode == TERM_MODE_TEXT )
+ ret = term->TextWidth;
+ else
+ ret = term->Width;
+ LEAVE('i', ret);
+ return ret;
+
+ // Get/set the terminal height
+ case TERM_IOCTL_HEIGHT:
+ if(Data != NULL) {
+ if( CheckMem(Data, sizeof(int)) == 0 ) {
+ LEAVE('i', -1);
+ return -1;
+ }
+ term->NewHeight = *iData;
+ }
+ if( term->NewHeight )
+ ret = term->NewHeight;
+ else if( term->Mode == TERM_MODE_TEXT )
+ ret = term->TextHeight;
+ else
+ ret = term->Height;
+ LEAVE('i', ret);
+ return ret;
+
+ 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;
+
+ case TERM_IOCTL_GETCURSOR:
+ ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos;
+ LEAVE('i', ret);
+ return ret;
+ }
+ 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;
+ 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
+ VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER );
+
+ // Update the screen
+ VT_int_UpdateScreen( &gVT_Terminals[ ID ], 1 );