This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
MadBudderKing's profile picture

OS windows and Multitasking

Started by MadBudderKing, 03 May 2014 - 09:47 PM
MadBudderKing #1
Posted 03 May 2014 - 11:47 PM
Hi,

Im a lot more experienced with lua now, and im creating my own OS now.
The thing I want to know is how to create windows that run programs, and mostly how to multitask programs, like a windowed multi-tasking OS. :P/>
A small example and explanation would be fine

Thanks - MadBudder
Lyqyd #2
Posted 04 May 2014 - 12:14 AM
This is not something that can be demonstrated with "a small example and explanation", just so you know. This is a relatively complex thing to do, as far as ComputerCraft is concerned.
Zacklogan #3
Posted 04 May 2014 - 01:18 AM
Hi. What I would recommend is to is watch these videos, they are very indepth and would be a good place to start: Building a UI / OS.

Hope this helps!
oeed #4
Posted 04 May 2014 - 02:11 AM
Hi. What I would recommend is to is watch these videos, they are very indepth and would be a good place to start: Building a UI / OS.

Hope this helps!

They're pretty good for getting the concept of how GUI work in CC, but it's not the best. Once you've watched those take a look at some of the OSs that use windowing, CraftBang, OneOS and LyqydOS (I'd recommend you look at them in that order, ranked by easiness to understand)
MadBudderKing #5
Posted 04 May 2014 - 04:00 AM
Hi. What I would recommend is to is watch these videos, they are very indepth and would be a good place to start: Building a UI / OS.

Hope this helps!

I've watched all of those before, :)/>
But thanks anyways!

Hi. What I would recommend is to is watch these videos, they are very indepth and would be a good place to start: Building a UI / OS.

Hope this helps!

They're pretty good for getting the concept of how GUI work in CC, but it's not the best. Once you've watched those take a look at some of the OSs that use windowing, CraftBang, OneOS and LyqydOS (I'd recommend you look at them in that order, ranked by easiness to understand)

I was looking at craftbang, and it seems like theres a function that over rides the term API to suit it needs to put everything in the right position and everything, but I dont exactly understand 'how it does over rides the term API'.
OczkoSX #6
Posted 04 May 2014 - 08:29 AM
If you want to run multiple functions in one time, you can use parallel API
oeed #7
Posted 04 May 2014 - 08:35 AM
I was looking at craftbang, and it seems like theres a function that over rides the term API to suit it needs to put everything in the right position and everything, but I dont exactly understand 'how it does over rides the term API'.

What it does, as does OneOS, although not quite to the same extent as OneOS which completely sandboxes everything, is it runs each program in it's own environment. This means that you can set the term API for each program to be your custom one. Take a look at setfenv, or the code I use to do this in OneOS. (the term API overriding is in TermRedirect in the same folder)
viluon #8
Posted 04 May 2014 - 09:58 AM
It's definitely good to learn from code of OSes here at the forums (as oeed mentioned). However, I don't recommend you to start your own project if you don't understand multitasking. Start with something less complicated, multitasking is the main part of OS's kernel and asking for the code would sound like copy paste (for me). Have a look on how others do it, then try yourself, then ask if you don't understand.
oeed #9
Posted 04 May 2014 - 10:06 AM
It's definitely good to learn from code of OSes here at the forums (as oeed mentioned). However, I don't recommend you to start your own project if you don't understand multitasking. Start with something less complicated, multitasking is the main part of OS's kernel and asking for the code would sound like copy paste (for me). Have a look on how others do it, then try yourself, then ask if you don't understand.

Yea, there's no problem with looking at peoples code and learning from it.

I used the NDF-Jay tutorials to learn how CC OSs worked before making PearOS, then I used CraftBang to learn how to do shell based multitasking.
MadBudderKing #10
Posted 04 May 2014 - 02:20 PM
I was looking at craftbang, and it seems like theres a function that over rides the term API to suit it needs to put everything in the right position and everything, but I dont exactly understand 'how it does over rides the term API'.

