An ioL console can contain other ioL consoles. Your program can set aside an area of its screen, and run a completely separate program inside it. That program doesn't need to know it's inside another one: it prints its output and reads its input exactly as usual.
This is how you can build a program made of several smaller ones: a settings screen where each tab is its own program, a dashboard of independent panels, or a launcher that runs other programs in a window.
A clientFrame tag is an area of the screen, like a box, that another program's console can be connected to:
<left:clientFrame width=300 height=150 border=1>
When the frame is created, the console gives it a unique key, and puts it in the frame's primary field. To start a program inside the frame, your program does three things:
<putLn left>;In Python, the subprocess module starts other programs:
import subprocess
def start_in_frame(frame, command):
print('<putLn ' + frame + '>') # ask the console for the frame's key
key = input()
return subprocess.Popen(['iol', '-q', '-k', key, '--'] + command)
start_in_frame('left', ['python3', 'clock.py'])
-q stops iol from printing its welcome message. The -- marks the end of the options for iol, so that options meant for the other program (like Python's -c) aren't mistaken for iol's own. Always include it.
Each key can only be used once. When a program in a frame finishes, the frame is given a new key, so you can start another program in the same frame.
The program inside a frame runs independently. Its input and output go to its own console, not yours. But a frame does tell you a few things about it:
| Field | Tells you |
|---|---|
| title | the hosted program's title (its console.title) |
| connected | true while a program is running in the frame |
| onConnect | code to carry out when a program connects to the frame |
| onDisconnect | code to carry out when it finishes |
| onTitle | code to carry out when its title changes |
You can read these fields, but not change them: they belong to the hosted program.
First, a tiny program to host. It sets its title, says hello, and has a button to close it. There's nothing special about it at all; you could run it on its own too:
import sys
name = sys.argv[1]
print('<console.title {' + name + '}>')
print('<span size=16,pt bold=true {Hello from ' + name + '}></p>')
print('<button {Close me} onClick=<putLn {/quit}>>')
while input() != '/quit':
pass
Save it as child.py. Now the host program, which runs two copies of it in two frames, and shows each one's title underneath:
import subprocess
def start_in_frame(frame, command):
print('<putLn ' + frame + '>')
key = input()
return subprocess.Popen(['iol', '-q', '-k', key, '--'] + command)
print('''
<console.title {Host}>
<span bold=true {Two programs, side by side:}></n>
<left:clientFrame width=300 height=150 border=1 onTitle=<leftTitle left.title>
onDisconnect=<putLn {/left-finished}>>
<right:clientFrame width=300 height=150 border=1 onTitle=<rightTitle right.title>></n>
<leftTitle:span {}> | <rightTitle:span {}>
''')
start_in_frame('left', ['python3', 'child.py', 'Alpha'])
start_in_frame('right', ['python3', 'child.py', 'Beta'])
while True:
line = input()
if line == '/left-finished':
print('<leftTitle {(closed)}>')
Two programs, side by side:Click "Close me" in the left frame, and that program finishes: its frame empties, and the host is told.
A bigger example of the same idea is a program with tabs, where each tab shows a different program in its own frame, and only one frame is visible at a time. The program sets up one frame per tab, starts a program in each, and shows or hides the frames (with their visible field) when a tab is clicked. Each tab can be labelled with its program's title, using onTitle.
Programs you start are your program's responsibility. When your program finishes, make sure it also tells the programs it started to finish (or ends them), so they don't carry on running unseen.
Starting other programs is a good moment to look at the rest of the iol command's options:
| Option | Does |
|---|---|
| -q | quiet: don't print the welcome message |
| -k key | run the program inside the clientFrame with this key |
| -t title | set the console's starting title |
| -i file | set the console's starting icon, from a PNG file |
| -r text | pass some text to the program, which it can read as console.rescom |
| - | instead of a command: you are the program (see the chapter on printing text) |
| -- | everything after this is the command to run |
-r is a way to tell a program what to do when it starts, separately from its own command-line arguments. What the text means is up to the program: a file to open, perhaps, or which screen to show first.