summaryrefslogtreecommitdiffstats
path: root/Demo/sgi
diff options
context:
space:
mode:
Diffstat (limited to 'Demo/sgi')
-rw-r--r--Demo/sgi/audio/README8
-rwxr-xr-xDemo/sgi/audio/play.py75
-rw-r--r--Demo/sgi/audio_stdwin/README19
-rwxr-xr-xDemo/sgi/audio_stdwin/jukebox.py321
-rwxr-xr-xDemo/sgi/audio_stdwin/rec.py268
-rwxr-xr-xDemo/sgi/audio_stdwin/vumeter.py35
-rwxr-xr-xDemo/sgi/flp/test_cb.fd75
-rwxr-xr-xDemo/sgi/flp/test_cb.py62
-rwxr-xr-xDemo/sgi/flp/test_nocb.fd75
-rwxr-xr-xDemo/sgi/flp/test_nocb.py45
10 files changed, 983 insertions, 0 deletions
diff --git a/Demo/sgi/audio/README b/Demo/sgi/audio/README
new file mode 100644
index 0000000..02a3701
--- /dev/null
+++ b/Demo/sgi/audio/README
@@ -0,0 +1,8 @@
+Programs that demonstrate the use of the audio device on the SGI 4D/25.
+These require the built-in module 'audio'.
+
+XXX This hardware is already obsolete; see ../al for examples of audio
+XXX on the Indigo and 4D/35.
+
+play Read a sound sample from a file and play it through the
+ speaker. Options to set volume, sampling rate etc.
diff --git a/Demo/sgi/audio/play.py b/Demo/sgi/audio/play.py
new file mode 100755
index 0000000..adc7625
--- /dev/null
+++ b/Demo/sgi/audio/play.py
@@ -0,0 +1,75 @@
+#! /usr/local/python
+
+import sys
+import audio
+
+import string
+import getopt
+import auds
+
+debug = []
+
+DEF_RATE = 3
+
+def main():
+ #
+ gain = 100
+ rate = 0
+ starter = audio.write
+ stopper = 0
+ #
+ optlist, args = getopt.getopt(sys.argv[1:], 'adg:r:')
+ #
+ for optname, optarg in optlist:
+ if 0:
+ pass
+ elif optname == '-d':
+ debug.append(1)
+ elif optname == '-g':
+ gain = string.atoi(optarg)
+ if not (0 < gain < 256):
+ raise optarg.error, '-g gain out of range'
+ elif optname == '-r':
+ rate = string.atoi(optarg)
+ if not (1 <= rate <= 3):
+ raise optarg.error, '-r rate out of range'
+ elif optname == '-a':
+ starter = audio.start_playing
+ stopper = audio.wait_playing
+ #
+ audio.setoutgain(gain)
+ audio.setrate(rate)
+ #
+ if not args:
+ play(starter, rate, auds.loadfp(sys.stdin))
+ else:
+ real_stopper = 0
+ for file in args:
+ if real_stopper:
+ real_stopper()
+ play(starter, rate, auds.load(file))
+ real_stopper = stopper
+
+def play(starter, rate, data):
+ magic = data[:4]
+ if magic == '0008':
+ mrate = 3
+ elif magic == '0016':
+ mrate = 2
+ elif magic == '0032':
+ mrate = 1
+ else:
+ mrate = 0
+ if mrate:
+ data = data[4:]
+ else:
+ mrate = DEF_RATE
+ if not rate: rate = mrate
+ audio.setrate(rate)
+ starter(data)
+
+try:
+ main()
+finally:
+ audio.setoutgain(0)
+ audio.done()
diff --git a/Demo/sgi/audio_stdwin/README b/Demo/sgi/audio_stdwin/README
new file mode 100644
index 0000000..6d96fe1
--- /dev/null
+++ b/Demo/sgi/audio_stdwin/README
@@ -0,0 +1,19 @@
+Three programs that provide a user interface based upon STDWIN to the
+audio device of the SGI 4D/25. These scripts also demonstrate the power
+of a set of window interface classes implemented in Python that simplify
+the construction of all sorts of buttons, etc.
+
+XXX This hardware is already obsolete; see ../al for examples of audio
+XXX on the Indigo and 4D/35.
+
+jukebox Browses a directory full of sound samples and lets you
+ play selected ones. (Probably not fully functional, it
+ requires a conversion program.)
+
+rec A tape recorder that lets you record a sound sample,
+ play it back, and save it to a file. Various options to
+ set sampling rate, volume etc. When idle it doubles
+ as a VU meter.
+
+vumeter A VU meter that displays a history of the volume of
+ sound recently sampled from the microphone.
diff --git a/Demo/sgi/audio_stdwin/jukebox.py b/Demo/sgi/audio_stdwin/jukebox.py
new file mode 100755
index 0000000..b223992
--- /dev/null
+++ b/Demo/sgi/audio_stdwin/jukebox.py
@@ -0,0 +1,321 @@
+#! /usr/local/python
+
+# JUKEBOX: browse directories full of sampled sound files.
+#
+# One or more "list windows" display the files and subdirectories of
+# the arguments. Double-clicking on a subdirectory opens a new window
+# displaying its contents (and so on recursively). Double clicking
+# on a file plays it as a sound file (assuming it is one).
+#
+# Playing is asynchronous: the application keeps listening to events
+# while the sample is playing, so you can change the volume (gain)
+# during playing, cancel playing or start a new sample right away.
+#
+# The control window displays the current output gain and a primitive
+# "stop button" to cancel the current play request.
+#
+# Sound files must currently be in Dik Winter's compressed Mac format.
+# Since decompression is costly, decompressed samples are saved in
+# /usr/tmp/@j* until the application is left. The files are read
+# afresh each time, though.
+
+import audio
+import sunaudio
+import commands
+import getopt
+import path
+import posix
+import rand
+import stdwin
+from stdwinevents import *
+import string
+import sys
+
+from WindowParent import WindowParent
+from HVSplit import VSplit
+from Buttons import PushButton
+from Sliders import ComplexSlider
+
+# Pathnames
+
+HOME_BIN_SGI = '/ufs/guido/bin/sgi/' # Directory where macsound2sgi lives
+DEF_DB = '/ufs/dik/sounds/Mac/HCOM' # Default directory of sounds
+
+
+# Global variables
+
+class struct: pass # Class to define featureless structures
+
+G = struct() # Holds writable global variables
+
+
+# Main program
+
+def main():
+ G.synchronous = 0 # If set, use synchronous audio.write()
+ G.debug = 0 # If set, print debug messages
+ G.gain = 75 # Output gain
+ G.rate = 3 # Sampling rate
+ G.busy = 0 # Set while asynchronous playing is active
+ G.windows = [] # List of open windows (except control)
+ G.mode = 'mac' # Macintosh mode
+ G.tempprefix = '/usr/tmp/@j' + `rand.rand()` + '-'
+ #
+ optlist, args = getopt.getopt(sys.argv[1:], 'dg:r:sSa')
+ for optname, optarg in optlist:
+ if optname == '-d':
+ G.debug = 1
+ elif optname == '-g':
+ G.gain = string.atoi(optarg)
+ if not (0 < G.gain < 256):
+ raise optarg.error, '-g gain out of range'
+ elif optname == '-r':
+ G.rate = string.atoi(optarg)
+ if not (1 <= G.rate <= 3):
+ raise optarg.error, '-r rate out of range'
+ elif optname == '-s':
+ G.synchronous = 1
+ elif optname == '-S':
+ G.mode = 'sgi'
+ elif optname == '-a':
+ G.mode = 'sun'
+ #
+ if not args:
+ args = [DEF_DB]
+ #
+ G.cw = opencontrolwindow()
+ for dirname in args:
+ G.windows.append(openlistwindow(dirname))
+ #
+ #
+ savegain = audio.getoutgain()
+ try:
+ # Initialize stdaudio
+ audio.setoutgain(0)
+ audio.start_playing('')
+ dummy = audio.wait_playing()
+ audio.setoutgain(0)
+ maineventloop()
+ finally:
+ audio.setoutgain(savegain)
+ audio.done()
+ clearcache()
+
+def maineventloop():
+ mouse_events = WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP
+ while G.windows:
+ type, w, detail = event = stdwin.getevent()
+ if w == G.cw.win:
+ if type == WE_CLOSE:
+ return
+ G.cw.dispatch(event)
+ else:
+ if type == WE_DRAW:
+ w.drawproc(w, detail)
+ elif type in mouse_events:
+ w.mouse(w, type, detail)
+ elif type == WE_CLOSE:
+ w.close(w)
+ del w, event
+ else:
+ if G.debug: print type, w, detail
+
+# Control window -- to set gain and cancel play operations in progress
+
+def opencontrolwindow():
+ cw = WindowParent().create('Jukebox', (0, 0))
+ v = VSplit().create(cw)
+ #
+ gain = ComplexSlider().define(v)
+ gain.setminvalmax(0, G.gain, 255)
+ gain.settexts(' ', ' ')
+ gain.sethook(gain_setval_hook)
+ #
+ stop = PushButton().definetext(v, 'Stop')
+ stop.hook = stop_hook
+ #
+ cw.realize()
+ return cw
+
+def gain_setval_hook(self):
+ G.gain = self.val
+ if G.busy: audio.setoutgain(G.gain)
+
+def stop_hook(self):
+ if G.busy:
+ audio.setoutgain(0)
+ dummy = audio.stop_playing()
+ G.busy = 0
+
+
+# List windows -- to display list of files and subdirectories
+
+def openlistwindow(dirname):
+ list = posix.listdir(dirname)
+ list.sort()
+ i = 0
+ while i < len(list):
+ if list[i] == '.' or list[i] == '..':
+ del list[i]
+ else:
+ i = i+1
+ for i in range(len(list)):
+ name = list[i]
+ if path.isdir(path.join(dirname, name)):
+ list[i] = list[i] + '/'
+ width = maxwidth(list)
+ width = width + stdwin.textwidth(' ') # XXX X11 stdwin bug workaround
+ height = len(list) * stdwin.lineheight()
+ stdwin.setdefwinsize(width, min(height, 500))
+ w = stdwin.open(dirname)
+ stdwin.setdefwinsize(0, 0)
+ w.setdocsize(width, height)
+ w.drawproc = drawlistwindow
+ w.mouse = mouselistwindow
+ w.close = closelistwindow
+ w.dirname = dirname
+ w.list = list
+ w.selected = -1
+ return w
+
+def maxwidth(list):
+ width = 1
+ for name in list:
+ w = stdwin.textwidth(name)
+ if w > width: width = w
+ return width
+
+def drawlistwindow(w, area):
+ d = w.begindrawing()
+ d.erase((0, 0), (1000, 10000))
+ lh = d.lineheight()
+ h, v = 0, 0
+ for name in w.list:
+ d.text((h, v), name)
+ v = v + lh
+ showselection(w, d)
+
+def hideselection(w, d):
+ if w.selected >= 0:
+ invertselection(w, d)
+
+def showselection(w, d):
+ if w.selected >= 0:
+ invertselection(w, d)
+
+def invertselection(w, d):
+ lh = d.lineheight()
+ h1, v1 = p1 = 0, w.selected*lh
+ h2, v2 = p2 = 1000, v1 + lh
+ d.invert(p1, p2)
+
+def mouselistwindow(w, type, detail):
+ (h, v), clicks, button = detail[:3]
+ d = w.begindrawing()
+ lh = d.lineheight()
+ if 0 <= v < lh*len(w.list):
+ i = v / lh
+ else:
+ i = -1
+ if w.selected <> i:
+ hideselection(w, d)
+ w.selected = i
+ showselection(w, d)
+ if type == WE_MOUSE_DOWN and clicks >= 2 and i >= 0:
+ name = path.join(w.dirname, w.list[i])
+ if name[-1:] == '/':
+ if clicks == 2:
+ G.windows.append(openlistwindow(name[:-1]))
+ else:
+ playfile(name)
+
+def closelistwindow(w):
+ remove(G.windows, w)
+
+def remove(list, item):
+ for i in range(len(list)):
+ if list[i] == item:
+ del list[i]
+ break
+
+
+# Playing tools
+
+cache = {}
+
+def clearcache():
+ for x in cache.keys():
+ try:
+ sts = posix.system('rm -f ' + cache[x])
+ if sts:
+ print cmd
+ print 'Exit status', sts
+ except:
+ print cmd
+ print 'Exception?!'
+ del cache[x]
+
+def playfile(name):
+ if G.mode <> 'mac':
+ tempname = name
+ elif cache.has_key(name):
+ tempname = cache[name]
+ else:
+ tempname = G.tempprefix + `rand.rand()`
+ cmd = HOME_BIN_SGI + 'macsound2sgi'
+ cmd = cmd + ' ' + commands.mkarg(name)
+ cmd = cmd + ' >' + tempname
+ if G.debug: print cmd
+ sts = posix.system(cmd)
+ if sts:
+ print cmd
+ print 'Exit status', sts
+ stdwin.fleep()
+ return
+ cache[name] = tempname
+ fp = open(tempname, 'r')
+ try:
+ hdr = sunaudio.gethdr(fp)
+ except sunaudio.error, msg:
+ hdr = ()
+ if hdr:
+ data_size = hdr[0]
+ data = fp.read(data_size)
+ # XXX this doesn't work yet, need to convert from uLAW!!!
+ del fp
+ else:
+ del fp
+ data = readfile(tempname)
+ if G.debug: print len(data), 'bytes read from', tempname
+ if G.busy:
+ G.busy = 0
+ dummy = audio.stop_playing()
+ #
+ # Completely reset the audio device
+ audio.setrate(G.rate)
+ audio.setduration(0)
+ audio.setoutgain(G.gain)
+ #
+ if G.synchronous:
+ audio.write(data)
+ audio.setoutgain(0)
+ else:
+ try:
+ audio.start_playing(data)
+ G.busy = 1
+ except:
+ stdwin.fleep()
+ del data
+
+def readfile(filename):
+ return readfp(open(filename, 'r'))
+
+def readfp(fp):
+ data = ''
+ while 1:
+ buf = fp.read(102400) # Reads most samples in one fell swoop
+ if not buf:
+ return data
+ data = data + buf
+
+main()
diff --git a/Demo/sgi/audio_stdwin/rec.py b/Demo/sgi/audio_stdwin/rec.py
new file mode 100755
index 0000000..0caba89
--- /dev/null
+++ b/Demo/sgi/audio_stdwin/rec.py
@@ -0,0 +1,268 @@
+#! /ufs/guido/bin/sgi/python
+
+import sys
+import audio
+import stdwin
+
+import string
+import getopt
+
+from stdwinevents import *
+from Buttons import *
+from Sliders import *
+#from Soundogram import Soundogram
+from VUMeter import VUMeter
+from WindowParent import WindowParent, MainLoop
+from HVSplit import HSplit, VSplit
+
+class TimeOutToggleButton(ToggleButton):
+ def define(self, parent):
+ self = ToggleButton.define(self, parent)
+ self.parent.need_timer(self)
+ self.timer_hook = 0
+ return self
+ def timer(self):
+ if self.timer_hook:
+ self.timer_hook(self)
+
+K = 1024
+BUFSIZE = 30*8*K
+Rates = [0, 32*K, 16*K, 8*K]
+Magics = ['', '0032', '0016', '0008']
+
+class Struct: pass
+G = Struct()
+
+def main():
+ #
+ # Turn off scroll bars
+ #
+ stdwin.setdefscrollbars(0, 0)
+ #
+ # Set default state
+ #
+ G.gain = 60
+ G.rate = 3
+ G.nomuting = 0
+ G.savefile = '@rec'
+ #
+ # Set default values
+ #
+ G.data = ''
+ G.playing = 0
+ G.recording = 0
+ G.sogram = 0
+ #
+ # Parse options
+ #
+ optlist, args = getopt.getopt(sys.argv[1:], 'mdg:r:')
+ #
+ for optname, optarg in optlist:
+ if 0: # (So all cases start with elif)
+ pass
+ elif optname == '-d':
+ G.debug = 1
+ elif optname == '-g':
+ G.gain = string.atoi(optarg)
+ if not (0 < G.gain < 256):
+ raise optarg.error, '-g gain out of range'
+ elif optname == '-m':
+ G.nomuting = (not G.nomuting)
+ elif optname == '-r':
+ G.rate = string.atoi(optarg)
+ if not (1 <= G.rate <= 3):
+ raise optarg.error, '-r rate out of range'
+ #
+ if args:
+ G.savefile = args[0]
+ #
+ # Initialize the sound package
+ #
+ audio.setoutgain(G.nomuting * G.gain) # Silence the speaker
+ audio.setrate(G.rate)
+ #
+ # Create the WindowParent and VSplit
+ #
+ G.window = WindowParent().create('Recorder', (0, 0))
+ w = G.vsplit = VSplit().create(G.window)
+ #
+ # VU-meter
+ #
+ G.vubtn = VUMeter().define(w)
+ #
+ # Radiobuttons for rates
+ #
+ r1btn = RadioButton().definetext(w, '32 K/sec')
+ r1btn.on_hook = rate_hook
+ r1btn.rate = 1
+ #
+ r2btn = RadioButton().definetext(w, '16 K/sec')
+ r2btn.on_hook = rate_hook
+ r2btn.rate = 2
+ #
+ r3btn = RadioButton().definetext(w, '8 K/sec')
+ r3btn.on_hook = rate_hook
+ r3btn.rate = 3
+ #
+ radios = [r1btn, r2btn, r3btn]
+ r1btn.group = r2btn.group = r3btn.group = radios
+ for r in radios:
+ if r.rate == G.rate: r.select(1)
+ #
+ # Other controls
+ #
+ G.recbtn = TimeOutToggleButton().definetext(w, 'Record')
+ G.recbtn.on_hook = record_on_hook
+ G.recbtn.timer_hook = record_timer_hook
+ G.recbtn.off_hook = record_off_hook
+ #
+ G.mutebtn = CheckButton().definetext(w, 'Mute')
+ G.mutebtn.select(not G.nomuting)
+ G.mutebtn.hook = mute_hook
+ #
+ G.playbtn = TimeOutToggleButton().definetext(w, 'Playback')
+ G.playbtn.on_hook = play_on_hook
+ G.playbtn.timer_hook = play_timer_hook
+ G.playbtn.off_hook = play_off_hook
+ #
+ G.gainbtn = ComplexSlider().define(w)
+ G.gainbtn.settexts(' Volume: ', ' ')
+ G.gainbtn.setminvalmax(0, G.gain, 255)
+ G.gainbtn.sethook(gain_hook)
+ #
+ G.sizebtn = Label().definetext(w, `len(G.data)` + ' bytes')
+ #
+ #G.showbtn = PushButton().definetext(w, 'Sound-o-gram...')
+ #G.showbtn.hook = show_hook
+ #
+ G.savebtn = PushButton().definetext(w, 'Save...')
+ G.savebtn.hook = save_hook
+ #
+ G.quitbtn = PushButton().definetext(w, 'Quit')
+ G.quitbtn.hook = quit_hook
+ G.playbtn.enable(0)
+ G.savebtn.enable(0)
+ #G.showbtn.enable(0)
+ start_vu()
+ G.window.realize()
+ #
+ # Event loop
+ #
+ MainLoop()
+
+# XXX Disabled...
+def show_hook(self):
+ savetext = self.text
+ self.settext('Be patient...')
+ close_sogram()
+ stdwin.setdefwinsize(400, 300)
+ win = stdwin.open('Sound-o-gram')
+ G.sogram = Soundogram().define(win, G.data)
+ win.buttons = [G.sogram]
+ self.settext(savetext)
+
+def close_sogram():
+ if G.sogram:
+ # Break circular references
+ G.sogram.win.buttons[:] = []
+ del G.sogram.win
+ G.sogram = 0
+
+def mute_hook(self):
+ G.nomuting = (not self.selected)
+ audio.setoutgain(G.nomuting * G.gain)
+
+def rate_hook(self):
+ G.rate = self.rate
+ audio.setrate(G.rate)
+
+def record_on_hook(self):
+ stop_vu()
+ close_sogram()
+ audio.setrate(G.rate)
+ audio.setoutgain(G.nomuting * G.gain)
+ audio.start_recording(BUFSIZE)
+ G.recording = 1
+ G.playbtn.enable(0)
+ G.window.settimer(10 * BUFSIZE / Rates[G.rate])
+
+def record_timer_hook(self):
+ if G.recording:
+ if audio.poll_recording():
+ self.hilite(0)
+ record_off_hook(self)
+ else:
+ self.parent.settimer(5)
+
+def record_off_hook(self):
+ if not G.recording:
+ return
+ G.data = audio.stop_recording()
+ G.recording = 0
+ G.sizebtn.settext(`len(G.data)` + ' bytes')
+ audio.setoutgain(G.nomuting * G.gain)
+ G.playbtn.enable((len(G.data) > 0))
+ G.savebtn.enable((len(G.data) > 0))
+ #G.showbtn.enable((len(G.data) > 0))
+ G.window.settimer(0)
+ start_vu()
+
+def play_on_hook(self):
+ stop_vu()
+ audio.setrate(G.rate)
+ audio.setoutgain(G.gain)
+ audio.start_playing(G.data)
+ G.playing = 1
+ G.recbtn.enable(0)
+ G.window.settimer(max(10 * len(G.data) / Rates[G.rate], 1))
+
+def play_timer_hook(self):
+ if G.playing:
+ if audio.poll_playing():
+ self.hilite(0)
+ play_off_hook(self)
+ else:
+ self.parent.settimer(5)
+
+def play_off_hook(self):
+ if not G.playing:
+ return
+ x = audio.stop_playing()
+ G.playing = 0
+ audio.setoutgain(G.nomuting * G.gain)
+ G.recbtn.enable(1)
+ G.window.settimer(0)
+ start_vu()
+
+def gain_hook(self):
+ G.gain = self.val
+ if G.playing or G.nomuting: audio.setoutgain(G.gain)
+
+def save_hook(self):
+ if not G.data:
+ stdwin.fleep()
+ else:
+ prompt = 'Store sampled data on file: '
+ try:
+ G.savefile = stdwin.askfile(prompt, G.savefile, 1)
+ except KeyboardInterrupt:
+ return
+ try:
+ fp = open(G.savefile, 'w')
+ fp.write(Magics[G.rate] + G.data)
+ except:
+ stdwin.message('Cannot create ' + file)
+
+def stop_vu():
+ G.vubtn.stop()
+
+def start_vu():
+ G.vubtn.start()
+
+def quit_hook(self):
+ G.window.delayed_destroy()
+
+try:
+ main()
+finally:
+ audio.setoutgain(0)
diff --git a/Demo/sgi/audio_stdwin/vumeter.py b/Demo/sgi/audio_stdwin/vumeter.py
new file mode 100755
index 0000000..bfee66e
--- /dev/null
+++ b/Demo/sgi/audio_stdwin/vumeter.py
@@ -0,0 +1,35 @@
+#! /usr/local/python
+
+import audio
+import stdwin
+
+from VUMeter import VUMeter
+from WindowParent import WindowParent
+import MainLoop
+
+NBUFS=20
+BUFSIZE = NBUFS*48
+SCALE=128
+
+class MyVUMeter(VUMeter):
+ def init_reactivity(self):
+ self.parent.need_mouse(self)
+ def mouse_down(self, detail):
+ if self.enabled:
+ self.stop()
+ else:
+ self.start()
+ def mouse_move(self, detail): pass
+ def mouse_up(self, detail): pass
+
+def main():
+ audio.setrate(3)
+ audio.setoutgain(0)
+ w = WindowParent().create('VU Meter', (200, 100))
+ v = MyVUMeter().define(w)
+ v.start()
+ w.realize()
+ while 1:
+ w.dispatch(stdwin.getevent())
+
+main()
diff --git a/Demo/sgi/flp/test_cb.fd b/Demo/sgi/flp/test_cb.fd
new file mode 100755
index 0000000..e83fd1f
--- /dev/null
+++ b/Demo/sgi/flp/test_cb.fd
@@ -0,0 +1,75 @@
+Magic: 12321
+
+Internal Form Definition File
+ (do not change)
+
+Number of forms: 1
+
+=============== FORM ===============
+Name: main_form
+Width: 170.000000
+Height: 190.000000
+Number of Objects: 4
+
+--------------------
+class: 1
+type: 1
+box: 0.000000 0.000000 170.000000 190.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label:
+name:
+callback:
+argument:
+
+--------------------
+class: 11
+type: 0
+box: 10.000000 140.000000 150.000000 40.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Button 1
+name: button1
+callback: button1CB
+argument: 0
+
+--------------------
+class: 11
+type: 0
+box: 10.000000 100.000000 150.000000 40.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Button 2
+name: button2
+callback: button2CB
+argument: 0
+
+--------------------
+class: 11
+type: 6
+box: 10.000000 10.000000 150.000000 40.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: EXIT
+name: exitbutton
+callback: exitbuttonCB
+argument: 0
+
+==============================
+create_the_forms
diff --git a/Demo/sgi/flp/test_cb.py b/Demo/sgi/flp/test_cb.py
new file mode 100755
index 0000000..d622332
--- /dev/null
+++ b/Demo/sgi/flp/test_cb.py
@@ -0,0 +1,62 @@
+#
+# Example 2 - Using fl in python with callbacks.
+#
+# The form is named 'main_form' and resides on file 'test_cb.fd'.
+# It has three objects named button1, button2 and exitbutton.
+# All buttons have callbacks with the same names as their corresponding
+# buttons but with CB appended.
+#
+import fl # The forms library
+import FL # Symbolic constants for the above
+import flp # The module to parse .fd files
+import sys
+
+# The following struct is created to hold the instance variables
+# main_form, button1, button2 and exitbutton.
+
+class myform():
+ #
+ # The init function parses and creates the form, but doesn't
+ # display it (yet).
+ def init(self, number):
+ #
+ # First we parse the form
+ parsetree = flp.parse_form('test_cb', 'main_form')
+ #
+ # Next we create it
+
+ flp.create_full_form(self, parsetree)
+
+ # And keep our number
+ self.number = number
+ return self
+
+ #
+ # The show function displays the form. It doesn't do any interaction,
+ # though.
+ def show(self):
+ self.main_form.show_form(FL.PLACE_SIZE, 1, '')
+
+ # The callback functions
+ def button1CB(self, obj, arg):
+ print 'Button 1 pressed on form', self.number
+
+ def button2CB(self, obj, arg):
+ print 'Button 2 pressed on form', self.number
+
+ def exitbuttonCB(self, obj, arg):
+ print 'Ok, bye bye'
+ sys.exit(0)
+
+#
+# The main program. Instantiate two variables of the forms class
+# and interact with them.
+
+form1 = myform().init(1)
+form2 = myform().init(2)
+
+form1.show()
+form2.show()
+
+obj = fl.do_forms()
+print 'do_forms() returned. This should not happen. obj=', obj
diff --git a/Demo/sgi/flp/test_nocb.fd b/Demo/sgi/flp/test_nocb.fd
new file mode 100755
index 0000000..4d3f7ef
--- /dev/null
+++ b/Demo/sgi/flp/test_nocb.fd
@@ -0,0 +1,75 @@
+Magic: 12321
+
+Internal Form Definition File
+ (do not change)
+
+Number of forms: 1
+
+=============== FORM ===============
+Name: main_form
+Width: 170.000000
+Height: 190.000000
+Number of Objects: 4
+
+--------------------
+class: 1
+type: 1
+box: 0.000000 0.000000 170.000000 190.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label:
+name:
+callback:
+argument:
+
+--------------------
+class: 11
+type: 0
+box: 10.000000 140.000000 150.000000 40.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Button 1
+name: button1
+callback:
+argument:
+
+--------------------
+class: 11
+type: 0
+box: 10.000000 100.000000 150.000000 40.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: Button 2
+name: button2
+callback:
+argument:
+
+--------------------
+class: 11
+type: 6
+box: 10.000000 10.000000 150.000000 40.000000
+boxtype: 1
+colors: 47 47
+alignment: 4
+style: 0
+size: 11.000000
+lcol: 0
+label: EXIT
+name: exitbutton
+callback:
+argument:
+
+==============================
+create_the_forms
diff --git a/Demo/sgi/flp/test_nocb.py b/Demo/sgi/flp/test_nocb.py
new file mode 100755
index 0000000..48cee9d
--- /dev/null
+++ b/Demo/sgi/flp/test_nocb.py
@@ -0,0 +1,45 @@
+#
+# Example 1 - Using fl in python without callbacks.
+#
+# The form is named 'main_form' and resides on file 'test_nocb.fd'.
+# It has three objects named button1, button2 and exitbutton.
+#
+import fl # The forms library
+import FL # Symbolic constants for the above
+import flp # The module to parse .fd files
+import sys
+
+# The following struct is created to hold the instance variables
+# main_form, button1, button2 and exitbutton.
+
+class struct(): pass
+container = struct()
+
+#
+# We now first parse the forms file
+
+parsetree = flp.parse_form('test_nocb', 'main_form')
+
+#
+# Next we create it
+
+flp.create_full_form(container, parsetree)
+
+#
+# And display it
+
+container.main_form.show_form(FL.PLACE_MOUSE, 1, '')
+
+#
+# And interact until the exit button is pressed
+while 1:
+ selected_obj = fl.do_forms()
+ if selected_obj == container.button1:
+ print 'Button 1 selected'
+ elif selected_obj == container.button2:
+ print 'Button 2 selected'
+ elif selected_obj == container.exitbutton:
+ print 'Ok, bye bye'
+ sys.exit(0)
+ else:
+ print 'do_forms() returned unknown object ', selected_obj