What it does, as does OneOS, although not quite to the same extent as OneOS which completely sandboxes everything, is it runs each program in it's own environment. This means that you can set the term API for each program to be your custom one. Take a look at setfenv, or the code I use to do this in OneOS. (the term API overriding is in TermRedirect in the same folder)

Funny enough, I was just looking at this, but ill try it out. :)/>
MadBudderKing #11
Posted 04 May 2014 - 03:27 PM

local buffer =
{
setCursorPos = function(x, y)
term.native.setCursorPos(x+1, y+1)
end;
write = function(text)
term.native.write(text)
end
}
setmetatable(buffer, {__index = _G})
setfenv(1, buffer)
term.setCursorPos(1,1)
term.write("Hii!!")

Ive tried this, but it just prints at 1,1. As its supposed to at 2,2. I might not be getting something, anything Im doing wrong here?
MKlegoman357 #12
Posted 04 May 2014 - 03:35 PM
You are defining global 'setCursorPos' and 'write' functions, not 'term.setCursorPos' and 'term.write'. This might work (not tested):


local env = setmetatable({
  term = setmetatable({
    setCursorPos = function (x, y)
      _G.term.native.setCursorPos(x + 1, y + 1)
    end
  }, {__index = _G.term.native})
}, {__index = _G})

setfenv(1, env)
term.setCursorPos(1,1)
term.write("Hii!!")

Don't forget that in CC 1.6 and above 'term.native' was changed from a table to a function.
MadBudderKing #13
Posted 04 May 2014 - 03:40 PM
You are defining global 'setCursorPos' and 'write' functions, not 'term.setCursorPos' and 'term.write'. This might work (not tested):


local env = setmetatable({
  term = setmetatable({
	setCursorPos = function (x, y)
	  _G.term.native.setCursorPos(x + 1, y + 1)
	end
  }, {__index = _G.term.native})
}, {__index = _G})

setfenv(1, env)
term.setCursorPos(1,1)
term.write("Hii!!")

Don't forget that in CC 1.6 and above 'term.native' was changed from a table to a function.

Ya, It errors.
Line 4, attempt to index ? (a function value)
Edited on 04 May 2014 - 01:40 PM
MKlegoman357 #14
Posted 04 May 2014 - 03:59 PM
Ya, It errors.
Line 4, attempt to index ? (a function value)

Don't forget that in CC 1.6 and above 'term.native' was changed from a table to a function.

Here's a fixed example (for CC 1.6+):


local env = setmetatable({
  term = setmetatable({
    setCursorPos = function (x, y)
      _G.term.setCursorPos(x + 1, y + 1)
    end
  }, {__index = _G.term})
}, {__index = _G})

local function func ()
  term.setCursorPos(1, 1)
  term.write("Hii!!")
end

setfenv(func, env)

func()
Edited on 04 May 2014 - 02:00 PM
MadBudderKing #15
Posted 04 May 2014 - 04:12 PM
Thanks, it works. Now, what If I want to run it on another program?
Running shell.run after the setfenv errors; Line 11 (Line w/ the shell.run on it), attempt to index ? (a nil value)
CometWolf #16
Posted 04 May 2014 - 04:28 PM
Shell is not indexed in _G by default. So unless you put it in there, you won't be able to acess it through the index meta to _G. I would suggest putting it in the new environment.
MadBudderKing #17
Posted 04 May 2014 - 04:40 PM
I might get you entirly, but something like this?

