#!/usr/bin/tclsh
# =======
# LICENSE
# =======
# This program can be used and modified freely and you are welcome to
# redistribute it under the following terms:
# 
# - This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# - Any derived works should be also distributed freely under an all-permisive
# license. Share the spirit of open source.
#
# Version 0.2 by puppy forum member "gray" 04-Sep-07
#
package require Gnocl

# initial values for menu options 
set signal	-9

#############
# PROCEDURES
#############

proc kill_proc {} {
	global signal plist

	#
	# Get the selected line number.
	# If the list is empty, nothing is selected, so return
	#
	set sell [$plist getSelection]
	if {[llength $sell] == 0} {
		return
	}

	# get the the pid
          set pidn [$plist get $sell 0]
	# Construct a "kill" command line,
	# execute it and get the error return
	set cmd [list exec kill $signal $pidn]
	set ret [catch $cmd err]
	# If there was a problem signalling a process, 
	# let the user know
	if {$ret == 1} {
		gnocl::dialog -type warning -text "Could not kill a process;\nit's already gone?"
		return
	}

	# Refresh the process list
          exec usleep 100
	scan_proc
         # restore signal
         set signal	-9
} 

proc scan_proc {} {
  global plist
	set cmd "|ps"
	# Sort the output (by names or PIDs)
	append cmd " | sort -n | tr -s \" \" "
	# Evaluate the command line
	# Get the resulting list of lines
	# Fill the list-box with the lines
	# Be careful to retain our position in the listbox!
	set fid [open $cmd r]
	if {$fid != 0} {
		# save original position
		set sel [$plist getSelection]
		# clear contents, refill it
		$plist erase 0 end
 		while {[gets $fid line] > 0} {
                       set line [string trim $line]
                       set fields [split $line " "]
                       if { [string first "PID" $line] >= 0 } {continue}
                       if {! [string is digit -strict [lindex $fields 2] ]}  {
                          set fields [linsert $fields 2 "0" ]
                       }
                       set rems [lassign $fields c1 c2 c3 c4]
	           	 $plist add [list $c1 $c2 $c3 $c4 [join $rems] ]  -singleRow 1
		}
		catch {close $fid}

		# restore listbox position
		if {$sel != ""} {
			$plist setSelection $sel -single 1
			$plist scrollToPosition -align center -path $sel
		}
	} {
		gnocl::dialog -type error -text "Cannot run command\n$cmd"
		return
	}
} 

proc do_signal {but} {

    if { $but > 2 } {
       set menu [gnocl::menu -title "signalMenu" -tearoff 0]
       $menu add [gnocl::menuItem -text "1 hangup（ハングアップ）" -onClicked {set signal -1 ; kill_proc}]
       $menu add [gnocl::menuItem -text "2 Interrupt（割り込み）" -onClicked {set signal -2 ; kill_proc}]
       $menu add [gnocl::menuItem -text "3 Quit（終了）" -onClicked {set signal -3 ; kill_proc}]
       $menu add [gnocl::menuItem -text "9 Kill（キル）" -onClicked {set signal -9 ; kill_proc}]
       $menu add [gnocl::menuItem -text "14 Alarm（警告）" -onClicked {set signal -14 ; kill_proc}]
       $menu add [gnocl::menuItem -text "15 Terminate（処理終了）" -onClicked {set signal -15 ; kill_proc}]
       $menu add [gnocl::menuItem -text "23 Stop（停止）" -onClicked {set signal -23 ; kill_proc}]
       $menu add [gnocl::menuItem -text "24 Term. Stop" -onClicked {set signal -24 ; kill_proc}]
       $menu add [gnocl::menuItem -text "25 Continue（継続）" -onClicked {set signal -25 ; kill_proc}]
       $menu popup
    }
    
}

#############
# MAIN CODE
#############


#set up GUI elements
set mainBox [gnocl::box -orientation vertical -borderWidth small -padding small]
set butbox [gnocl::box -orientation horizontal -buttonType true -spacing big -borderWidth small]

set plist [gnocl::list  -titles {"pid" "uid" "size" "stat" "   command"} \
      -scrollbar {automatic always}  -selectionMode single\
      -types {integer string integer string string}  -headersClickable true\
      -onButtonPress {do_signal %b} ]

$plist columnConfigure 0 -titleAlign center
$plist columnConfigure 1 -titleAlign center
$plist columnConfigure 2 -titleAlign center
$plist columnConfigure 3 -titleAlign center

$mainBox add $plist -fill 1 -expand 1
$mainBox add $butbox

$butbox add [gnocl::button -icon "%#Refresh" -text "スキャン" -onClicked scan_proc -widthGroup "1"] 
$butbox add [gnocl::button -icon "%#Remove" -text "Kill" -onClicked kill_proc -widthGroup "1"] 
$butbox add [gnocl::button -text "%#Quit" -onClicked exit -widthGroup "1"] 

# activate (realize) GUI
gnocl::window -title "Process Lister（プロセス一覧）" -child $mainBox \
          -onDestroy exit -onRealize scan_proc -height 300 -width 360

# enter gtk main loop
gnocl::mainLoop
