function preReq () local col=term.isColour() local requiresPocket=false if requiresPocket then if col and pocket then return true end else if col then return true end end return false end ------------------------------------------------------------------------- --diagnostic stuff oldOsVersion=os.version os.version = function() return oldOsVersion().." & X project" end ------------------------------------------------------------------------ function multishells() -- Setup process switching local parentTerm = term.current() local w,h = parentTerm.getSize() local tProcesses = {} local nCurrentProcess = nil local nRunningProcess = nil local multishell = {} local nLastProcess = 0 --------------------------------------------------------------------- ---Diagnostic stuff function freeSpace (space) for i=1,space,1 do write(" ") end end function multishell.printProcesses() multishell.printTable(tProcesses,1,"window","terminal") end function multishell.printStatus(ID) print (coroutine.status(tProcesses[ID].co)) end function multishell.printTable (tab,dep,...) local filter={...} if dep==nil then dep=1 end print ("") freeSpace(dep-1) print ("{") for i,v in pairs (tab) do local filMatch=false for j,w in pairs (filter) do if w==i then filMatch=true end end if not filMatch then freeSpace(dep) write (i.." ") if type(v) =="table" then dep=dep+1 multishell.printTable(v,dep,unpack(filter)) dep=dep-1 else print (v) end local curX,curY = term.getCursorPos() local sizeX,sizeY = term.getSize() if curY == sizeY then os.pullEvent("key") end end end freeSpace(dep-1) print ("}") end ---------------------------------------------------------------------- local function selectProcess( n ) if nCurrentProcess ~= n then if tProcesses[n] ~= nil then if nCurrentProcess then local tOldProcess = tProcesses[ nCurrentProcess ] tOldProcess.window.setVisible( false ) end nCurrentProcess = n if nCurrentProcess then local tNewProcess = tProcesses[ nCurrentProcess ] tNewProcess.window.setVisible( true ) tNewProcess.bInteracted = true end end end end local function setProcessTitle( n, sTitle ) tProcesses[ n ].sTitle = sTitle end function resumeProcess( nProcess, sEvent, ... ) if multishell.isValid(nProcess) then local tProcess = tProcesses[ nProcess ] --local sFilter = tProcess.sFilter -- if sFilter == nil or sFilter == sEvent or sEvent == "terminate" then local nPreviousProcess = nRunningProcess nRunningProcess = nProcess term.redirect( tProcess.terminal ) local ok, result = coroutine.resume( tProcess.co, sEvent, ... ) tProcess.terminal = term.current() if ok then tProcess.sFilter = result else printError( result ) end nRunningProcess = nPreviousProcess --end -- else -- print ("you failed") -- end else print ("you failed") end end function multishell.killProcess (ID) if ID~=1 and multishell.isValid(ID) then resumeProcess( ID, "terminate") end end local function launchProcess( tProgramEnv, sProgramPath, ... ) if not tProgramEnv.multishell then tProgramEnv.multishell=multishell end if not tProgramEnv.shell then tProgramEnv.shell=shell end local tProgramArgs = { ... } nLastProcess = nLastProcess + 1 local nProcess = nLastProcess local tProcess = {} tProcess.sTitle = fs.getName( sProgramPath ) tProcess.window = window.create( parentTerm, 1, 1, w, h, false ) tProcess.co = coroutine.create( function() --if nLastProcess~=1 then -- parallel.waitForAny( -- function() os.run( tProgramEnv, sProgramPath, unpack( tProgramArgs ) ) end, -- function() endProcess(nProcess) end -- ) --else os.run( tProgramEnv, sProgramPath, unpack( tProgramArgs ) ) --end if not tProcess.bInteracted then term.setCursorBlink( false ) print( "Press any key to continue" ) os.pullEvent( "char" ) end if nCurrentProcess==nProcess then selectProcess (1) end os.queueEvent("check_Processes") end ) -- tProcess.sFilter = nil tProcess.terminal = tProcess.window tProcess.bInteracted = false tProcesses[ nProcess ] = tProcess resumeProcess( nProcess ) return nProcess end local function cullProcess( nProcess ) --if nProcess==nil then -- return --end local tProcess = tProcesses[ nProcess ] if tProcess==nil then return end --printTable(tProcess) --local cor = tProcess.co --print (cor) --print (coroutine.status(cor)) -- --multishell.printTable(tProcess,1,"window","terminal") --print (coroutine.status(tProcess.co)) --if tProcesses[nProcess].active==false then if coroutine.status( tProcess.co ) == "dead" then if nCurrentProcess==nProcess then selectProcess (1) end tProcesses[nProcess] = nil end end local function cullProcesses() --local culled = false --for n=multishell.getCount(),1,-1 do --culled = culled or cullProcess( n ) --end --return culled for i=1, nLastProcess do if multishell.isValid(i) then cullProcess( i ) end end end function multishell.checkProcesses() cullProcesses() end function multishell.isValid(id) if tProcesses[id]~=nil then return true end return false end function multishell.getProcesses() local procArray = {} local index=1 for id,proc in pairs(tProcesses) do procArray[index]={} procArray[index].id=id procArray[index].title=proc.sTitle index=index+1 end return procArray end function multishell.getFocus() return nCurrentProcess end function multishell.setFocus( n ) if multishell.isValid(n) then selectProcess( n ) return true end return false end function multishell.getLastID() return nLastProcess end function multishell.getTitle( n ) if multishell.isValid(n) then return tProcesses[n].sTitle end return nil end function multishell.setTitle( n, sTitle ) if multishell.isValid(n) then setProcessTitle( n, sTitle ) end end function multishell.getCurrent() return nRunningProcess end function multishell.launch( tProgramEnv, sProgramPath, ... ) local previousTerm = term.current() local nResult = launchProcess( tProgramEnv, sProgramPath, ... ) term.redirect( previousTerm ) return nResult end function multishell.getCount() local count = 0 for id, proc in pairs(tProcesses) do count = count + 1 end return count end local jump={false,false} -- Begin parentTerm.clear() selectProcess( launchProcess( { ["shell"] = shell, ["multishell"] = multishell }, "/rom/programs/shell" ) ) -- Run processes while multishell.isValid(1) do -- Get the event if jump[1] and jump[2] then selectProcess(1) --print ("jumped") end local tEventData = { os.pullEventRaw() } local sEvent = tEventData[1] if sEvent == "check_Processes" then cullProcesses() elseif sEvent == "terminate" then if nCurrentProcess ~= 1 then resumeProcess( nCurrentProcess, unpack( tEventData ) ) cullProcesses() end elseif sEvent == "tabChangeDisable" then jump[1]=false jump[2]=false elseif sEvent == "key" then if jump[1]==false and tEventData[2]==29 then jump[1]=true os.queueEvent("tabChangeDisable") elseif jump[2]==false and tEventData[2]==56 then jump[2]=true os.queueEvent("tabChangeDisable") end resumeProcess( nCurrentProcess, unpack( tEventData ) ) elseif sEvent == "char" or sEvent == "paste" then -- Keyboard event -- Passthrough to current process resumeProcess( nCurrentProcess, unpack( tEventData ) ) elseif sEvent == "mouse_click" or sEvent == "mouse_drag" or sEvent == "mouse_scroll" then -- Click event local button, x, y = tEventData[2], tEventData[3], tEventData[4] -- Passthrough to current process resumeProcess( nCurrentProcess, sEvent, button, x, y ) elseif sEvent=="send_event" then if multishell.isValid(tEventData[2]) then local target = tEventData[2] tEventData[2] = nRunningProcess resumeProcess( target, unpack( tEventData ) ) end else -- Other event -- Passthrough to all processes local nLimit = nLastProcess -- Storing this ensures any new things spawned don't get the event for n=1,nLimit do if multishell.isValid(n) then resumeProcess( n, unpack( tEventData ) ) end end end end -- Shutdown term.redirect( parentTerm ) end ----------------------------------------------------------------------------------- local function run(mainFunc, errFunc) local oldOsShutdown, oldCoroutineStatus = os.shutdown, coroutine.status if type(mainFunc) ~= "function" then error("Nothing to run", 2) end local function clearScreen() term.redirect(type(term.native) == "function" and term.native() or term.native) term.setBackgroundColour(colours.black) term.setTextColour(colours.white) term.setCursorPos(1, 1) term.setCursorBlink(false) term.clear() end local function coroutineStatusOverride(...) return "dead" end local function osShutdownOverride() clearScreen() rednet.close() os.unloadAPI("rednet") os.loadAPI("/rom/apis/rednet") rawset(os, "shutdown", oldOsShutdown) rawset(coroutine, "status", oldCoroutineStatus) local ok, err = pcall(mainFunc) if not ok then clearScreen() pcall( function() if type(errFunc) == "function" then errFunc(err) else printError(err) print("Press any key to continue") os.pullEvent("key") end end ) end os.sleep(2) os.shutdown() end rawset(os, "shutdown", osShutdownOverride) rawset(coroutine, "status", coroutineStatusOverride) end if preReq() then run(multishells) else print("You need advanced pocket computer to run X project") end