local env = setmetatable({
  term = setmetatable({
    setCursorPos = function (x, y)
	  _G.term.setCursorPos(x + 1, y + 1)
    end
  }, {__index = _G.term}),
  shell = setmetatable({
    run = function (prg)
	  shell.run(prg)
    end
  }, {__index = _G.shell})
}, {__index = _G})
function func()
shell.run("firewolf")
end
setfenv(func, env)
func()
When ran, firewolf will stay at 1,1
CometWolf #18
Posted 04 May 2014 - 05:55 PM
I was thinkin more along the lines of just sticking the shell table in there, instead of putting the run function in there. Also as i noted earlier, there is no _G.shell. Anyways, i believe shell.run sets the environment to the environment of the shell, not the environment of the function calling it. Therefore, you're overrides won't work with shell.run unless you replace the global functions. You'll have to use os.run instead.
MadBudderKing #19
Posted 04 May 2014 - 06:17 PM
Yay, it works!
Im pretty much using this code:

local env = setmetatable({
  term = setmetatable({
	setCursorPos = function (x, y)
	  _G.term.setCursorPos(x + 1, y + 1)
	end
  }, {__index = _G.term}),
}, {__index = _G})
function func()
os.run(env, "ptest")
end
setfenv(func, env)
func()
ptest just has a simple term.setCursorPos(2,2) and write("hi") in it.

Now, to implement all the other drawing functions (paintutils.drawLine, drawPixel image, etc)

Oh, and while im doing that, what about multitasking?
No-one talked about that, really in here yet
Edited on 04 May 2014 - 04:18 PM
CometWolf #20
Posted 04 May 2014 - 06:28 PM

function func()
os.run(env, "ptest")
end
setfenv(func, env)
func()
This, is pointless. os.run sets the environment of the called program to the first argument anyways, so you might aswell just do just

os.run(env, "ptest")
MadBudderKing #21
Posted 04 May 2014 - 06:41 PM
Ive been wondering a little about that to, but thanks anyways to answer a question I never even asked to you. xD
Edited on 04 May 2014 - 04:41 PM
MKlegoman357 #22
Posted 04 May 2014 - 06:59 PM
Now, to implement all the other drawing functions (paintutils.drawLine, drawPixel image, etc)

You don't actually need to re-implement all functions that use term API. You can either set their environment to the new sandboxed one or whenever you resume a program's coroutine (when you will implement 'multitasking') you can use term.redirect to redirect to the sandboxed (specifically for that program) term API (this is how Lyqyd OS manages displays).

Oh, and while im doing that, what about multitasking?
No-one talked about that, really in here yet

To make a multitasking system which would work with CC programs you first have to understand how CC events and coroutines work Lua side. (I will assume you already know how coroutines work)

To manage events CC uses coroutines. Whenever you run a program a new coroutine is created specifically for that program. Then that coroutine is resumed and CC waits for it to either yield or stop. When a coroutine yields (calling coroutine.yield, os.pullEventRaw or os.pullEvent) it may return some values. In CC it either returns an event filter or doesn't return anything (when you don't specify an event filter). If a filter was returned by a program CC waits for that specific event to fire, and when that event fires CC resumes the program passing that event and all parameters that came with it. If there was no event filter specified then CC resumes the program passing the first event it gets. I suggest you to look at how parallel API manages coroutines.

Note: 'terminate' event fires regardless of the event filter, be aware of that.
MadBudderKing #23
Posted 04 May 2014 - 07:17 PM
Now, to implement all the other drawing functions (paintutils.drawLine, drawPixel image, etc)

You don't actually need to re-implement all functions that use term API. You can either set their environment to the new sandboxed one or whenever you resume a program's coroutine (when you will implement 'multitasking') you can use term.redirect to redirect to the sandboxed (specifically for that program) term API (this is how Lyqyd OS manages displays).
Ya, I noticed :)/>

Also, lets say I give a program a designated area, like a 15*15 area. The program being ran in there wants to draw a image bigger then that.
The image is drawn outside the area, is there any special way to fix hat instead of drawing over it?
CometWolf #24
Posted 04 May 2014 - 07:32 PM
Use a screen buffer, and simply ignore any changes made to the area outside the window.
Bomb Bloke #25
Posted 04 May 2014 - 11:31 PM
For eg, a window.