[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
helpd - the help viewer main window
The helpd program is the program which receives
messages from the helplib library and converts these
messages to actions: loading various help pages and
related actions.
Currently the helpd program is written in tcl/tk for
speed of prototyping and ease of changing. This
may be rewritten in other languages without any
problem, as long as they can perform the following
functions:
1. Receive messages via a pipe.
2. Create a window which may be used by the display processes.
3. Send messages via a pipe to the display processes.
The main help daemon performs the following tasks:
1. Translates the messages from the incoming pipe to actions.
2. Keep track of view histories.
3. Match help files with the proper display processes.
4. Invoke display processes to display the corect help files.
5. Communicate with the display processes via pipes.
6. Provides navigation and main window related actions.
The current help daemon has several shortcomings which are
known, as well as many shortcomings which are not known.
In the near future improved versions will be written which
will then be posted.
Comments, as always, are welcome.
Note that filecomplete.tcl was not written by me, and is
not used with permission. I will track down the originator
and get permission, or write my own at a later date.
Ken Duck
twoducks@globalserve.net
#!/usr/bin/wish
# Help Daemon.
#
# This program provides three main functions:
# 1. Listens to the main help fifo pipe to receive messages from
# programs using the help API.
# 2. Creates the main help frame and buttons, and handles navigation and
# management of help files.
# 3. Manages display plugins and directs messages to control the
# display.
########################################################################
# Initial settings and stuff
source filecomplete.tcl
# Remove pipe if it already exists.
# If the pipe exists then problems can occur.
if {[catch {set test [open help.fifo "RDONLY NONBLOCK"]}] == 0} \
{
close $test
exec rm help.fifo
}
# Navigation list stuff
set navlist [list {}]
set navptr 0
# set the fifo
set fifo 0
set plugin none
# Strings which are used in the frame
set windowTitle "Help"
set openButt "Open"
set backButt "Back"
set forebutt "Forward"
set histButt "History"
set splitButt "Split"
set indexButt "Index"
set contentButt "Contents"
#########################################################################
# Set the main help window gui
wm title . $windowTitle
# Set the help space. This frame (.plugin) is only to be used to give the
# plugins a place to put their views of the documents.
frame .plugin -width 600 -height 400 -container true
pack .plugin -side bottom -fill both -expand true
# Get the ID of the window which plugin may get.
set frameID [winfo id .plugin]
# Do menu
menu .menu -tearoff 0
menu .menu.file -tearoff 0
.menu add cascade -label "File" -menu .menu.file -underline 0
.menu.file add command -label "Open..." -command openFile
.menu.file add command -label "Print Setup..." -command {error "this is just a demo: no action has been defined for the \"Print Setup...\" entry"}
.menu.file add command -label "Print..." -command {error "this is just a demo: no action has been defined for the \"Print...\" entry"}
.menu.file add separator
.menu.file add command -label "Exit" -command exitTasks
menu .menu.nav -tearoff 0
.menu add cascade -label "Navigation" -menu .menu.nav -underline 0
.menu.nav add command -label "Back" -command backFile
.menu.nav add command -label "Forward" -command foreFile
.menu.nav add separator
.menu.nav add command -label "Search..." -command {error "this is just a demo: no action has been defined for the \"Search...\" entry"}
.menu.nav add command -label "Contents..." -command {error "this is just a demo: no action has been defined for the \"Contents...\" entry"}
.menu.nav add command -label "Index..." -command {error "this is just a demo: no action has been defined for the \"Index...\" entry"}
menu .menu.conf -tearoff 0
.menu add cascade -label "Configuration" -menu .menu.conf -underline 0
.menu.conf add command -label "Plugins..." -command {error "this is just a demo: no action has been defined for the \"Plugins...\" entry"}
.menu.conf add command -label "Appearance..." -command {error "this is just a demo: no action has been defined for the \"Appearance...\" entry"}
. configure -menu .menu
# Set the quick navigation button bar.
frame .butt
pack .butt -side top -fill x
# Get the button images
set leftImg [image create photo -file l_hand.gif]
set rightImg [image create photo -file r_hand.gif]
set searchImg [image create photo -file m_glass.gif]
set openImg [image create photo -file folder3.gif]
set indexImg [image create photo -file book.gif]
set contentsImg [image create photo -file doc02.gif]
set infoImg [image create photo -file info.gif]
# Set the buttons
button .butt.open -image $openImg -command openFile
button .butt.back -image $leftImg -command backFile
button .butt.hist -text $histButt
button .butt.search -image $searchImg
button .butt.split -text $splitButt
button .butt.index -image $indexImg
button .butt.contents -image $contentsImg
button .butt.fore -image $rightImg -command foreFile
label .butt.info -image $infoImg
pack .butt.open -side left -fill y
pack .butt.back -side left -fill y
pack .butt.fore -side left -fill y
# pack .butt.hist -side left -fill y
# pack .butt.split -side left -fill y
pack .butt.search -side left -fill y
pack .butt.index -side left -fill y
pack .butt.contents -side left -fill y
pack .butt.info -side right -fill y
####################################################################
# Actions caused by gui actions
# openFile allows the user to select a file from a file menu. This
# file causes the appropriate plugin to be run and a message
# sent down the pipeline.
proc openFile {} \
{
global plugin frameID fifo
global navlist navptr
set filename [fileselect "Open Help File"]
if {[string compare $filename ""] == 0} {return}
#Open a new help file
if {[string compare $plugin none] == 0} \
{
# Start the plugin
exec wish -f testPlugin -use $frameID \&
puts stdout [file type plugin.fifo]
# Start the fifo
set fifo [open "plugin.fifo" w]
set plugin html
}
incr navptr
if {$navptr >= [llength $navlist]} \
{
lappend navlist $filename
} \
else \
{
set navlist [lreplace $navlist $navptr end $filename]
}
writeFifo "open $filename"
}
# backFile causes the main plugin to set the plugin for the previous
# document and send the previous filename down the pipeline.
proc backFile {} \
{
global plugin frameID fifo
global navlist navptr
if {$navptr > 1} \
{
incr navptr -1
}
#Open a new help file
if {[string compare $plugin none] == 0} \
{
# Start the plugin
exec wish -f testPlugin -use $frameID \&
puts stdout [file type plugin.fifo]
# Start the fifo
set fifo [open "plugin.fifo" w]
set plugin html
}
writeFifo "open [lindex $navlist $navptr]"
}
# foreFile causes the main plugin to set the plugin for the next
# document and send the next filename down the pipeline.
proc foreFile {} \
{
global plugin frameID fifo
global navlist navptr
if {$navptr < [expr [llength $navlist] - 1]} \
{
incr navptr
}
#Open a new help file
if {[string compare $plugin none] == 0} \
{
# Start the plugin
exec wish -f testPlugin -use $frameID \&
puts stdout [file type plugin.fifo]
# Start the fifo
set fifo [open "plugin.fifo" w]
set plugin html
}
writeFifo "open [lindex $navlist $navptr]"
}
# writeFifo cuses a message to be sent down the plugin pipeline
proc writeFifo {cmd} \
{
global fifo
# open the file
puts $fifo $cmd
close $fifo
set fifo [open "plugin.fifo" w]
}
# reader is involked when the help pipeline is written to. A pipe reader
# is opened on the pipe and the message is read and handled.
proc reader {pipe} \
{
global plugin frameID fifo
global navptr navlist
if [eof $pipe] \
{
puts stderr "eof!"
catch {close $pipe}
set pipe [open help.fifo "RDONLY NONBLOCK"]
fileevent $pipe readable [list reader $pipe]
return
} \
else \
{
set actualpipe [open help.fifo r]
}
gets $actualpipe line
if {[regexp ^open\ (.*) $line matching filename] != 0} \
{
puts stdout "open $filename"
if {[string compare $filename ""] == 0} {return}
#Open a new help file
if {[string compare $plugin none] == 0} \
{
# Start the plugin
exec wish -f testPlugin -use $frameID \&
puts stdout [file type plugin.fifo]
# Start the fifo
set fifo [open "plugin.fifo" w]
set plugin html
}
incr navptr
if {$navptr >= [llength $navlist]} \
{
lappend navlist $filename
} \
else \
{
set navlist [lreplace $navlist $navptr end $filename]
}
writeFifo "open $filename"
}
close $actualpipe
catch {close $pipe}
set pipe [open help.fifo "RDONLY NONBLOCK"]
fileevent $pipe readable [list reader $pipe]
puts stdout "closed pipe"
}
# The following tasks set up the help pipe so that actions may be sent
# to the main help window.
if {[catch {set pipe [open help.fifo "RDONLY NONBLOCK"]}] != 0} \
{
exec mkfifo help.fifo
} \
else \
{
close $pipe
}
set pipe [open help.fifo "RDONLY NONBLOCK"]
fileevent $pipe readable [list reader $pipe]
# exitTasks are the tasks that need to be performed to cleanly close the
# program.
proc exitTasks {} \
{
global plugin
if {[string compare $plugin none] != 0} \
{
writeFifo close
}
exec rm help.fifo
exit
}
# Assume that since the program is started something is getting sent to
# it. This will prevent the missing of an event between the creation of
# the pipe and the callback handler.
# If there is a command line argument, this is a file name. Show it.
# Elsewise start watching the pipe.
puts stderr "$argc $argv"
if {$argc > 0} \
{
#Open a new help file
if {[string compare $plugin none] == 0} \
{
# Start the plugin
exec wish -f testPlugin -use $frameID \&
puts stdout [file type plugin.fifo]
# Start the fifo
set fifo [open "plugin.fifo" w]
set plugin html
}
incr navptr
if {$navptr >= [llength $navlist]} \
{
lappend navlist $argv
} \
else \
{
set navlist [lreplace $navlist $navptr end $filename]
}
writeFifo "open $argv"
set pipe [open help.fifo "RDONLY NONBLOCK"]
fileevent $pipe readable [list reader $pipe]
} \
else \
{
reader $pipe
}
filecomplete.tcl