home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-01-28 | 9.7 KB | 344 lines | [TEXT/ALFA] |
-
- namespace eval app {}
-
- proc app::ensureRunning {sig {in_front 0}} {
- # See if a process w/ any of the acceptable
- # sigs already running.
- if {[app::isRunning $sig name]} {
- if {$in_front} {switchTo '$sig'}
- return $name
- }
- if {[catch {nameFromAppl $sig} name]} {
- alertnote "Can't find app w/ sig '$sig'.\
- Try rebuilding your desktop or changing your helper apps."
- error ""
- }
- if {![file exists $name]} {
- alertnote "Sig '$sig' is mapped to '$name', which doesn't\
- exist. Try changing your helper apps."
- error ""
- }
- # Launch the app
- if {$in_front} {
- launch -f $name
- } else {
- launch $name
- }
- hook::callAll launch $sig
- return $name
- }
-
- # Switch to 'sig', launching if necesary
- proc app::launchFore {sig} {
- app::ensureRunning $sig 1
- }
-
- # Ensure that the app is at least running in the background.
- proc app::launchBack {sig} {
- app::ensureRunning $sig 0
- }
-
- proc app::launchAnyOfThese {sigs sig {prompt "Please locate the application:"}} {
- app::launchBackSigs $sigs $sig $prompt 0
- }
- proc app::launchElseTryThese {sigs sig {prompt "Please locate the application:"}} {
- app::launchBackSigs $sigs $sig $prompt 1
- }
-
- # Check to see if any of the 'sigs' is running. If so, return its name.
- # Otherwise, attempt to launch the file named by 'sig'.
- proc app::launchBackSigs {sigs sig {prompt "Please locate the application:"} {running_first 1} } {
- global $sig
- if {$running_first || ![info exists $sig] || [catch {nameFromAppl [set $sig]}]} {
- app::setRunningSig $sigs $sig
- app::getSig $prompt $sig
- }
- return [app::launchBack [set $sig]]
- }
-
- proc app::getSig {prompt sig} {
- global $sig modifiedVars
- if {[catch {nameFromAppl [set $sig]}]} {
- set $sig [getFileSig [getfile $prompt]]
- lappend modifiedVars $sig
- }
- }
-
- proc app::setRunningSig {sigs sig} {
- global $sig modifiedVars
- if {[app::isRunning $sigs name s]} {
- if {![info exists $sig] || ($s != [set $sig])} {
- set $sig $s
- lappend modifiedVars $sig
- }
- return 1
- }
- return 0
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "app::runScript" --
- #
- # Generic run script handler. Will prompt for the location of your
- # application if necessary, run in fore/background, show a log of
- # the result etc. See latexComm.tcl or diffMode.tcl for examples
- # of the necessary array entries.
- #
- # 3 variables must be defined: ${op}Sig is a variable whose
- # value is the signature of the application the user has selected
- # to carry out this operation (or the path of an executable, if
- # 'exec' is possible), ${op}AppSignatures is an array of all
- # possible name/signature pairs currently known, and ${op}AppScripts
- # are the scripts for each of those signatures.
- #
- # Modified from original evalTeXScript in latex mode.
- # -------------------------------------------------------------------------
- ##
- proc app::runScript {op prompt filename {runAppInBackground 0} {showLog 0} {flags ""}} {
- global ${op}Sig ${op}AppSignatures ${op}AppScripts nonInteractiveApps
-
- set supportedApps [array names ${op}AppSignatures]
- foreach app $supportedApps { eval lappend sigs [set ${op}AppSignatures($app)] }
- set longPrompt "Please locate a $prompt."
- if { [catch {app::launchAnyOfThese $sigs ${op}Sig $longPrompt} appname] } {
- error "bug in 'app::launchAnyOfThese' : $appname"
- }
- set sig [set ${op}Sig]
- set quotedSig "'[string trim $sig {'}]'"
- if {!$runAppInBackground} { switchTo $quotedSig }
- if {[file exists $sig]} {
- global tcl_platform
- set stream 1
- # Windows Tcl 8.0 has some fileevent bugs
- if {$tcl_platform(platform) == "windows" && [info tclversion] < 8.1} {
- set stream 0
- }
- # Some apps we never wish to capture stdout/stderr
- if {[info exists nonInteractiveApps]} {
- if {[lsearch -exact $nonInteractiveApps $op] != -1} {
- set stream 0
- set runAppInBackground 1
- }
- }
- if {$stream && $showLog} {
- global mode
- set win [new -n "* $op log *" -m $mode -text "File: $filename\n" -shell 1]
- if {$filename != ""} {
- set olddir [pwd]
- cd [file dirname $filename]
- app::setupInput "$sig [file tail $filename] $flags" $win
- cd $olddir
- } else {
- app::setupInput "$sig [file tail $filename] $flags" $win
- }
- set res ""
- } else {
- if {$filename != ""} {
- set olddir [pwd]
- cd [file dirname $filename]
- if {$runAppInBackground} {
- set err [catch {eval [list exec $sig [file tail $filename]] $flags &} res]
- } else {
- set err [catch {eval [list exec $sig [file tail $filename]] $flags} res]
- }
- cd $olddir
- } else {
- if {$runAppInBackground} {
- set err [catch {eval exec [list $sig] $flags &} res]
- } else {
- set err [catch {eval exec [list $sig] $flags} res]
- }
- }
- if {$runAppInBackground} {
- message "Application running in background."
- return
- }
- if {[expr {($showLog + $err) > 1}]} {
- global mode
- new -n "* $op log *" -m $mode -info "File: $filename\n$res"
- }
- if {$err} {
- beep
- message "Run completed abnormally."
- } else {
- message "Run completed successfully."
- }
- }
-
- return $res
- } else {
- foreach app $supportedApps {
- if {[lsearch -exact [set ${op}AppSignatures($app)] $sig] >= 0} {
- foreach script [set ${op}AppScripts($app)] {
- set res [eval $script]
- }
- return $res
- }
- }
- }
- beep
- alertnote "Sorry, no support for your $prompt."
- return
- }
-
- proc app::setupInput {cmd win} {
- global catSig
- app::getSig "Please find your 'cat' application" catSig
- insertText -w $win $cmd "\n"
- set pipe [open "| $catSig" r+]
- fconfigure $pipe -buffering none
- fileevent $pipe readable [list app::handleErrorInput $win $pipe 1]
- set output [open "|$cmd 2>@ $pipe" r]
- fileevent $output readable [list app::handleStdoutInput $win $output $pipe]
- }
-
- proc app::handleErrorInput {w f {err 1}} {
- set data [gets $f]
- if {[string length $data] > 0} {
- insertText -w $w $data "\n"
- update
- }
- }
-
- proc app::handleStdoutInput {w output err} {
- if {[eof $output]} {
- fileevent $output readable ""
- catch close $output
- fileevent $err readable ""
- #catch flush $err
- catch close $err
- insertText -w $w "\nDone\n"
- winReadOnly $w
- }
- set data [gets $output]
- if {[string length $data] > 0} {
- insertText -w $w $data "\n"
- update
- }
- }
-
- proc app::handleInput {w f {err 0}} {
- # Delete handler if input was exhausted.
- if {[eof $f]} {
- fileevent $f readable {}
- close $f
- return
- }
-
- set data [read $f]
-
- if {[string length $data] > 0} {
- insertText -w $w $data
- }
- }
-
-
- ##
- # -------------------------------------------------------------------------
- #
- # "app::isRunning" --
- #
- # Is an app with one of the given sigs running. Set the global $sig
- # to the name of that thing if it is
- #
- # {"Finder" "MACS" 978944 182209 }
- #
- # Much improved by Vince to avoid scanning the processes list one at a
- # time.
- #
- # -------------------------------------------------------------------------
- ##
- proc app::isRunning {sigs {n ""} {s ""}} {
- if {$n != ""} {upvar $n name}
- if {$s != ""} {upvar $s sig}
- if {[regexp "\"(\[^\"\]+)\" \"([join [quote::Regfind [quote::Regfind $sigs]] |])\" " [processes] "" name sig]} {
- return 1
- } else {
- foreach ss $sigs {
- if {[string length $ss] > 4 && [file exists $ss]} {
- set sig $ss
- set name $ss
- return 1
- }
- }
- }
- return 0
-
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "app::registerMultiple" --
- #
- # Does the dirty work so a mode can use different icons for its menu
- # according to which application a particular user has selected for
- # that mode. The arguments are as follows:
- #
- # type - a prefix such as 'java' which is used to create variables
- # such as 'javaSig' 'javaMenu'
- # creators - the list of recognised creators (1st is default)
- # icons - the list of icon resources
- # menurebuild - the procedure which is used to rebuild the mode menu
- #
- # here's an example:
- #
- # app::registerMultiple java [list Javc WARZ] \
- # [list •140 •285] rebuildJavaMenu
- #
- # of course the rebuild procedure must use the correct icon like this:
- #
- # proc rebuildJavaMenu {} {
- # global javaMenu
- # menu -n $javaMenu -p javaMenuProc {
- # }
- # }
- #
- # Note: this procedure ensures the menu is created the first time it
- # is called.
- # --Version--Author------------------Changes-------------------------------
- # 1.0 <darley@fas.harvard.edu> original
- # -------------------------------------------------------------------------
- ##
- proc app::registerMultiple {type creators icons menurebuild} {
- global ${type}Sig multiApp
- if {![info exists ${type}Sig]} {
- set ${type}Sig [lindex $creators 0]
- }
- set multiApp($type) [list $creators $icons $menurebuild]
- app::multiChanged ${type}Sig
- trace variable ${type}Sig w app::multiChanged
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "app::multiChanged" --
- #
- # Utility procedure used by the above. No need to call it manually.
- # -------------------------------------------------------------------------
- ##
- proc app::multiChanged {type args} {
- set type [string range $type 0 [expr {[string last "Sig" $type] -1}]]
- global ${type}Menu ${type}Sig multiApp
- # remove old menu
- catch {removeMenu [set ${type}Menu]}
- # update the icon according to signature
- set info $multiApp($type)
- if {[set i [lsearch -exact [lindex $info 0] [set ${type}Sig]]] == -1} {
- set i 0
- }
- set ${type}Menu [lindex [lindex $info 1] $i]
- # rebuild the menu
- eval [lindex $multiApp($type) 2]
- # insert the new menu
- insertMenu [set ${type}Menu]
- }
-
-
-
-
-
-