You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4128 lines
88 KiB
4128 lines
88 KiB
#!/usr/bin/env ruby
|
|
|
|
# encoding: UTF-8
|
|
# coding: UTF-8
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
#encoding: utf-8
|
|
|
|
require 'gtk2'
|
|
require 'rsvg2'
|
|
require 'socket'
|
|
require 'monitor'
|
|
require 'zlib'
|
|
|
|
# pour debug
|
|
|
|
$threads=[]
|
|
$currentNetName=""
|
|
|
|
# Pour un usage des threads avec GTK
|
|
# http://ruby-gnome2.sourceforge.jp/hiki.cgi?cmd=view&p=tips_threads
|
|
|
|
$home="https://opale.iut-clermont.uca.fr/info/wiki/doku.php?id=public:vdn:start"
|
|
|
|
$lock=false
|
|
|
|
|
|
def setDefaultEditor
|
|
if ENV['NANO_EDITOR'] == "1"; then
|
|
$editor="nano"
|
|
else
|
|
#$editor=ENV['EDITOR']
|
|
$editor="vi" #if $EDITOR == ""
|
|
end
|
|
ENV['EDITOR']=$editor
|
|
end
|
|
|
|
setDefaultEditor
|
|
|
|
#=begin
|
|
#p "[** MAIN prcess **] : #{Process.pid}"
|
|
|
|
Thread.new {
|
|
while true
|
|
$main.setTitle if $main
|
|
sleep(3)
|
|
begin
|
|
#p "[**WAIT parent:#{Process.pid}**]}"
|
|
#Process.wait2(-1, Process::WUNTRACED)
|
|
Process.wait()
|
|
rescue => e
|
|
#p e
|
|
next
|
|
end
|
|
#p "[**RET parent:#{Process.pid}**] #{$?}"
|
|
end
|
|
|
|
}
|
|
#=end
|
|
|
|
=begin
|
|
trap("CLD") do
|
|
p "TRAP CLD begin"
|
|
begin
|
|
cpid = Process.wait
|
|
rescue StandardError => e
|
|
p e
|
|
end
|
|
|
|
p "TRAP CLD end pid:#{cpid}"
|
|
end
|
|
=end
|
|
|
|
def mySystem(cmd)
|
|
|
|
#p "*** #{cmd[-1]}"
|
|
if cmd[-1] == "&"
|
|
cmd=cmd[0..-2]
|
|
end
|
|
#p "+++ #{cmd}"
|
|
|
|
#Gtk.idle_add {
|
|
#system(cmd)
|
|
|
|
#Thread.new {
|
|
# spawn(cmd)
|
|
#}
|
|
#return
|
|
|
|
Thread.new {
|
|
|
|
desc="mySystem"
|
|
$threads.push(desc)
|
|
|
|
#p "[parent : #{Process.pid}] : fork : #{cmd}"
|
|
pid=spawn(cmd)
|
|
#pid=fork {
|
|
# p "[child : #{Process.pid} #{Process.ppid}] :exec : #{cmd}"
|
|
# exec(cmd)
|
|
#}
|
|
sleep(0.5)
|
|
Process.detach(pid)
|
|
$threads.delete_at($threads.index(desc))
|
|
}
|
|
|
|
# false
|
|
#}
|
|
#fork {system(cmd)}
|
|
#pid = fork { system(cmd) }
|
|
#Thread.new {
|
|
# puts "system:#{cmd}"
|
|
# pid = fork { system(cmd) }
|
|
# puts "system end"
|
|
#}
|
|
end
|
|
|
|
module Gtk
|
|
GTK_PENDING_BLOCKS = []
|
|
GTK_PENDING_BLOCKS_LOCK = Monitor.new
|
|
|
|
def Gtk.queue &block
|
|
if Thread.current == Thread.main
|
|
block.call
|
|
else
|
|
GTK_PENDING_BLOCKS_LOCK.synchronize do
|
|
GTK_PENDING_BLOCKS << block
|
|
end
|
|
end
|
|
end
|
|
|
|
def Gtk.main_with_queue timeout
|
|
|
|
if $lock==false
|
|
Gtk.timeout_add timeout do
|
|
if $lock==false
|
|
begin
|
|
GTK_PENDING_BLOCKS_LOCK.synchronize do
|
|
for block in GTK_PENDING_BLOCKS
|
|
block.call
|
|
end
|
|
GTK_PENDING_BLOCKS.clear
|
|
end
|
|
rescue => e
|
|
p "$!"
|
|
puts e.backtrace
|
|
end
|
|
end
|
|
true
|
|
end
|
|
Gtk.main
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
# Gestion du graphique
|
|
|
|
module Svg
|
|
|
|
def svgInit
|
|
@white = Gdk::Color.parse("white")
|
|
@black = Gdk::Color.parse("black")
|
|
@grey = Gdk::Color.parse("grey")
|
|
@blue = Gdk::Color.parse("blue")
|
|
@red = Gdk::Color.parse("red")
|
|
@green = Gdk::Color.parse("green")
|
|
@yellow = Gdk::Color.parse("yellow")
|
|
@orange = Gdk::Color.parse("orange")
|
|
end
|
|
|
|
def draw(area)
|
|
|
|
return false if ! @gw
|
|
return false if ! @gh
|
|
|
|
width=@gw
|
|
height=@gh
|
|
|
|
a=area.allocation.to_a
|
|
aw=a[2]; ah=a[3]
|
|
|
|
width=width+100+2*@bx; height=height+100+2*@by
|
|
|
|
x=0; y=0
|
|
|
|
w0=(aw)-2*@bx; h0=(ah)-2*@by
|
|
|
|
if width>w0 || height>h0
|
|
width=w0; height=h0
|
|
end
|
|
|
|
w=width
|
|
h=height
|
|
|
|
awin=area.window
|
|
@gc=Gdk::GC.new(awin) if !@gc && awin!=nil
|
|
|
|
if @gc
|
|
gc=@gc
|
|
gc.fill = Gdk::GC::Fill::SOLID
|
|
gc.rgb_fg_color = @white
|
|
if awin!= nil
|
|
area.window.draw_rectangle(gc, true, 0, 0 , aw, ah)
|
|
end
|
|
end
|
|
|
|
return if w-2*@bx<=0 || h-2*@by<=0
|
|
|
|
rw=w0*1.0/@gw; rh=h0*1.0/@gh
|
|
|
|
if rw>rh
|
|
ratio=rh
|
|
else
|
|
ratio=rw
|
|
end
|
|
|
|
ratio=1.2 if ratio > 1.2
|
|
|
|
begin
|
|
if ! @pixbuf
|
|
@pixbuf=nil
|
|
svg=RSVG::Handle.new_from_file(@graphfile)
|
|
surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, @gw*ratio, @gh*ratio)
|
|
context = Cairo::Context.new(surface)
|
|
context.scale(ratio, ratio);
|
|
context.render_rsvg_handle(svg)
|
|
file="#{ENV['TMPDIR']}/vdn-gui-#{ENV['USER']}-#{ENV['VDN_GUI_IDENT']}-graph"
|
|
context.target.write_to_png(file)
|
|
context.target.finish
|
|
@pixbuf=GdkPixbuf::Pixbuf.new(:file => file)
|
|
File.delete(file)
|
|
end
|
|
rescue
|
|
return
|
|
end
|
|
|
|
return if ! @pixbuf
|
|
|
|
pixbuf=@pixbuf
|
|
|
|
w=pixbuf.width
|
|
h=pixbuf.height
|
|
|
|
width=w; height=h
|
|
|
|
dx=(w0-w)/2; dy=(h0-h)/2
|
|
|
|
area.window.draw_pixbuf(nil, pixbuf, 0, 0, x+@bx+dx, y+@by+dy, width, height, Gdk::RGB::DITHER_MAX, 0, 0)
|
|
|
|
@x=x; @y=y; @w=w; @h=h; @w0=w0; @h0=h0; @dx=dx; @dy=dy; @w=w; @h=h
|
|
@width=width; @height=height
|
|
|
|
@cx=@gw/w.to_f; @cy=@gh/h.to_f
|
|
@cx=1.0/@cx; @cy=1.0/@cy
|
|
|
|
#drawBoxs
|
|
drawBoxs
|
|
updateSelect
|
|
#Gtk.idle_add { sleep 0.01; updateSelect; false; }
|
|
#drawSelRec
|
|
#updateSelRec
|
|
|
|
true
|
|
end
|
|
|
|
end
|
|
|
|
class Preview
|
|
include Svg
|
|
|
|
attr_reader :dx, :dy, :area, :gc
|
|
attr_reader :cx, :cy, :bx, :by
|
|
attr_reader :selColor
|
|
attr_reader :consoles, :combo
|
|
attr_accessor :hosts, :selection, :pixbuf
|
|
attr_accessor :lines, :graphfile
|
|
|
|
|
|
def initialize(main)
|
|
super()
|
|
@main=main
|
|
|
|
@gc=nil
|
|
@drawed=false
|
|
@gw=@gh=nil
|
|
|
|
svgInit
|
|
|
|
@area = Gtk::DrawingArea.new
|
|
@area.set_size_request(640,480)
|
|
|
|
@area.show
|
|
#@area.realize
|
|
|
|
@area.signal_connect("expose-event") do |widget, event|
|
|
#p "expose...#{ENV['VDN_GUI_IDENT']} #{event} #{@area}"
|
|
load(@dir) if @dir
|
|
false
|
|
end
|
|
|
|
@bx=20
|
|
@by=20
|
|
|
|
end
|
|
|
|
def draw(area)
|
|
#p "draw: #{area}"
|
|
end
|
|
|
|
def load(dir)
|
|
#p "load:#{dir}"
|
|
|
|
return if ! dir
|
|
@dir=dir if dir
|
|
|
|
return if ! @dir
|
|
|
|
if FileTest.exist?(@dir+"/net.svgz") && ENV['RAW_GRAPH']=="0"
|
|
@graphfile=@dir+"/net.svgz"
|
|
elsif FileTest.exist?(@dir+"/graph.svgz")
|
|
@graphfile=@dir+"/graph.svgz"
|
|
end
|
|
|
|
begin
|
|
svg=RSVG::Handle.new_from_file(@graphfile)
|
|
svg.close
|
|
rescue
|
|
return
|
|
end
|
|
|
|
@gw=svg.width
|
|
@gh=svg.height
|
|
#p "w: #{@gw} #{@gh}"
|
|
|
|
return false if ! @gw
|
|
return false if ! @gh
|
|
|
|
width=@gw
|
|
height=@gh
|
|
|
|
area=@area
|
|
|
|
a=area.allocation.to_a
|
|
aw=a[2]; ah=a[3]
|
|
|
|
width=width+100+2*@bx; height=height+100+2*@by
|
|
|
|
x=0; y=0
|
|
|
|
w0=(aw)-2*@bx; h0=(ah)-2*@by
|
|
|
|
if width>w0 || height>h0
|
|
width=w0; height=h0
|
|
end
|
|
|
|
w=width
|
|
h=height
|
|
|
|
awin=area.window
|
|
@gc=Gdk::GC.new(awin) if !@gc && awin!=nil
|
|
|
|
if @gc
|
|
gc=@gc
|
|
gc.fill = Gdk::GC::Fill::SOLID
|
|
gc.rgb_fg_color = @white
|
|
if awin!= nil
|
|
area.window.draw_rectangle(gc, true, 0, 0 , aw, ah)
|
|
end
|
|
end
|
|
|
|
return if w-2*@bx<=0 || h-2*@by<=0
|
|
|
|
rw=w0*1.0/@gw; rh=h0*1.0/@gh
|
|
|
|
if rw>rh
|
|
ratio=rh
|
|
else
|
|
ratio=rw
|
|
end
|
|
|
|
ratio=1.2 if ratio > 1.2
|
|
|
|
#return
|
|
@pixbuf=nil
|
|
|
|
begin
|
|
if ! @pixbuf
|
|
@pixbuf=nil
|
|
svg=RSVG::Handle.new_from_file(@graphfile)
|
|
surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, @gw*ratio, @gh*ratio)
|
|
context = Cairo::Context.new(surface)
|
|
context.scale(ratio, ratio);
|
|
context.render_rsvg_handle(svg)
|
|
file="#{ENV['TMPDIR']}/vdn-gui-#{ENV['USER']}-#{ENV['VDN_GUI_IDENT']}-graph"
|
|
context.target.write_to_png(file)
|
|
context.target.finish
|
|
@pixbuf=GdkPixbuf::Pixbuf.new(:file => file)
|
|
File.delete(file)
|
|
end
|
|
rescue
|
|
return
|
|
end
|
|
|
|
return if ! @pixbuf
|
|
|
|
#p "pixbuf:#{@pixbuf}"
|
|
|
|
pixbuf=@pixbuf
|
|
|
|
w=pixbuf.width
|
|
h=pixbuf.height
|
|
|
|
width=w; height=h
|
|
|
|
dx=(w0-w)/2; dy=(h0-h)/2
|
|
|
|
area.window.draw_pixbuf(nil, pixbuf, 0, 0, x+@bx+dx, y+@by+dy, width, height, Gdk::RGB::DITHER_MAX, 0, 0)
|
|
|
|
@x=x; @y=y; @w=w; @h=h; @w0=w0; @h0=h0; @dx=dx; @dy=dy; @w=w; @h=h
|
|
@width=width; @height=height
|
|
|
|
@cx=@gw/w.to_f; @cy=@gh/h.to_f
|
|
@cx=1.0/@cx; @cy=1.0/@cy
|
|
|
|
#drawBoxs
|
|
#updateSelect
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class Log < Gtk::ScrolledWindow
|
|
def initialize(main, fifo)
|
|
@main=main
|
|
@fifo=fifo
|
|
super()
|
|
set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
|
|
|
|
add(@textView=Gtk::TextView.new)
|
|
|
|
@buffer=@textView.buffer
|
|
@errorTag=@buffer.create_tag('error', {'foreground' => 'red'})
|
|
@normalTag=@buffer.create_tag('normal', {'foreground' => 'black'})
|
|
@buffer.signal_connect("changed") {
|
|
@eob_mark = @textView.buffer.create_mark(nil,@textView.buffer.start_iter.forward_to_end,false)
|
|
@textView.scroll_mark_onscreen(@eob_mark)
|
|
}
|
|
|
|
startLogListener
|
|
|
|
end
|
|
|
|
def startLogListener
|
|
Gtk.init_add do
|
|
Thread.new {
|
|
desc="startLogListener"
|
|
$threads.push(desc)
|
|
|
|
l=[]
|
|
while line=@fifo.gets
|
|
l=line.dup
|
|
|
|
#Gtk.queue do
|
|
eob_mark = @textView.buffer.create_mark(nil,@textView.buffer.start_iter.forward_to_end,false)
|
|
iter = @buffer.get_iter_at_mark(eob_mark)
|
|
if l.include? "rror"
|
|
tag=@errorTag
|
|
else
|
|
tag=@normalTag
|
|
end
|
|
@buffer.insert(iter, Time.now.to_s+ " "+l, tag)
|
|
#end
|
|
end
|
|
|
|
$threads.delete_at($threads.index(desc))
|
|
}
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class BasicTerminal < Gtk::ScrolledWindow
|
|
attr_reader :pid
|
|
|
|
def initialize(command)
|
|
|
|
super()
|
|
|
|
set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_NEVER)
|
|
|
|
add_with_viewport(@vbox=Gtk::VBox.new)
|
|
@vbox.pack_start(@hbox=Gtk::HBox.new)
|
|
|
|
@vte=Vte::Terminal.new
|
|
@vte.signal_connect('child-exited') { |w| parent.destroy }
|
|
|
|
@scrollbar=Gtk::VScrollbar.new(@vte.adjustment)
|
|
|
|
@hbox.pack_start(@vte)#, false, false)
|
|
@hbox.pack_start(@scrollbar) #, false, false) if p
|
|
|
|
@vte.set_size(80,24)
|
|
@vte.set_word_chars(".a-zA-Z_0-9//-")
|
|
@vte.set_colors(Gdk::Color.parse("black"), Gdk::Color.parse("white"),[])
|
|
@vte.audible_bell=false
|
|
@vte.visible_bell=true
|
|
@vte.scrollback_lines=1000
|
|
@vte.set_font("Monospace 12", Vte::TerminalAntiAlias::USE_DEFAULT)
|
|
@pid=@vte.fork_command(:argv => args("bash -c \"#{command}\""))
|
|
show_all
|
|
end
|
|
|
|
def args(s)
|
|
r=[]
|
|
s.gsub(/'([^']*)'|"([^"]*)"|([^[:space:]]+)/) { |m|
|
|
r.push("#{$1}#{$2}#{$3}")
|
|
}
|
|
return r
|
|
end
|
|
end
|
|
|
|
class VdnTerminal < Gtk::Window
|
|
def initialize(name, cmd, read=true, background=true, center=true)
|
|
super()
|
|
|
|
set_title(name)
|
|
|
|
cmd="#{cmd}; echo; echo Press Enter to exit !; read" if read
|
|
|
|
t=BasicTerminal.new(cmd)
|
|
add(t)
|
|
realize
|
|
|
|
if(center)
|
|
x,y=$main.position
|
|
w,h=$main.size
|
|
x=x+w/2; y=y+h/2
|
|
w,h=size
|
|
x=x-w/2; y=y-h/2
|
|
move(x, y)
|
|
end
|
|
|
|
show_all
|
|
|
|
if !background
|
|
while `ps --no-headers -p #{t.pid} -o pid` != ""
|
|
Gtk.main_iteration while Gtk.events_pending?
|
|
sleep(0.05)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
class Vdn < Gtk::Window
|
|
|
|
attr_reader :group, :accelGroup
|
|
def initialize
|
|
super()
|
|
$main=self
|
|
|
|
@group = Gtk::AccelGroup.new
|
|
add_accel_group(@group)
|
|
|
|
@consolesAccelGroup= Gtk::AccelGroup.new
|
|
|
|
@accelGroupGui=Gtk::AccelGroup.new
|
|
@accelGroupConsole=Gtk::AccelGroup.new
|
|
|
|
@accelGroup = @accelGroupGui
|
|
|
|
|
|
open
|
|
#mainDetector
|
|
end
|
|
|
|
def add_main_accel_group
|
|
if @consolesAccelGroup
|
|
remove_accel_group(@consolesAccelGroup)
|
|
end
|
|
add_accel_group(@group)
|
|
end
|
|
|
|
def add_consoles_accel_group
|
|
if @group
|
|
remove_accel_group(@group)
|
|
end
|
|
add_accel_group(@consolesAccelGroup)
|
|
|
|
end
|
|
|
|
|
|
def open
|
|
|
|
dir=ENV['NETWORK_DIR']
|
|
#p "Vdn OPEN dir:#{dir}"
|
|
@frame=VdnFrame.new
|
|
add(@frame)
|
|
|
|
show_all
|
|
|
|
#setTitle("")
|
|
set_default_size(720,480)
|
|
maximize if ENV["MAXIMIZE"] == "1"
|
|
|
|
signal_connect("delete-event") { r=whenQuit; Gtk::main_quit if r; true }
|
|
|
|
#p "frame.net:#{@frame.net}"
|
|
@net=@frame.net
|
|
@notebook=@frame.notebook
|
|
end
|
|
|
|
def setTitle
|
|
name=$currentNetName
|
|
release=ENV["VDN_RELEASE"]
|
|
if name==""
|
|
set_title("[#{ENV['USER']}] vdn-gui (#{release}) - [ nThreads:#{$threads.length} ]") #
|
|
else
|
|
set_title("[#{ENV['USER']}] vdn-gui (#{release}) - #{name} - [ nThreads:#{$threads.length} ]")
|
|
end
|
|
end
|
|
|
|
def clean
|
|
remove(@frame)
|
|
end
|
|
|
|
|
|
|
|
def startListener
|
|
Gtk.init_add do
|
|
Thread.new {
|
|
desc="startListener"
|
|
$threads.push(desc)
|
|
fifo="#{ENV['TMPDIR']}/vdn-gui-#{ENV['USER']}-fifo-ctrl"
|
|
if ! File.exist?(fifo)
|
|
mySystem("umask 077; mkfifo #{fifo}")
|
|
sleep 0.5
|
|
end
|
|
|
|
session = File.open(fifo, "r+")
|
|
|
|
rawLine=session.gets
|
|
while line=rawLine.chomp.split
|
|
|
|
|
|
cmd=line[0]
|
|
|
|
|
|
case cmd
|
|
|
|
when "quit"
|
|
exit(0)
|
|
when "start"
|
|
name=line[1]
|
|
#if mySystem("#{$VDN_PATH}/bin/vdn-alive #{name}")
|
|
# $stderr.puts "Abort starting #{name}., is alive !"
|
|
#else
|
|
expr=line[2..100]
|
|
if @net && @net.consoles
|
|
#cmd=$VDN_PATH+"/bin/vdn-start-wrapper -et -v \"#{expr}\" #{name}"
|
|
#puts "cmd:#{cmd}"
|
|
#Gtk.queue do
|
|
@net.consoles.addTerm(name)
|
|
@notebook.set_page(2)
|
|
#end
|
|
#sleep 1
|
|
else
|
|
cmd=$VDN_PATH+"/bin/vdn-start-wrapper -v \"#{expr}\" #{name}"
|
|
#$stderr.puts "cmd:#{cmd}"
|
|
mySystem(cmd)
|
|
end
|
|
#end
|
|
|
|
when "vnc-viewer"
|
|
name=line[1]
|
|
@net.startVnc(name)
|
|
when "spice-viewer"
|
|
name=line[1]
|
|
@net.startSpice(name)
|
|
end
|
|
|
|
|
|
rawLine=session.gets
|
|
#p "raw line : #{rawLine}"
|
|
end
|
|
$threads.delete_at($threads.index(desc))
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
=begin
|
|
def mainDetector
|
|
Gtk.timeout_add(500) {
|
|
begin
|
|
while pid = Process.wait(-1, Process::WNOHANG)
|
|
end
|
|
rescue
|
|
end
|
|
}
|
|
|
|
|
|
|
|
end
|
|
=end
|
|
|
|
def method_missing(m, *args, &block)
|
|
@frame.send(m, *args, &block)
|
|
end
|
|
end
|
|
|
|
class VdnFrame < Gtk::Frame
|
|
|
|
attr_reader :scriptsMenu, :scriptsTestsMenu, :notebook
|
|
attr_accessor :bback, :bforward, :bhome, :actionsMenu, :actions, :files, :filesMenu
|
|
attr_reader :mod, :net, :preview
|
|
attr_reader :main
|
|
|
|
def initialize()
|
|
super()
|
|
|
|
|
|
@main=$main
|
|
|
|
@preview=Preview.new(self)
|
|
|
|
|
|
@folder=nil
|
|
|
|
@testsToggle=false
|
|
|
|
|
|
@group = @main.group
|
|
|
|
|
|
|
|
@menubar = Gtk::MenuBar.new
|
|
|
|
@vbox=Gtk::VBox.new
|
|
add(@vbox)
|
|
|
|
networksMenu = Gtk::Menu.new
|
|
@scriptsMenu = Gtk::Menu.new
|
|
optionsMenu = Gtk::Menu.new
|
|
@setupMenu = Gtk::Menu.new
|
|
|
|
@setupMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
s=Gtk::MenuItem.new("Edit default rc config (local)...");
|
|
@setupMenu.append(s)
|
|
s.signal_connect('activate') { |w|
|
|
startTerminal("#{$editor} config.rc.local",
|
|
"[ ! -e #{ENV['VDN_PATH']}/config.rc.local ] && \
|
|
cp #{ENV['VDN_PATH']}/config.rc #{ENV['VDN_PATH']}/config.rc.local; \
|
|
#{$editor} #{ENV['VDN_PATH']}/config.rc.local", false)
|
|
}
|
|
|
|
@setupMenu.append(Gtk::MenuItem.new())
|
|
|
|
s=Gtk::MenuItem.new("Edit default guest config (local) ...");
|
|
@setupMenu.append(s)
|
|
s.signal_connect('activate') { |w|
|
|
startTerminal("#{$editor} config.template.local",
|
|
"[ ! -e #{ENV['VDN_PATH']}/config.template.local ] && \
|
|
cp #{ENV['VDN_PATH']}/config.template #{ENV['VDN_PATH']}/config.template.local; \
|
|
#{$editor} #{ENV['VDN_PATH']}/config.template", false)
|
|
}
|
|
|
|
@setupMenu.append(Gtk::MenuItem.new)
|
|
|
|
s=Gtk::MenuItem.new("New network...");
|
|
@setupMenu.append(s)
|
|
s.signal_connect('activate') { |w|
|
|
startTerminal("vdn-new-network",
|
|
"#{$VDN_PATH}/bin/vdn-new-network", true, false)
|
|
}
|
|
|
|
@setupMenu.append(Gtk::MenuItem.new)
|
|
|
|
s=Gtk::MenuItem.new("Download network...");
|
|
@setupMenu.append(s)
|
|
s.signal_connect('activate') { |w|
|
|
startTerminal("vdn-download-network",
|
|
"#{$VDN_PATH}/bin/vdn-download-network", true, false)
|
|
}
|
|
|
|
@setupMenu.append(Gtk::MenuItem.new)
|
|
|
|
@setupMenu.append(s=Gtk::MenuItem.new("Terminal (in vdn directory...)"))
|
|
s.signal_connect('activate') {
|
|
startTerminal("", "cd #{$VDN_PATH}/files; bash", false)
|
|
}
|
|
#@setupMenu.show_all
|
|
|
|
@actionsMenu = Gtk::Menu.new
|
|
@filesMenu = Gtk::Menu.new
|
|
|
|
|
|
@filesMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
|
|
@filesMenu.append(s=Gtk::MenuItem.new("Terminal (in files directory...)"))
|
|
s.signal_connect('activate') {
|
|
startTerminal("", "vdn-manage-files; cd #{$VDN_PATH}/files; bash", false)
|
|
}
|
|
@filesMenu.show_all
|
|
|
|
|
|
@scriptsTestsMenu = Gtk::Menu.new
|
|
|
|
networks = Gtk::MenuItem.new("Network")
|
|
options = Gtk::MenuItem.new("Preferences")
|
|
@scripts = Gtk::MenuItem.new("Scripts")
|
|
@setup = Gtk::MenuItem.new("Main setup")
|
|
@actions = Gtk::MenuItem.new("Network setup")
|
|
@scriptsTests = Gtk::MenuItem.new("All scripts")
|
|
@files = Gtk::MenuItem.new("Files (disks, ...)")
|
|
|
|
#p"vdn: @actions:#{@actions}"
|
|
#p"vdn: @actionsMenu:#{@actionsMenu}"
|
|
|
|
networks.submenu = networksMenu
|
|
options.submenu = optionsMenu
|
|
@scripts.submenu = @scriptsMenu
|
|
@actions.submenu = @actionsMenu
|
|
@setup.submenu = @setupMenu
|
|
@files.submenu = @filesMenu
|
|
|
|
@scriptsTests.submenu = @scriptsTestsMenu
|
|
|
|
@actions.signal_connect('activate') { |w,e|
|
|
@net.updateMoreMenu(@actionsMenu) if @net
|
|
@actionsMenu.show_all
|
|
false
|
|
}
|
|
|
|
@setup.signal_connect('activate') { |w,e|
|
|
@setupMenu.show_all
|
|
false
|
|
}
|
|
|
|
#@files.signal_connect('activate') { |w,e|
|
|
# @net.updateFilesMenu if @net
|
|
# false
|
|
#}
|
|
|
|
#@scriptsTests.submenu = @scriptsTestsMenu
|
|
|
|
|
|
networksMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
# Create the Networks menu content.
|
|
|
|
@bopen = Gtk::ImageMenuItem.new(Gtk::Stock::OPEN, @group)
|
|
networksMenu.append(@bopen)
|
|
@bopen.signal_connect("activate") { |w| whenOpen }
|
|
|
|
@bclose = Gtk::ImageMenuItem.new(Gtk::Stock::CLOSE, @group)
|
|
networksMenu.append(@bclose)
|
|
@bclose.signal_connect("activate") { |w|
|
|
whenClose;
|
|
}
|
|
@bclose.sensitive=false
|
|
|
|
networksMenu.append(Gtk::MenuItem.new)
|
|
|
|
|
|
|
|
Gtk::Stock.add(Gtk::Stock::SELECT_ALL, "Select all", Gdk::Window::CONTROL_MASK, Gdk::Keyval::GDK_A)
|
|
|
|
@bselect = Gtk::ImageMenuItem.new(Gtk::Stock::SELECT_ALL, @group)
|
|
networksMenu.append(@bselect)
|
|
@bselect.signal_connect("activate") { |w| whenSelectAll }
|
|
@bselect.sensitive=false
|
|
|
|
Gtk::Stock.add(Gtk::Stock::YES, "Start selected", Gdk::Window::CONTROL_MASK, Gdk::Keyval::GDK_S)
|
|
@bstart = Gtk::ImageMenuItem.new(Gtk::Stock::YES, @group)
|
|
networksMenu.append(@bstart)
|
|
@bstart.signal_connect("activate") { |w| whenStartSelected }
|
|
@bstart.sensitive=false
|
|
|
|
Gtk::Stock.add(Gtk::Stock::NO, "Halt all", Gdk::Window::CONTROL_MASK, Gdk::Keyval::GDK_H)
|
|
@bhalt = Gtk::ImageMenuItem.new(Gtk::Stock::NO, @group)
|
|
networksMenu.append(@bhalt)
|
|
@bhalt.signal_connect("activate") { |w| whenHaltAll }
|
|
@bhalt.sensitive=false
|
|
|
|
Gtk::Stock.add(Gtk::Stock::REFRESH, "Restart selected", Gdk::Window::CONTROL_MASK, Gdk::Keyval::GDK_R)
|
|
@brestart = Gtk::ImageMenuItem.new(Gtk::Stock::REFRESH, @group)
|
|
networksMenu.append(@brestart)
|
|
@brestart.signal_connect("activate") { |w| whenRestartAll }
|
|
@brestart.sensitive=false
|
|
|
|
Gtk::Stock.add(Gtk::Stock::CLEAR, "Clean selected", Gdk::Window::CONTROL_MASK, Gdk::Keyval::GDK_C)
|
|
@bclean = Gtk::ImageMenuItem.new(Gtk::Stock::CLEAR, @group)
|
|
networksMenu.append(@bclean)
|
|
@bclean.signal_connect("activate") { |w| whenCleanAll }
|
|
@bclean.sensitive=false
|
|
|
|
Gtk::Stock.add(Gtk::Stock::DISCONNECT, "Kill all", Gdk::Window::CONTROL_MASK, Gdk::Keyval::GDK_K)
|
|
@bkill = Gtk::ImageMenuItem.new(Gtk::Stock::DISCONNECT, @group)
|
|
networksMenu.append(@bkill)
|
|
@bkill.signal_connect("activate") { |w| whenKillAll }
|
|
@bkill.sensitive=false
|
|
|
|
# Accel -> Tests mode
|
|
|
|
#@group.connect(Gdk::Keyval::GDK_M, Gdk::Window::CONTROL_MASK,
|
|
# Gtk::ACCEL_VISIBLE) {
|
|
# toggleTests
|
|
#}
|
|
|
|
networksMenu.append(Gtk::MenuItem.new)
|
|
|
|
Gtk::Stock.add(Gtk::Stock::COPY, "View all backups", Gdk::Window::CONTROL_MASK, Gdk::Keyval::GDK_B)
|
|
@bfiles = Gtk::ImageMenuItem.new(Gtk::Stock::COPY, @group)
|
|
networksMenu.append(@bfiles)
|
|
@bfiles.signal_connect("activate") { |w| whenBackups }
|
|
|
|
networksMenu.append(Gtk::MenuItem.new)
|
|
|
|
s=Gtk::MenuItem.new("Edit user rc file...");
|
|
networksMenu.append(s)
|
|
s.signal_connect('activate') { |w|
|
|
startTerminal("#{$editor} rc file",
|
|
"#{$editor} #{ENV['HOME']}/.vdnrc; \
|
|
echo \\\"Pour que les modifications soient effectives vous devez redémarrer VDN\\\" ", true)
|
|
}
|
|
networksMenu.append(Gtk::MenuItem.new)
|
|
|
|
quit = Gtk::ImageMenuItem.new(Gtk::Stock::QUIT, @group)
|
|
quit.signal_connect('activate') {
|
|
r=whenQuit
|
|
p "whenQuit r:#{r}"
|
|
Gtk::main_quit if r
|
|
}
|
|
networksMenu.append(quit)
|
|
|
|
@menubar.append(networks)
|
|
|
|
|
|
# Create the Options menu content.
|
|
|
|
item=Gtk::CheckMenuItem.new("Debug")
|
|
#puts("VDN_DEBUG=#{ENV["VDN_DEBUG"]}")
|
|
item.active=false
|
|
item.active=true if ENV["VDN_DEBUG"] == "1"
|
|
optionsMenu.append(item)
|
|
item.signal_connect("activate") { |w| whenDebug(w) }
|
|
|
|
#item=Gtk::CheckMenuItem.new("External ssh")
|
|
#item.active=true if ENV["VDN_EXTERNAL_SSH"] == "1"
|
|
#optionsMenu.append(item)
|
|
#item.signal_connect("activate") { |w| whenExternalSsh(w) }
|
|
|
|
item=Gtk::CheckMenuItem.new("Parallel")
|
|
item.active=true if ENV["RUN_PARALLEL"] == "1"
|
|
optionsMenu.append(item)
|
|
item.signal_connect("activate") { |w| whenParallel(w) }
|
|
|
|
item=Gtk::CheckMenuItem.new("Maximize at startup")
|
|
item.active=true if ENV["MAXIMIZE"] == "1"
|
|
optionsMenu.append(item)
|
|
item.signal_connect("activate") { |w| whenPreferenceGeneric(w, "MAXIMIZE") }
|
|
|
|
item=Gtk::CheckMenuItem.new("Use nano text editor")
|
|
item.active=true if ENV["NANO_EDITOR"] == "1"
|
|
optionsMenu.append(item)
|
|
item.signal_connect("activate") { |w| whenPreferenceNano(w, "NANO_EDITOR") }
|
|
|
|
item=Gtk::CheckMenuItem.new("Raw graph")
|
|
item.active=true if ENV["RAW_GRAPH"] == "1"
|
|
optionsMenu.append(item)
|
|
item.signal_connect("activate") { |w| whenRawGraph(w) }
|
|
|
|
item=Gtk::CheckMenuItem.new("Test mode")
|
|
|
|
optionsMenu.append(item)
|
|
item.signal_connect("activate") { |w| whenTestMode(w) }
|
|
|
|
@menubar.append(options)
|
|
|
|
@menubar.append(@scripts)
|
|
|
|
if ENV["TEST_MODE"] == "1"
|
|
item.active=true
|
|
@testsToggle=false
|
|
end
|
|
|
|
@vbox.pack_start(@menubar, false, false)
|
|
|
|
@vbox.pack_start(@notebook=Gtk::Notebook.new, true, true)
|
|
|
|
@notebook.scrollable=true
|
|
@notebook.show_border=false
|
|
@notebook.focus_chain=[]
|
|
|
|
# moz
|
|
|
|
@mozbox=Gtk::VBox.new
|
|
|
|
@mozbox.pack_start(@mozbar=Gtk::HBox.new, false, false)
|
|
|
|
@html="#{$home}"
|
|
@banner="#{$VDN_PATH}/doc/banner.svgz"
|
|
|
|
@moz=Gtk::Browser.new
|
|
@moz.banner = @banner
|
|
@moz.location = @html
|
|
|
|
@mozbox.add(@moz)
|
|
@notebook.append_page(@mozbox, Gtk::Label.new("Documentation"))
|
|
|
|
#@log=Log.new(@main, $LOG_FIFO)
|
|
#@notebook.append_page(@log, Gtk::Label.new("Log"))
|
|
|
|
show_all
|
|
|
|
if ENV["NETWORK_DIR"] != ""
|
|
@dir=ENV["NETWORK_DIR"]
|
|
if @dir == ""
|
|
@dir=$dir
|
|
ENV["NETWORK_DIR"]=$dir
|
|
end
|
|
openNet
|
|
else
|
|
closeNet
|
|
end
|
|
|
|
|
|
|
|
signal_connect('event') { |w,e|
|
|
if e.class.to_s == "Gdk::EventKey"
|
|
n=Gdk::Keyval.to_name(e.keyval)
|
|
if e.event_type == Gdk::Event::Type::KEY_PRESS
|
|
if n =~ /Control/
|
|
@mod="Control"
|
|
end
|
|
|
|
if n =~ /Shift/
|
|
@mod="Shift"
|
|
end
|
|
else
|
|
if n =~ /Control/ || n =~ /Shift/
|
|
@mod=nil
|
|
end
|
|
|
|
end
|
|
end
|
|
}
|
|
end
|
|
|
|
|
|
def startTerminal(name, cmd, read=true, background=true, big=false)
|
|
#VdnTerminal.new(name, cmd, read, background, center);
|
|
#return
|
|
#=begin
|
|
opts=""
|
|
|
|
# bg only need for xfce4-terminal
|
|
bg="--disable-server"
|
|
bg="" if background
|
|
|
|
longCmd="NETWORK_DIR=#{@dir} #{cmd}"
|
|
|
|
# xfce4-terminal
|
|
#geom=""
|
|
#geom="--geometry 140x43 --font 10" if big
|
|
|
|
# sajura terminal
|
|
#geom=""
|
|
#geom="-c 140 -r 43 --font 10" if big
|
|
|
|
# xterm
|
|
# xterm -fa 'Monospace' -fs 12 -geometry 80x24 -j -rightbar
|
|
#p "big:#{big}"
|
|
opts="-j -rightbar -sb -vb"
|
|
geom="-fa 'Monospace' -fs 12"
|
|
geom="-fa 'Monospace' -fs 10 -geometry 140x43" if big
|
|
|
|
#p "cmd:#{cmd} read:#{read} bg:#{bg}"
|
|
|
|
#c="cd; export NO_INTERACTIVE=1; xfce4-terminal #{geom} --disable-server -T \"#{name}\" #{bg} -e \"bash -c \'#{longCmd}; echo; echo Press Enter to exit !; read\'\""
|
|
#c="cd; export NO_INTERACTIVE=1; sakura #{geom} -t \"#{name}\" -e \"bash -c \'#{longCmd}; echo; echo Press Enter to exit !; read\'\" 2> /dev/null"
|
|
#c="cd; export NO_INTERACTIVE=1; xterm #{geom} -T \"#{name}\" -e \"bash -c \'#{longCmd}; echo; echo Press Enter to exit !; read\'\" 2> /dev/null"
|
|
|
|
prefix="cd; export NO_INTERACTIVE=1; "
|
|
|
|
extra=""
|
|
extra="; echo; echo Press Enter to exit !; read" if read
|
|
|
|
#c="cd; export NO_INTERACTIVE=1; xfce4-terminal #{geom} --disable-server -T \"#{name}\" #{bg } -e \"bash -c \'#{longCmd} #{extra}\'\""
|
|
#c="cd; export NO_INTERACTIVE=1; sakura #{geom} -t \"#{name}\" -e \"bash -c \'#{longCmd}\'\" 2> /dev/null"
|
|
#c="xterm ${opts} #{geom} -T \"#{name}\" -e \"bash -c \'#{prefix} #{longCmd} #{extra}\'\" &"
|
|
|
|
c="bash -c \'#{prefix} #{longCmd} #{extra}\'"
|
|
|
|
#puts "c:#{c} networkDir:#{ENV['NETWORK_DIR']}"
|
|
#c="#{c} &" # if background
|
|
|
|
#mySystem(c)
|
|
#puts "=== vdn-terminal \"#{c}\""
|
|
|
|
if big == true
|
|
mySystem("vdn-terminal -b \"#{c}\" &")
|
|
else
|
|
mySystem("vdn-terminal \"#{c}\" &")
|
|
end
|
|
|
|
#=end
|
|
end
|
|
|
|
|
|
def getPass
|
|
m=" Mot de passe VDN (mode edit) : "
|
|
|
|
dialog = Gtk::Dialog.new("Message", self,
|
|
Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT,
|
|
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_REJECT],
|
|
[Gtk::Stock::OK, Gtk::Dialog::RESPONSE_ACCEPT])
|
|
|
|
dialog.vbox.add(Gtk::Label.new(m))
|
|
dialog.vbox.add(e=Gtk::Entry.new)
|
|
e.visibility=false
|
|
|
|
e.signal_connect("activate") {
|
|
dialog.children[0].children.last.children.first.clicked
|
|
true
|
|
}
|
|
|
|
#e.max_length=10
|
|
|
|
dialog.show_all
|
|
r=dialog.run
|
|
if r==Gtk::Dialog::RESPONSE_ACCEPT
|
|
require 'bcrypt'
|
|
|
|
# #hash a user's password
|
|
# require'bcrypt'
|
|
# BCrypt::Password.create("secret")
|
|
|
|
hash="$2a$10$bxqjywHoKH5LI6MP6oX2SeJJX./rdZknVByguTj936bqgqZ.Lv/QW"
|
|
r2=(BCrypt::Password.new(hash)==e.text)
|
|
end
|
|
|
|
dialog.destroy
|
|
|
|
return (r==Gtk::Dialog::RESPONSE_ACCEPT) && r2
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def toggleTests
|
|
if @testsToggle
|
|
@testsToggle=false
|
|
@menubar.remove(@setup)
|
|
@menubar.remove(@actions)
|
|
@menubar.remove(@scriptsTests)
|
|
@menubar.remove(@files)
|
|
else
|
|
#if (FileTest.writable?(ENV["NETWORK_DIR"]+"/scripts") || getPass )
|
|
#if (getPass )
|
|
@menubar.append(@setup)
|
|
@menubar.append(@actions)
|
|
@menubar.append(@scriptsTests)
|
|
@menubar.append(@files)
|
|
@scriptsTests.show
|
|
@setup.show
|
|
@actions.show
|
|
@files.show
|
|
|
|
@testsToggle=true
|
|
#end
|
|
end
|
|
end
|
|
|
|
def whenHaltAll
|
|
|
|
if @net != nil
|
|
@net.whenHaltAll
|
|
@notebook.set_page(1)
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
def whenRestartAll
|
|
if @net != nil
|
|
@net.whenRestart
|
|
@notebook.set_page(1)
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
def whenCleanAll
|
|
if @net != nil
|
|
@net.whenClean
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
def whenKillAll
|
|
r=`#{$VDN_PATH}/bin/vdn-alives`
|
|
if r != ""
|
|
m="
|
|
Un ou plusieurs systèmes restent en fonctionnement !
|
|
Si vous validez ils seront \"brutalement\" arrêtés (pas de sauvegarde !)
|
|
"
|
|
|
|
dialog = Gtk::Dialog.new("Message", @main,
|
|
Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT,
|
|
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_REJECT],
|
|
[Gtk::Stock::OK, Gtk::Dialog::RESPONSE_ACCEPT])
|
|
|
|
dialog.vbox.add(Gtk::Label.new(m))
|
|
dialog.show_all
|
|
r=dialog.run
|
|
dialog.destroy
|
|
#p "r:#{r}"
|
|
#p "Gtk::Dialog::RESPONSE_ACCEPT:#{Gtk::Dialog::RESPONSE_ACCEPT}"
|
|
return false if r != Gtk::Dialog::RESPONSE_ACCEPT
|
|
end
|
|
|
|
if @net != nil
|
|
@net.whenKillAll
|
|
@notebook.set_page(1)
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
def whenClose
|
|
|
|
#p "whenClose"
|
|
|
|
return false if ! whenKillAll
|
|
|
|
if @net
|
|
|
|
@net.close
|
|
@net=nil
|
|
closeNet
|
|
@dir=""
|
|
$currentNetName=""
|
|
|
|
|
|
end
|
|
|
|
@bclose.sensitive=false
|
|
@bselect.sensitive=false
|
|
@bstart.sensitive=false
|
|
@bhalt.sensitive=false
|
|
@brestart.sensitive=false
|
|
@bclean.sensitive=false
|
|
@bkill.sensitive=false
|
|
@bopen.sensitive=true
|
|
@scripts.sensitive=false
|
|
@scriptsTests.sensitive=false
|
|
@setup.sensitive=true
|
|
@actions.sensitive=false
|
|
#@files.sensitive=false
|
|
return true
|
|
end
|
|
|
|
|
|
def whenOpen
|
|
|
|
if @folder == nil
|
|
if ENV["NETWORK_DIR"] != ""
|
|
@folder=File.dirname(ENV["NETWORK_DIR"])
|
|
else
|
|
@folder=ENV["VDN_NETWORKS_BASE_DIR"]
|
|
end
|
|
end
|
|
|
|
dialog = Gtk::FileChooserDialog.new("Open network", $main,
|
|
Gtk::FileChooser::ACTION_OPEN,
|
|
nil,
|
|
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
|
|
[Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
|
|
dialog.preview_widget=@main.preview.area
|
|
preview_widget_active=true
|
|
|
|
dialog.signal_connect('update-preview') { |w|
|
|
#p "update-preview #{w.preview_filename}"
|
|
@main.preview.load(w.preview_filename)
|
|
}
|
|
|
|
|
|
#p "dialog.filename:#{dialog.filename}"
|
|
#@main.preview.load(dialog.filename)
|
|
|
|
if @folder
|
|
dialog.current_folder=@folder
|
|
|
|
dialog.signal_connect('current-folder-changed') { |w|
|
|
Gtk.timeout_add(200) {
|
|
begin
|
|
if File.exist?(w.current_folder+"/network.vdn")
|
|
w.filename=w.current_folder+"/network.vdn"
|
|
w.response(Gtk::Dialog::RESPONSE_ACCEPT)
|
|
end
|
|
rescue
|
|
end
|
|
false
|
|
}
|
|
false
|
|
}
|
|
|
|
f = Gtk::FileFilter.new
|
|
f.name="Vdn network"
|
|
f.add_pattern("*.vdn")
|
|
|
|
dialog.set_filter(f)
|
|
|
|
n=nil
|
|
|
|
if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
|
|
f=dialog.filename
|
|
n=File.dirname(f)
|
|
end
|
|
dialog.preview_widget=nil
|
|
dialog.destroy
|
|
else
|
|
@folder=ENV["VDN_NETWORKS_BASE_DIR"]
|
|
end
|
|
|
|
#p "n:#{n}"
|
|
|
|
|
|
|
|
if n
|
|
|
|
if @net != nil
|
|
r=whenClose
|
|
return false if !r
|
|
end
|
|
|
|
@dir=n
|
|
#mySystem($VDN_PATH+"/bin/vdn-busy.rb &")
|
|
|
|
=begin
|
|
message="\n\n\n Open #{@dir} network.\n\nPlease wait... \n\n\n"
|
|
dialog = Gtk::MessageDialog.new(
|
|
self,
|
|
Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT,
|
|
Gtk::MessageDialog::INFO,
|
|
Gtk::MessageDialog::BUTTONS_CLOSE,
|
|
message)
|
|
|
|
# Ensure that the dialog box is destroyed when the user responds.
|
|
dialog.signal_connect('response') { dialog.destroy }
|
|
|
|
# Add the message in a label, and show everything we've added to the dialog.
|
|
#dialog.vbox.add(Gtk::Label.new(message))
|
|
dialog.show_all
|
|
|
|
#Gtk.idle_add {
|
|
=end
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var NETWORK_DIR \"#{@dir}\"")
|
|
ENV['NETWORK_DIR']=@dir
|
|
#@net.close if @net
|
|
#$main.destroy
|
|
|
|
$main.whenQuit
|
|
#$main.destroy
|
|
|
|
#mySystem($VDN_PATH+"/bin/vdn #{@dir} &")
|
|
#sleep(2)
|
|
#whenQuit
|
|
|
|
startNet
|
|
=begin
|
|
#}
|
|
=end
|
|
end
|
|
end
|
|
|
|
def whenSelectAll
|
|
@net.hosts.each_value { |i|
|
|
@net.selection.add(i) if ! i.isSel
|
|
}
|
|
end
|
|
|
|
def whenStartSelected
|
|
@net.whenStart
|
|
end
|
|
|
|
def whenRestartSelected
|
|
@net.whenRestart
|
|
end
|
|
|
|
#def whenTermOld
|
|
# #mySystem("cd #{@dir}; cd scripts; xfce4-terminal --disable-server &")
|
|
# mySystem("cd #{@dir}; cd scripts; sakura &")
|
|
#end
|
|
|
|
def whenBackups
|
|
startTerminal("", "vdn-manage-backups; bash", false)
|
|
#mySystem("xfce4-terminal --disable-server &")
|
|
end
|
|
|
|
def whenFiles
|
|
startTerminal("", "vdn-manage-files; cd $VDN_PATH/files; bash", false)
|
|
#mySystem("xfce4-terminal --disable-server &")
|
|
end
|
|
|
|
def whenQuit
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var NETWORK_DIR \"#{@dir}\"")
|
|
if whenClose
|
|
begin
|
|
#Process.kill("SIGTERM", Process.ppid)
|
|
rescue
|
|
end
|
|
begin
|
|
File.delete("#{ENV['TMPDIR']}/vdn-#{ENV['USER']}-gui-log")
|
|
#File.delete("#{ENV['TMPDIR']}/vdn-gui-#{ENV['USER']}-fifo-ctrl")
|
|
|
|
rescue
|
|
end
|
|
#puts "Bye !"
|
|
#Gtk::main_quit
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
def openNet
|
|
|
|
#p "openNet:"
|
|
|
|
$dir=@dir if @dir && @dir != ""
|
|
|
|
@net.close if @net
|
|
|
|
|
|
@net=nil
|
|
|
|
@dir=$dir if @dir == ""
|
|
|
|
mySystem("#{$VDN_PATH}/bin/vdn-set-network-dir #{@dir}")
|
|
|
|
ENV["NETWORK_DIR"]=@dir
|
|
|
|
@net=Net.new(self, @dir)
|
|
|
|
@net.open
|
|
|
|
|
|
$currentNetName=File.basename(@dir)
|
|
$currentNetName="" if $currentNetName == nil
|
|
|
|
$main.setTitle
|
|
|
|
# Create the Scripts menu content.
|
|
|
|
@scripts.signal_connect('activate') { |w,e|
|
|
@net.updateScriptsMenu
|
|
false
|
|
}
|
|
|
|
@scriptsTests.signal_connect('activate') { |w,e|
|
|
@net.updateScriptsTestsMenu
|
|
false
|
|
}
|
|
|
|
@setup.signal_connect('activate') { |w,e|
|
|
false
|
|
}
|
|
|
|
@actions.signal_connect('activate') { |w,e|
|
|
@net.updateActionsMenu if @net
|
|
false
|
|
}
|
|
|
|
#@files.signal_connect('activate') { |w,e|
|
|
# p "files.activate"
|
|
# @net.updateFilesMenu if @net
|
|
# false
|
|
#}
|
|
|
|
show_all
|
|
|
|
@bclose.sensitive=true
|
|
#@bterm.sensitive=true
|
|
@bselect.sensitive=true
|
|
@bstart.sensitive=true
|
|
@bhalt.sensitive=true
|
|
@brestart.sensitive=true
|
|
@bclean.sensitive=true
|
|
@bkill.sensitive=true
|
|
#@bopen.sensitive=false
|
|
@scripts.sensitive=true
|
|
@scriptsTests.sensitive=true
|
|
@setup.sensitive=true
|
|
@actions.sensitive=true
|
|
@files.sensitive=true
|
|
@moz.banner=@banner
|
|
@moz.location=@html
|
|
|
|
@notebook.set_page(1)
|
|
|
|
end
|
|
|
|
def closeNet
|
|
|
|
@lastDateGraphFile=nil
|
|
if @net
|
|
@net.close
|
|
@net=nil
|
|
end
|
|
|
|
@dir=nil
|
|
ENV['NETWORK_DIR']=""
|
|
#mySystem($VDN_PATH+"/bin/vdn-set-var NETWORK_DIR \"\"")
|
|
|
|
@html="#{$home}"
|
|
@moz.banner=@banner
|
|
@moz.location=@html
|
|
#release=ENV["VDN_RELEASE"]
|
|
$main.setTitle
|
|
|
|
|
|
@bclose.sensitive=false
|
|
#@bterm.sensitive=false
|
|
@bselect.sensitive=false
|
|
@bstart.sensitive=false
|
|
@bhalt.sensitive=false
|
|
@brestart.sensitive=false
|
|
@bclean.sensitive=false
|
|
@bkill.sensitive=false
|
|
@bopen.sensitive=true
|
|
@scripts.sensitive=false
|
|
@actions.sensitive=false
|
|
#@setup.sensitive=false
|
|
@scriptsTests.sensitive=false
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
def whenDebug(w)
|
|
s="0"
|
|
s="1" if w.active?
|
|
ENV["VDN_DEBUG"]=s
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var VDN_DEBUG #{s}")
|
|
end
|
|
|
|
def whenExternalSsh(w)
|
|
|
|
#p "whenExternalSsh: #{w} #{w.active?}"
|
|
s="0"
|
|
s="1" if w.active?
|
|
ENV["VDN_EXTERNAL_SSH"]=s
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var VDN_EXTERNAL_SSH #{s}")
|
|
end
|
|
|
|
def whenPreferenceGeneric(w, varName)
|
|
s="0"
|
|
s="1" if w.active?
|
|
ENV[varName]=s
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var #{varName} #{s}")
|
|
end
|
|
|
|
def whenPreferenceNano(w, varName)
|
|
s="0"
|
|
s="1" if w.active?
|
|
ENV[varName]=s
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var #{varName} #{s}")
|
|
|
|
setDefaultEditor
|
|
end
|
|
|
|
def whenParallel(w)
|
|
s="0"
|
|
s="1" if w.active?
|
|
ENV["RUN_PARALLEL"]=s
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var RUN_PARALLEL #{s}")
|
|
end
|
|
|
|
def whenRawGraph(w)
|
|
s="0"
|
|
s="1" if w.active?
|
|
ENV["RAW_GRAPH"]=s
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var RAW_GRAPH #{s}")
|
|
|
|
return if ! @net
|
|
|
|
@net.lines=""
|
|
@net.graphfile=nil
|
|
@net.parseGraph
|
|
end
|
|
|
|
def whenTestMode(w)
|
|
s="0"
|
|
s="1" if w.active?
|
|
ENV["TEST_MODE"]=s
|
|
mySystem($VDN_PATH+"/bin/vdn-set-var TEST_MODE #{s}")
|
|
|
|
if ! w.active?
|
|
@testsToggle=false
|
|
@menubar.remove(@setup)
|
|
@menubar.remove(@actions)
|
|
@menubar.remove(@scriptsTests)
|
|
@menubar.remove(@files)
|
|
else
|
|
#if (FileTest.writable?(ENV["NETWORK_DIR"]+"/scripts") || getPass )
|
|
#if (getPass )
|
|
@menubar.append(@setup)
|
|
@menubar.append(@actions)
|
|
@menubar.append(@scriptsTests)
|
|
@menubar.append(@files)
|
|
@scriptsTests.show
|
|
@setup.show
|
|
@actions.show
|
|
@files.show
|
|
@testsToggle=true
|
|
#end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
def whenTests(w)
|
|
s="0"
|
|
s="1" if w.active?
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
class Net < Gtk::VBox
|
|
|
|
include Svg
|
|
|
|
attr_reader :dx, :dy, :area, :gc
|
|
attr_reader :cx, :cy, :bx, :by
|
|
attr_reader :selColor
|
|
attr_reader :consoles, :combo
|
|
attr_accessor :hosts, :selection, :pixbuf
|
|
attr_accessor :lines, :graphfile, :lines
|
|
|
|
|
|
def initialize(main, dir)
|
|
|
|
super()
|
|
|
|
@main=main
|
|
@notebook=@main.notebook
|
|
@dir=dir
|
|
|
|
@graphTimeout=nil
|
|
@netTimeout=nil
|
|
|
|
|
|
@lines=nil
|
|
@graphfile=nil
|
|
|
|
@gc=nil
|
|
@drawed=false
|
|
@gw=@gh=nil
|
|
|
|
@consoles=nil
|
|
@ssh=nil
|
|
|
|
svgInit
|
|
|
|
@selColor=Gdk::Color.parse("yellow")
|
|
|
|
@bx=20
|
|
@by=20
|
|
|
|
@selColor=Gdk::Color.parse("yellow")
|
|
|
|
@white = Gdk::Color.parse("white")
|
|
@grey = Gdk::Color.parse("grey")
|
|
@blue = Gdk::Color.parse("blue")
|
|
@red = Gdk::Color.parse("red")
|
|
@green = Gdk::Color.parse("green")
|
|
|
|
@dx=0
|
|
@dy=0
|
|
|
|
@selection=Selection.new(self)
|
|
|
|
@menu=Gtk::Menu.new
|
|
createMenu(@menu)
|
|
|
|
@hosts=Hash.new
|
|
@states=Hash.new
|
|
|
|
@mx=@my=nil
|
|
@selRec=nil
|
|
|
|
@area = Gtk::DrawingArea.new
|
|
|
|
@eventbox=Gtk::EventBox.new
|
|
@eventbox.events=Gdk::Event::ALL_EVENTS_MASK
|
|
|
|
@eventbox.add(@area)
|
|
add(@eventbox);
|
|
|
|
@eventbox.signal_connect('event') { |w,e|
|
|
parseEvent(w,e)
|
|
false
|
|
}
|
|
|
|
@notebook.insert_page(1,self, Gtk::Label.new("Graph"))
|
|
|
|
@area.signal_connect("expose-event") do |widget, event|
|
|
#p "expose...#{ENV['VDN_GUI_IDENT']} #{event} #{@area}"
|
|
draw(@area)
|
|
|
|
# MARCHE PAS !@main.main.add_main_accel_group
|
|
# Il y a des fois ou dans l'onglet graphe les raccourcis claviers
|
|
# Ne fonctionne pas ! Ex Ctrl A pour sélectionner toutes les machines.
|
|
|
|
false
|
|
end
|
|
|
|
@area.signal_connect("configure-event") do |widget, event|
|
|
#p "resize...#{ENV['VDN_GUI_IDENT']} #{event} #{@area}"
|
|
@pixbuf=nil
|
|
false
|
|
end
|
|
|
|
@area.signal_connect("event") do |widget, event|
|
|
#p "event...#{ENV['VDN_GUI_IDENT']} #{event} #{@area}"
|
|
false
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
def parseGraph # net
|
|
|
|
if FileTest.exist?(@dir+"/net.svgz") && ENV['RAW_GRAPH']=="0"
|
|
@graphfile=@dir+"/net.svgz"
|
|
elsif FileTest.exist?(@dir+"/graph.svgz")
|
|
@graphfile=@dir+"/graph.svgz"
|
|
end
|
|
|
|
begin
|
|
f=File::open(@graphfile)
|
|
z=Zlib::GzipReader.open(f)
|
|
lines=z.readlines[1..20].join
|
|
z.close
|
|
f.close
|
|
rescue
|
|
return
|
|
end
|
|
if lines != @lines
|
|
@hosts={}
|
|
@selection.clear
|
|
@lines=lines
|
|
if lines.include?("nkscape") then
|
|
parseInkscape
|
|
elsif lines.include?("raphviz") then
|
|
parseGraphviz
|
|
else
|
|
$stderr.puts("Error : Svg parser not found !")
|
|
end
|
|
begin
|
|
draw(@area)
|
|
rescue
|
|
|
|
end
|
|
whenNewGraph
|
|
end
|
|
end
|
|
|
|
def netDetector
|
|
|
|
#p "add netDetector"
|
|
@netTimeout=Gtk.timeout_add(2000) {
|
|
#p "netDetector... #{Time.now}"
|
|
detect
|
|
#p "netDetector end #{Time.now}"
|
|
true
|
|
}
|
|
|
|
#Gtk.timeout_add(100) {
|
|
# begin
|
|
# @net.detect if @net
|
|
# rescue
|
|
# end
|
|
# false
|
|
#}
|
|
@graphTimeout=Gtk.timeout_add(200) {
|
|
|
|
if @dir && @dir != ""
|
|
|
|
if ! FileTest.exist?(@graphfile)
|
|
@graphfile=nil
|
|
end
|
|
|
|
if ! @graphfile
|
|
if FileTest.exist?(@dir+"/net.svgz") && ENV['RAW_GRAPH']=="0"
|
|
@graphfile=@dir+"/net.svgz"
|
|
elsif FileTest.exist?(@dir+"/graph.svgz")
|
|
@graphfile=@dir+"/graph.svgz"
|
|
end
|
|
end
|
|
|
|
if (@graphfile)
|
|
begin
|
|
@dateGraphFile=File.mtime(@graphfile)
|
|
rescue
|
|
end
|
|
#p @dateGraphFile
|
|
#p " "
|
|
if( ! @lastDateGraphFile || @dateGraphFile!=@lastDateGraphFile)
|
|
|
|
dir=@dir.dup
|
|
|
|
@lines=""
|
|
@pixbuf=nil
|
|
parseGraph
|
|
area.queue_draw
|
|
@lastDateGraphFile=@dateGraphFile
|
|
end
|
|
end
|
|
end
|
|
|
|
true
|
|
}
|
|
|
|
end
|
|
|
|
def whenNewGraph
|
|
|
|
#p "whenNewGraph..."
|
|
|
|
l=`#{$VDN_PATH}/bin/vdn-list | grep -v '^#'`
|
|
l=l.split("\n")
|
|
l=l.sort { |a,b|
|
|
if a.size > b.size
|
|
1
|
|
else
|
|
a <=> b
|
|
end
|
|
}
|
|
|
|
# consoles
|
|
|
|
#@consolesNotebook.set_page(0)
|
|
|
|
#while @consolesNotebook.n_pages > 0
|
|
# @consolesNotebook.remove_page(0)
|
|
#end
|
|
|
|
while @consolesNotebook.n_items > 0
|
|
@consolesNotebook.remove(@consolesNotebook.nth_item(0))
|
|
end
|
|
|
|
l.each { |i|
|
|
#@consolesNotebook.append_page(Gtk::Frame.new, Gtk::Button.new(i))
|
|
#@consolesNotebook.show_all
|
|
b=Gtk::ToolButton.new(nil, i)
|
|
#b.can_focus=false
|
|
@consolesNotebook.add(b)
|
|
b.signal_connect("clicked") {
|
|
#p "initBar : add console"
|
|
#@consoles.addTerm(i)
|
|
mySystem("vdn-viewer #{i} &")
|
|
}
|
|
}
|
|
|
|
@consolesNotebook.show_all
|
|
#@consoles.initBar # initBar consoles
|
|
|
|
# ssh
|
|
|
|
#while @sshNotebook.n_pages > 0
|
|
# @sshNotebook.remove_page(0)
|
|
#end
|
|
|
|
while @sshNotebook.n_items > 0
|
|
@sshNotebook.remove(@sshNotebook.nth_item(0))
|
|
end
|
|
|
|
l.each { |i|
|
|
|
|
#b=Gtk::Button.new(i)
|
|
b=Gtk::ToolButton.new(nil, i)
|
|
#b.can_focus=false
|
|
#b.relief=Gtk::RELIEF_NONE
|
|
|
|
#@sshNotebook.append_page(Gtk::Frame.new, b)
|
|
@sshNotebook.add(b)
|
|
b.signal_connect("clicked") {
|
|
#p "initBar : add ssh"
|
|
if ENV['VDN_EXTERNAL_SSH'] != "1"
|
|
#cmd=$VDN_PATH+"/bin/vdn-ssh-loop -X #{user}@#{i.name}"
|
|
#@ssh.addTerm(i.name, cmd)
|
|
@ssh.addTerm(i)
|
|
@notebook.set_page(3)
|
|
else
|
|
user=@main.net.combo.active_text
|
|
startTerminal("vdn-ssh-loop -X #{user}@#{i}",
|
|
"#{$VDN_PATH}/bin/vdn-ssh-loop -X #{user}@#{i}")
|
|
end
|
|
}
|
|
|
|
}
|
|
|
|
@sshNotebook.show_all
|
|
|
|
#@ssh.initBar # ssh initBar
|
|
|
|
|
|
#@notebook.set_page(3)
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
def open # class Net
|
|
|
|
|
|
return if ! @dir || @dir == ""
|
|
|
|
|
|
r=Dir.glob("#{@dir}/*.conf")
|
|
|
|
if Dir.glob("#{@dir}/*.conf").size == 0
|
|
Gtk.main_iteration while Gtk.events_pending?
|
|
|
|
#p "@dir:#{@dir}"
|
|
#p "ENV['NETWORK_DIR']:#{ENV['NETWORK_DIR']}"
|
|
|
|
startTerminal("vdn-build-network",
|
|
"#{$VDN_PATH}/bin/vdn-build-network", true, false)
|
|
end
|
|
|
|
if FileTest.exist?(@dir+"/net.svgz") && ENV['RAW_GRAPH']=="0"
|
|
@graphfile=@dir+"/net.svgz"
|
|
elsif FileTest.exist?(@dir+"/graph.svgz")
|
|
@graphfile=@dir+"/graph.svgz"
|
|
else
|
|
$stderr.puts("No SVGZ file found !")
|
|
return
|
|
end
|
|
|
|
Gtk.idle_add {
|
|
parseGraph
|
|
if (@graphfile)
|
|
@lastDateGraphFile=File.mtime(@graphfile)
|
|
end
|
|
|
|
#GC.start
|
|
false
|
|
}
|
|
|
|
#@consolesNotebook=Gtk::Notebook.new
|
|
#@consolesNotebook.scrollable=true
|
|
|
|
# Create console
|
|
|
|
@consoles=ConsolesPanel.new(@main, "vdn-start-wrapper -et ", "", \
|
|
"\nN'utilisez les consoles qu'en cas de perte de réseau ! \
|
|
Utilisez le panneau \"Ssh\".\n")
|
|
#@consolesNotebook.append_page(@consoles,
|
|
# Gtk::Label.new("ttyS0"))
|
|
|
|
@consolesNotebook=Gtk::Toolbar.new
|
|
@consolesNotebook.toolbar_style=Gtk::Toolbar::Style::TEXT
|
|
@consolesNotebook.can_focus=false
|
|
|
|
@consolesContainer=Gtk::VBox.new
|
|
@consolesContainerHBox=Gtk::HBox.new
|
|
@consolesContainerHBox.pack_start(Gtk::Label.new("Click to open display -> : "), false, false)
|
|
@consolesContainerHBox.pack_start(@consolesNotebook)
|
|
@consolesContainer.pack_start(@consolesContainerHBox, false, false)
|
|
@consolesContainer.pack_start(@consoles)
|
|
|
|
|
|
@notebook.insert_page(2,@consolesContainer,
|
|
Gtk::Label.new("Consoles"))
|
|
|
|
@consoles.setProps("fgColor", "white")
|
|
@consoles.setProps("bgColor", "black")
|
|
@consoles.setProps("canClose", "false")
|
|
@consoles.setProps("audibleBell", "false")
|
|
@consoles.setProps("gridFont", ENV["GRID_FONT"])
|
|
|
|
|
|
# Create ssh
|
|
|
|
@ssh=SshPanel.new(@main, "vdn-ssh-loop -X ")
|
|
|
|
#@sshNotebook=Gtk::Notebook.new
|
|
@sshNotebook=Gtk::Toolbar.new
|
|
#@sshNotebook.scrollable=true
|
|
@sshNotebook.toolbar_style=Gtk::Toolbar::Style::TEXT
|
|
@sshNotebook.can_focus=false
|
|
|
|
@sshContainer=Gtk::VBox.new
|
|
@sshContainerHBox=Gtk::HBox.new(false, 5)
|
|
|
|
@sshContainerHBox.pack_start(Gtk::Label.new("Ssh user : "), false, false)
|
|
|
|
|
|
combo = Gtk::ComboBoxEntry.new
|
|
combo.can_focus=false
|
|
combo.has_focus=false
|
|
combo.focus_on_click=false
|
|
%w( root test alice bob eve ).each do |val|
|
|
combo.append_text(val)
|
|
end
|
|
combo.set_size_request(120, -1)
|
|
combo.active = 0
|
|
@combo=combo
|
|
|
|
@sshContainerHBox.pack_start(@combo, false, false)
|
|
@sshContainerHBox.pack_start(Gtk::Label.new(" Click to open ssh -> : "), false, false)
|
|
@sshContainerHBox.pack_start(@sshNotebook)
|
|
@sshContainer.pack_start(@sshContainerHBox, false, false)
|
|
@sshContainer.pack_start(@ssh)
|
|
|
|
|
|
item=Gtk::CheckButton.new("New window")
|
|
item.active=true if ENV["VDN_EXTERNAL_SSH"] == "1"
|
|
item.signal_connect("clicked") { |w| @main.whenExternalSsh(w) }
|
|
|
|
@sshContainerHBox.pack_start(item, false, false)
|
|
|
|
|
|
@sshContainerHBox.pack_start(b=Gtk::Button.new("Remove all"), false, false)
|
|
b.signal_connect('clicked') {
|
|
puts "clear ssh..."
|
|
@ssh.close
|
|
}
|
|
|
|
|
|
|
|
@ssh.setProps("audibleBell", "false")
|
|
@ssh.setProps("gridFont", ENV["GRID_FONT"])
|
|
|
|
|
|
createMoreMenu(@main.actionsMenu)
|
|
|
|
|
|
@notebook.insert_page(3, @sshContainer, Gtk::Label.new("Ssh"))
|
|
|
|
whenNewGraph
|
|
|
|
netDetector
|
|
end
|
|
|
|
|
|
def detect
|
|
return if ! @graphfile
|
|
begin
|
|
f=File::open(@graphfile)
|
|
rescue
|
|
return
|
|
end
|
|
|
|
z=nil
|
|
begin
|
|
z=Zlib::GzipReader.open(f) if f != nil
|
|
rescue
|
|
z=nil
|
|
end
|
|
|
|
begin
|
|
lines=z.readlines[1..10].join if z != nil
|
|
rescue
|
|
return
|
|
end
|
|
|
|
begin
|
|
z.close if z != nil
|
|
f.close if f != nil
|
|
rescue
|
|
end
|
|
|
|
#if lines != @lines
|
|
# @main.whenClose
|
|
# @main.openNet
|
|
#end
|
|
|
|
#l=IO.popen("/bin/bash -c \""+$VDN_PATH+"/bin/vdn-alives"+"\"").read
|
|
io=IO.popen($VDN_PATH+"/bin/vdn-alives")
|
|
l=io.read
|
|
Thread.new {
|
|
desc="detect"
|
|
$threads.push(desc)
|
|
Process.wait(io.pid)
|
|
$threads.delete_at($threads.index(desc))
|
|
}
|
|
#p "l1:#{l}"
|
|
|
|
#cmd=$VDN_PATH+"/bin/vdn-alives"
|
|
#l=`#{cmd}`
|
|
#p "l2:#{l}"
|
|
|
|
l=l.split
|
|
|
|
#puts "detect : #{l}"
|
|
|
|
@states.each_key { |i|
|
|
v=@hosts[i]
|
|
if v
|
|
if l.include?(i)
|
|
@states[i]=true
|
|
v.draw(self, @green)
|
|
else
|
|
@states[i]=false
|
|
v.draw(self, @red)
|
|
|
|
if v.vncViewer
|
|
begin
|
|
v.vncViewer.destroy
|
|
rescue
|
|
end
|
|
v.vncViewer=nil
|
|
end
|
|
|
|
if v.spiceViewer
|
|
begin
|
|
v.spiceViewer.destroy
|
|
rescue
|
|
end
|
|
v.spiceViewer=nil
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
}
|
|
true
|
|
end
|
|
|
|
def runScript(name, script)
|
|
$stderr.puts "#{Time.now} Run: \"#{script}\""
|
|
cmd="#{$VDN_PATH}/bin/vdn-scripts -n -r #{script}"
|
|
#VdnTerminal.new(name, cmd, false)
|
|
startTerminal(name, cmd, false, true, true)
|
|
end
|
|
|
|
def editScript(name, script)
|
|
cmd="#{$VDN_PATH}/bin/vdn-scripts -e #{script}"
|
|
startTerminal(name, cmd, false)
|
|
#VdnTerminal.new(name, cmd, false, true, false)
|
|
end
|
|
|
|
def hideScript(file)
|
|
mySystem("chmod 644 #{file}")
|
|
end
|
|
|
|
def unhideScript(file)
|
|
mySystem("chmod 755 #{file}")
|
|
end
|
|
|
|
def isScript(f)
|
|
return true if FileTest.symlink?(f)
|
|
return false if
|
|
! FileTest.file?(f) || ! FileTest.executable?(f) # || ( f =~ /\/repair[^\/]*$/)
|
|
true
|
|
end
|
|
|
|
def updateScriptsMenu
|
|
@main.scriptsMenu.each { |c| @main.scriptsMenu.remove(c) }
|
|
@main.scriptsMenu.append(Gtk::TearoffMenuItem.new)
|
|
dir=@dir+"/scripts"
|
|
l=Dir["#{dir}/*"]
|
|
l.sort.each { |i|
|
|
#next if ! FileTest.file?(i)
|
|
#if ! @testsToggle
|
|
# next if ! FileTest.executable?(i)
|
|
# next if ( i =~ /\/test.*/)
|
|
#end
|
|
|
|
next if ! isScript(i)
|
|
f=File.basename(i)
|
|
s=Gtk::MenuItem.new(f)
|
|
s.signal_connect('activate') {
|
|
runScript("Script : #{f}", f)
|
|
}
|
|
@main.scriptsMenu.append(s)
|
|
}
|
|
@main.scriptsMenu.show_all
|
|
end
|
|
|
|
def isTestScript(f)
|
|
return false if isScript(f)
|
|
return false if
|
|
! FileTest.file?(f) || ! FileTest.executable?(f)
|
|
return true if ( f =~ /\/test.*/)
|
|
false
|
|
end
|
|
|
|
def updateActionsMenu
|
|
#@main.actionsMenu.each { |c| @main.actionsMenu.remove(c) }
|
|
|
|
#createMoreMenu(@main.actionsMenu)
|
|
|
|
#@main.actionsMenu.show
|
|
#@main.actionsMenu.show_all
|
|
|
|
#@main.actions.submenu=@main.actionsMenu
|
|
#@main.actions.show_all
|
|
#@main.actions.signal_connect('activate') { |w,e|
|
|
# updateActionsMenu
|
|
# false
|
|
#}
|
|
end
|
|
|
|
def updateScriptsTestsMenu
|
|
@main.scriptsTestsMenu.each { |c| @main.scriptsTestsMenu.remove(c) }
|
|
dir=@dir+"/scripts"
|
|
l=Dir["#{dir}/*"]
|
|
@main.scriptsTestsMenu.append(@tearoff=Gtk::TearoffMenuItem.new)
|
|
l.sort.each { |i|
|
|
#next if ! FileTest.file?(i)
|
|
#if ! @testsToggle
|
|
# next if ! FileTest.executable?(i)
|
|
# next if ( i =~ /\/test.*/)
|
|
#end
|
|
#next if ! isTestScript(i)
|
|
next if ! FileTest.file?(i)
|
|
f=File.basename(i)
|
|
s=Gtk::MenuItem.new(f)
|
|
s.signal_connect('activate') {
|
|
#editScript("Script : #{f}", f)
|
|
runScript("Script : #{f}", f)
|
|
}
|
|
@main.scriptsTestsMenu.append(s)
|
|
}
|
|
|
|
@main.scriptsTestsMenu.append(Gtk::MenuItem.new)
|
|
|
|
# edit sub menu
|
|
editMenu = Gtk::Menu.new
|
|
editMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
l.sort.each { |i|
|
|
#next if ( ! isScript(i) && !isTestScript(i) )
|
|
next if ! FileTest.file?(i)
|
|
f=File.basename(i)
|
|
e=Gtk::MenuItem.new(f)
|
|
e.signal_connect('activate') {
|
|
editScript("Script : #{f}", f)
|
|
}
|
|
editMenu.append(e)
|
|
}
|
|
|
|
s=Gtk::MenuItem.new("Edit...")
|
|
s.submenu=editMenu
|
|
|
|
#editMenu.append(s)
|
|
#editMenu.show
|
|
|
|
@main.scriptsTestsMenu.append(s)
|
|
|
|
# hide sub menu
|
|
hideMenu = Gtk::Menu.new
|
|
hideMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
l.sort.each { |i|
|
|
#next if ( ! isScript(i) && !isTestScript(i) )
|
|
next if ! FileTest.file?(i)
|
|
f=File.basename(i)
|
|
e=Gtk::MenuItem.new(f)
|
|
e.signal_connect('activate') {
|
|
hideScript(i)
|
|
}
|
|
hideMenu.append(e)
|
|
}
|
|
|
|
s=Gtk::MenuItem.new("Hide...")
|
|
s.submenu=hideMenu
|
|
@main.scriptsTestsMenu.append(s)
|
|
|
|
# unhide sub menu
|
|
unhideMenu = Gtk::Menu.new
|
|
unhideMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
l.sort.each { |i|
|
|
#next if ( ! isScript(i) && !isTestScript(i) )
|
|
next if ! FileTest.file?(i)
|
|
f=File.basename(i)
|
|
e=Gtk::MenuItem.new(f)
|
|
e.signal_connect('activate') {
|
|
unhideScript(i)
|
|
}
|
|
unhideMenu.append(e)
|
|
}
|
|
s=Gtk::MenuItem.new("Unhide...")
|
|
s.submenu=unhideMenu
|
|
@main.scriptsTestsMenu.append(s)
|
|
|
|
|
|
s=Gtk::MenuItem.new("New script...")
|
|
s.signal_connect('activate') {
|
|
#mySystem("echo -en \"New script name ? : \"; read new; echo #{dir}/$new")
|
|
cmd="echo -en \\\"(new) New script name ? : \\\"; \
|
|
read new;
|
|
|
|
cat << EOF > #{dir}/\\$new;
|
|
#!/usr/bin/env bash
|
|
|
|
DESC=\\\"One line description.\\\"
|
|
|
|
run() {
|
|
|
|
# name=XXX
|
|
#
|
|
# requestSshGuest \\\$name
|
|
# ...
|
|
|
|
}
|
|
|
|
EOF
|
|
"
|
|
|
|
startTerminal("New script", cmd, false)
|
|
}
|
|
@main.scriptsTestsMenu.append(s)
|
|
|
|
|
|
|
|
# renameScript sub menu
|
|
renameScriptMenu = Gtk::Menu.new
|
|
renameScriptMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
l.sort.each { |i|
|
|
#next if ( ! isScript(i) && !isTestScript(i) )
|
|
next if ! FileTest.file?(i)
|
|
f=File.basename(i)
|
|
e=Gtk::MenuItem.new(f)
|
|
e.signal_connect('activate') {
|
|
cmd="echo -en \\\"(rename) New script name ? : \\\"; read new; mv #{i} #{dir}/\\$new"
|
|
startTerminal("Rename #{i}", cmd, false)
|
|
}
|
|
renameScriptMenu.append(e)
|
|
}
|
|
s=Gtk::MenuItem.new("Rename...")
|
|
s.submenu=renameScriptMenu
|
|
@main.scriptsTestsMenu.append(s)
|
|
|
|
|
|
# copyScriptMenu sub menu
|
|
copyScriptMenu = Gtk::Menu.new
|
|
copyScriptMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
l.sort.each { |i|
|
|
#next if ( ! isScript(i) && !isTestScript(i) )
|
|
next if ! FileTest.file?(i)
|
|
f=File.basename(i)
|
|
e=Gtk::MenuItem.new(f)
|
|
e.signal_connect('activate') {
|
|
cmd="echo -en \\\"(copy) New script name ? : \\\"; read new; cp #{i} #{dir}/\\$new"
|
|
startTerminal("Copy #{i}", cmd, false)
|
|
}
|
|
copyScriptMenu.append(e)
|
|
}
|
|
s=Gtk::MenuItem.new("Copy...")
|
|
s.submenu=copyScriptMenu
|
|
@main.scriptsTestsMenu.append(s)
|
|
|
|
# deleteScript sub menu
|
|
deleteScriptMenu = Gtk::Menu.new
|
|
deleteScriptMenu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
l.sort.each { |i|
|
|
#next if ( ! isScript(i) && !isTestScript(i) )
|
|
next if ! FileTest.file?(i)
|
|
f=File.basename(i)
|
|
e=Gtk::MenuItem.new(f)
|
|
e.signal_connect('activate') {
|
|
cmd="rm -i #{i}"
|
|
startTerminal("Delete #{i}", cmd, false)
|
|
}
|
|
deleteScriptMenu.append(e)
|
|
}
|
|
s=Gtk::MenuItem.new("Delete...")
|
|
s.submenu=deleteScriptMenu
|
|
@main.scriptsTestsMenu.append(s)
|
|
|
|
@main.scriptsTestsMenu.append(Gtk::MenuItem.new)
|
|
|
|
s=Gtk::MenuItem.new("Terminal (in scripts directory)...")
|
|
s.signal_connect('activate') {
|
|
startTerminal("", "cd #{@dir}/scripts; bash", false)
|
|
}
|
|
@main.scriptsTestsMenu.append(s)
|
|
|
|
|
|
@main.scriptsTestsMenu.show_all
|
|
end
|
|
|
|
|
|
def updateIsosMenu(menu)
|
|
menu.each { |c| menu.remove(c) }
|
|
dir=$VDN_PATH+"/files/g"
|
|
l=Dir["#{dir}/*.iso"]
|
|
l.sort.each { |i|
|
|
f=File.basename(i)
|
|
s=Gtk::MenuItem.new(f)
|
|
s.signal_connect('activate') {
|
|
whenStartOnSelectedIso(i)
|
|
}
|
|
menu.append(s)
|
|
}
|
|
menu.show_all
|
|
end
|
|
|
|
def updateMenus
|
|
updateMainMenu
|
|
#updateMoreMenu
|
|
end
|
|
|
|
def updateMoreMenu(menu)
|
|
state=true
|
|
state=false if @selection.empty
|
|
|
|
l=[menu.downloadDisks,menu.uploadDisksAndIsos,menu.uploadDisks]
|
|
l.each { |i| i.sensitive=state }
|
|
end
|
|
|
|
def updateOtherBuildMenu
|
|
l=`vdn-list-networks -b`
|
|
#p "l:#{l}"
|
|
l.split.sort.each { |i|
|
|
f=File.basename(i)
|
|
e=Gtk::MenuItem.new(f)
|
|
e.signal_connect('activate') {
|
|
startTerminal("Edit and build network...",
|
|
"#{ENV['VDN_PATH']}/bin/vdn-build-network -e #{File.dirname(@dir)}/#{f}", true)
|
|
#startTerminal("#{$editor} #{f}",
|
|
#"#{$editor} #{File.dirname(@dir)}/#{f}/build", false)
|
|
|
|
}
|
|
@otherBuildMenu.append(e)
|
|
}
|
|
end
|
|
|
|
def createMoreMenu(menu)
|
|
|
|
#p "createMoreMenu:#{menu}"
|
|
menu.append(Gtk::TearoffMenuItem.new)
|
|
|
|
#p "add meth to menu : #{menu}"
|
|
class << menu
|
|
attr_accessor :downloadDisks, :uploadDisksAndIsos, :uploadDisks
|
|
end
|
|
|
|
menu.downloadDisks=Gtk::MenuItem.new("Download cdrom(s) and/or disk(s)...")
|
|
menu.append(menu.downloadDisks)
|
|
menu.downloadDisks.signal_connect('activate') { |w|
|
|
whenDownload
|
|
}
|
|
|
|
menu.uploadDisksAndIsos=Gtk::MenuItem.new("Upload cdrom(s) and/or disk(s)...")
|
|
menu.append(menu.uploadDisksAndIsos)
|
|
menu.uploadDisksAndIsos.signal_connect('activate') { |w|
|
|
whenUploadDisksAndIsos
|
|
}
|
|
|
|
menu.uploadDisks=Gtk::MenuItem.new("Upload only disk(s)...")
|
|
menu.append(menu.uploadDisks)
|
|
menu.uploadDisks.signal_connect('activate') { |w|
|
|
whenUploadDisks
|
|
}
|
|
|
|
menu.append(Gtk::MenuItem.new())
|
|
=begin
|
|
@editMainConfigTemplate=Gtk::MenuItem.new("Edit template config (local) ...");
|
|
menu.append(@editMainConfigTemplate)
|
|
@editMainConfigTemplate.signal_connect('activate') { |w|
|
|
startTerminal("#{$editor} config.template.local",
|
|
"[ ! -e #{ENV['VDN_PATH']}/config.template.local ] && \
|
|
cp #{ENV['VDN_PATH']}/config.template #{ENV['VDN_PATH']}/config.template.local; \
|
|
#{$editor} #{ENV['VDN_PATH']}/config.template", false)
|
|
}
|
|
=end
|
|
@editNetworkScript=Gtk::MenuItem.new("Edit network script...");
|
|
menu.append(@editNetworkScript)
|
|
@editNetworkScript.signal_connect('activate') { |w|
|
|
startTerminal("Build network...", "#{ENV['VDN_PATH']}/bin/vdn-build-network -e #{@dir}", false)
|
|
}
|
|
|
|
@buildNetwork=Gtk::MenuItem.new("(Re)build network...");
|
|
menu.append(@buildNetwork)
|
|
@buildNetwork.signal_connect('activate') { |w|
|
|
#p "@dir:#{@dir}"
|
|
#p "ENV['NETWORK_DIR']:#{ENV['NETWORK_DIR']}"
|
|
|
|
startTerminal("vdn-build-network",
|
|
"#{$VDN_PATH}/bin/vdn-build-network")
|
|
}
|
|
|
|
|
|
|
|
menu.append(Gtk::MenuItem.new())
|
|
|
|
|
|
@otherBuildMenu = Gtk::Menu.new
|
|
@otherBuildMenu.append(Gtk::TearoffMenuItem.new)
|
|
updateOtherBuildMenu
|
|
s=Gtk::MenuItem.new("Other \"build\" scripts...")
|
|
s.submenu=@otherBuildMenu
|
|
|
|
menu.append(s)
|
|
|
|
menu.append(Gtk::MenuItem.new())
|
|
|
|
@cloneNetwork=Gtk::MenuItem.new("Clone network...");
|
|
menu.append(@cloneNetwork)
|
|
@cloneNetwork.signal_connect('activate') { |w|
|
|
startTerminal("vdn-clone-network",
|
|
"#{$VDN_PATH}/bin/vdn-clone-network", true, false)
|
|
#mySystem("vdn-clone-network")
|
|
|
|
}
|
|
|
|
@cloneNetwork=Gtk::MenuItem.new("Delete network...");
|
|
menu.append(@cloneNetwork)
|
|
@cloneNetwork.signal_connect('activate') { |w|
|
|
startTerminal("vdn-clone-network",
|
|
"#{$VDN_PATH}/bin/vdn-delete-network")
|
|
#mySystem("vdn-clone-network")
|
|
@main.closeNet
|
|
}
|
|
|
|
menu.append(Gtk::MenuItem.new())
|
|
|
|
@editNetworkGraph=Gtk::MenuItem.new("Inkscape net.svgz...");
|
|
menu.append(@editNetworkGraph)
|
|
@editNetworkGraph.signal_connect('activate') { |w|
|
|
mySystem("inkscape #{@dir}/net.svgz &")
|
|
}
|
|
|
|
@editNetworkGraph=Gtk::MenuItem.new("Delete net.svgz...");
|
|
menu.append(@editNetworkGraph)
|
|
@editNetworkGraph.signal_connect('activate') { |w|
|
|
startTerminal("Delete #{@dir}/net.svgz", "rm -i #{@dir}/net.svgz", false)
|
|
}
|
|
|
|
menu.append(Gtk::MenuItem.new())
|
|
|
|
@s=Gtk::MenuItem.new("Publish network...");
|
|
menu.append(@s)
|
|
@s.signal_connect('activate') { |w|
|
|
startTerminal("vdn-publish-network",
|
|
"vdn-publish-network")
|
|
}
|
|
|
|
menu.append(Gtk::MenuItem.new)
|
|
|
|
s=Gtk::MenuItem.new("Terminal (in network directory)...")
|
|
s.signal_connect('activate') {
|
|
startTerminal("", "cd #{@dir}; bash", false)
|
|
}
|
|
menu.append(s)
|
|
|
|
end
|
|
|
|
def createMenu(menu)
|
|
menu.append(Gtk::MenuItem.new(""))
|
|
@tearoff=Gtk::TearoffMenuItem.new
|
|
menu.append(@tearoff)
|
|
|
|
|
|
#menu.append(Gtk::MenuItem.new(""))
|
|
|
|
@start=Gtk::MenuItem.new("Download disk(s)...")
|
|
menu.append(@start)
|
|
@start.signal_connect('activate') { |w| whenDownload }
|
|
|
|
menu.append(Gtk::MenuItem.new())
|
|
|
|
@start=Gtk::MenuItem.new("Start")
|
|
menu.append(@start)
|
|
@start.signal_connect('activate') { |w| whenStart }
|
|
|
|
@startOnCdrom=Gtk::MenuItem.new("Start on cdrom")
|
|
menu.append(@startOnCdrom)
|
|
@startOnCdrom.signal_connect('activate') { |w| whenStartOnCdrom }
|
|
|
|
@startSelectCdromMenu = Gtk::Menu.new
|
|
@startSelectCdrom=Gtk::MenuItem.new("Start on selected cdrom")
|
|
@startSelectCdrom.submenu=@startSelectCdromMenu
|
|
|
|
updateIsosMenu(@startSelectCdromMenu)
|
|
|
|
menu.append(@startSelectCdrom)
|
|
|
|
@halt=Gtk::MenuItem.new("Halt")
|
|
menu.append(@halt)
|
|
@halt.signal_connect('activate') { |w| whenHalt }
|
|
|
|
#@reboot=Gtk::MenuItem.new("Reboot")
|
|
#menu.append(@reboot)
|
|
#@reboot.signal_connect('activate') { |w| whenReboot }
|
|
#@reboot.sensitive=false
|
|
|
|
@save=Gtk::MenuItem.new("Save")
|
|
menu.append(@save)
|
|
@save.signal_connect('activate') { |w| whenSave }
|
|
|
|
@restart=Gtk::MenuItem.new("Restart")
|
|
menu.append(@restart)
|
|
@restart.signal_connect('activate') { |w| whenRestart }
|
|
|
|
@ssh=Gtk::MenuItem.new("Ssh")
|
|
menu.append(@ssh)
|
|
@ssh.signal_connect('activate') { |w| whenSsh }
|
|
|
|
|
|
@viewer=Gtk::MenuItem.new("Viewer")
|
|
menu.append(@viewer)
|
|
@viewer.signal_connect('activate') { |w| whenViewer }
|
|
|
|
#Gtk::Stock.add(Gtk::Stock::EXECUTE, "Terminal", Gdk::Window::CONTROL_MASK, Gdk::Keyval::GDK_T)
|
|
#@bviewer = Gtk::ImageMenuItem.new(Gtk::Stock::EXECUTE, @group)
|
|
#networksMenu.append(@bviewer)
|
|
#@bviewer.signal_connect("activate") { |w| whenViewer }
|
|
|
|
|
|
@config=Gtk::MenuItem.new("Config...")
|
|
menu.append(@config)
|
|
@config.signal_connect('activate') { |w| whenConfig }
|
|
|
|
@infos=Gtk::MenuItem.new("Infos")
|
|
menu.append(@infos)
|
|
@infos.signal_connect('activate') { |w| whenInfos }
|
|
|
|
@clean=Gtk::MenuItem.new("Clean")
|
|
menu.append(@clean)
|
|
@clean.signal_connect('activate') { |w| whenClean }
|
|
|
|
@kill=Gtk::MenuItem.new("Kill")
|
|
menu.append(@kill)
|
|
@kill.signal_connect('activate') { |w| whenKill }
|
|
|
|
menu.append(Gtk::MenuItem.new(""))
|
|
|
|
=begin
|
|
@moreMenu = Gtk::Menu.new
|
|
@more=Gtk::MenuItem.new("More...")
|
|
@more.submenu=@moreMenu
|
|
|
|
createMoreMenu(@moreMenu)
|
|
menu.append(@more)
|
|
@more.signal_connect('activate') { |w,e|
|
|
updateMoreMenu(menu)
|
|
false
|
|
}
|
|
|
|
sep1=Gtk::MenuItem.new()
|
|
menu.append(sep1)
|
|
=end
|
|
|
|
menu.show_all
|
|
end
|
|
|
|
def updateMainMenu
|
|
state=true
|
|
state=false if @selection.empty
|
|
|
|
@menu.children.each { |i| i.sensitive=state }
|
|
#@more.sensitive=true
|
|
@tearoff.sensitive=true
|
|
|
|
end
|
|
|
|
def showMenu
|
|
updateMainMenu
|
|
@menu.popup(nil, nil, 3, 0)
|
|
end
|
|
|
|
def startTerminal(name, cmd, read=true, background=true, big=false)
|
|
@main.startTerminal(name, cmd, read, background, big)
|
|
end
|
|
|
|
def whenStart
|
|
@selection.to_a.sort_by{ |i| i.name }.each { |i|
|
|
if ! @states[i.name]
|
|
p "Start #{i.name}"
|
|
if @consoles
|
|
cmd=$VDN_PATH+"/bin/vdn-start-wrapper -et #{i.name}"
|
|
@consoles.addTerm(i.name, cmd)
|
|
@notebook.set_page(2)
|
|
else
|
|
cmd=$VDN_PATH+"/bin/vdn-start-wrapper #{i.name}"
|
|
mySystem(cmd)
|
|
end
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
def whenStartOnCdrom
|
|
@selection.to_a.each { |i|
|
|
if ! @states[i.name]
|
|
p "Start #{i.name}"
|
|
if @consoles
|
|
cmd=$VDN_PATH+"/bin/vdn-start-wrapper -et -v BOOT_CDROM=1 #{i.name}"
|
|
p "addTerm:"
|
|
@consoles.addTerm(i.name, cmd)
|
|
@notebook.set_page(2)
|
|
else
|
|
cmd=$VDN_PATH+"/bin/vdn-start-wrapper -v BOOT_CDROM=1 #{i.name}"
|
|
mySystem(cmd)
|
|
end
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
def whenStartOnSelectedIso(iso)
|
|
@selection.to_a.each { |i|
|
|
if ! @states[i.name]
|
|
p "Start #{i.name}"
|
|
if @consoles
|
|
cmd=$VDN_PATH+"/bin/vdn-start-wrapper -et -v \"BOOT_CDROM=1;CDROM=#{iso}\" #{i.name}"
|
|
@consoles.addTerm(i.name, cmd)
|
|
@notebook.set_page(2)
|
|
else
|
|
cmd=$VDN_PATH+"/bin/vdn-start-wrapper -v \"BOOT_CDROM=1;CDROM=#{iso}\" #{i.name}"
|
|
mySystem(cmd)
|
|
end
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
def whenDownload
|
|
l=""
|
|
@selection.to_a.each { |i|
|
|
l="#{l} #{i.name}"
|
|
}
|
|
|
|
startTerminal("vdn-download-disks #{l}", "#{$VDN_PATH}/bin/vdn-download-disks #{l}")
|
|
end
|
|
|
|
def whenUploadDisks
|
|
l=""
|
|
@selection.to_a.each { |i|
|
|
l="#{l} #{i.name}"
|
|
}
|
|
startTerminal("vdn-upload-disks #{l}", "#{$VDN_PATH}/bin/vdn-upload-disks #{l}")
|
|
end
|
|
|
|
def whenUploadDisksAndIsos
|
|
l=""
|
|
@selection.to_a.each { |i|
|
|
l="#{l} #{i.name}"
|
|
}
|
|
startTerminal("vdn-upload-disks -o #{l}", "#{$VDN_PATH}/bin/vdn-upload-disks -o #{l}")
|
|
end
|
|
|
|
def whenHalt
|
|
|
|
@selection.to_a.each { |i|
|
|
if @states[i.name]
|
|
mySystem($VDN_PATH+"/bin/vdn-halt #{i.name} &")
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
|
|
def whenReboot
|
|
@selection.to_a.each { |i|
|
|
if @states[i.name]
|
|
mySystem($VDN_PATH+"/bin/vdn-ssh root@#{i.name} reboot &")
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
def whenRestart
|
|
@selection.to_a.each { |i|
|
|
if @states[i.name]
|
|
p "Restart #{i.name}..."
|
|
mySystem($VDN_PATH+"/bin/vdn-restart -g #{i.name} &")
|
|
end
|
|
}
|
|
end
|
|
|
|
def whenSave
|
|
@selection.to_a.each { |i|
|
|
if @states[i.name]
|
|
mySystem($VDN_PATH+"/bin/vdn-save #{i.name} &")
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
def whenSsh
|
|
@selection.to_a.each { |i|
|
|
user=@main.net.combo.active_text
|
|
if @ssh && ENV['VDN_EXTERNAL_SSH'] != "1"
|
|
cmd=$VDN_PATH+"/bin/vdn-ssh-loop -X #{user}@#{i.name}"
|
|
@ssh.addTerm(i.name, cmd)
|
|
@notebook.set_page(3)
|
|
else
|
|
startTerminal("vdn-ssh-loop -X #{user}@#{i.name}",
|
|
"#{$VDN_PATH}/bin/vdn-ssh-loop -X #{user}@#{i.name}")
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
def whenViewer
|
|
@selection.to_a.each { |i|
|
|
if @states[i.name]
|
|
mySystem($VDN_PATH+"/bin/vdn-spice-viewer #{i.name} &")
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
def whenConfig
|
|
@selection.to_a.each { |i|
|
|
startTerminal("#{$editor} #{i.name}.conf",
|
|
"#{$editor} #{@dir}/#{i.name}.conf", false)
|
|
}
|
|
|
|
end
|
|
|
|
|
|
def whenInfos
|
|
@selection.to_a.each { |i|
|
|
startTerminal("vdn-infos #{i.name}",
|
|
"#{$VDN_PATH}/bin/vdn-infos #{i.name}")
|
|
}
|
|
|
|
end
|
|
|
|
def whenClean
|
|
l=""
|
|
@selection.to_a.each { |i|
|
|
l="#{l} #{i.name}"
|
|
}
|
|
|
|
startTerminal("vdn-clean #{l}", "#{$VDN_PATH}/bin/vdn-clean #{l}", false) if l != ""
|
|
|
|
end
|
|
|
|
def whenHaltAll
|
|
@hosts.each_value { |i|
|
|
if @states[i.name]
|
|
mySystem($VDN_PATH+"/bin/vdn-halt #{i.name} &")
|
|
end
|
|
}
|
|
end
|
|
|
|
def whenKillAll
|
|
@hosts.each_value { |i|
|
|
if @states[i.name]
|
|
mySystem($VDN_PATH+"/bin/vdn-kill -s #{i.name} &")
|
|
end
|
|
}
|
|
end
|
|
|
|
|
|
def whenKill
|
|
@selection.to_a.each { |i|
|
|
if @states[i.name]
|
|
mySystem($VDN_PATH+"/bin/vdn-kill -s #{i.name} &")
|
|
end
|
|
}
|
|
end
|
|
|
|
def startVnc(name)
|
|
Gtk.queue do
|
|
@notebook.set_page(2)
|
|
end
|
|
cmdFifoPath="#{ENV['TMPDIR']}/vdn-vnc-#{ENV['USER']}-#{name}-fifo"
|
|
mySystem("mkfifo #{cmdFifoPath} 2> /dev/null")
|
|
mySystem("chmod 600 #{cmdFifoPath}")
|
|
vncSock="#{ENV['TMPDIR']}/vdn-vnc-#{ENV['USER']}-#{name}-socket"
|
|
=begin
|
|
Thread.new {
|
|
|
|
Gtk.queue do
|
|
label=Gtk::Label.new(name)
|
|
vnc=VncViewer.new(self, label, name, $VDN_PATH, vncSock, cmdFifoPath)
|
|
@hosts[name].vncViewer=vnc
|
|
@consolesNotebook.append_page(vnc, label)
|
|
@consolesNotebook.show_all
|
|
vnc.plug
|
|
@consolesNotebook.set_page(@consolesNotebook.n_pages-1)
|
|
end
|
|
}
|
|
=end
|
|
end
|
|
|
|
|
|
|
|
def startSpiceOld(name)
|
|
Gtk.queue do
|
|
@notebook.set_page(2)
|
|
end
|
|
#cmdFifoPath="#{ENV['TMPDIR']}/vdn-vnc-#{ENV['USER']}-#{name}-fifo"
|
|
#mySystem("mkfifo #{cmdFifoPath} 2> /dev/null")
|
|
#mySystem("chmod 600 #{cmdFifoPath}")
|
|
|
|
Thread.new {
|
|
desc="startSPiceOld"
|
|
$threads.push(desc)
|
|
Gtk.queue do
|
|
label=Gtk::Label.new(name)
|
|
#spice=Gtk::EventBox.new
|
|
spice=SpiceViewer.new(name)
|
|
sleep 2
|
|
#spice=Gtk::EventBox.new
|
|
#@hosts[name].spiceViewer=spice
|
|
#@consolesNotebook.append_page(spice, label)
|
|
|
|
#@consolesNotebook.show_all
|
|
|
|
#spice.plug
|
|
|
|
#@consolesNotebook.set_page(@consolesNotebook.n_pages-1)
|
|
|
|
end
|
|
$threads.delete_at($threads.index(desc))
|
|
}
|
|
end
|
|
|
|
def hostsSorted
|
|
systems=[]
|
|
@hosts.each_value { |i| systems.push(i) }
|
|
systems.sort! { |a,b|
|
|
r=0
|
|
if a.y < b.y+50 && a.y < b.y-50
|
|
r=-1
|
|
elsif a.y > b.y+50 && a.y > b.y-50
|
|
r=1
|
|
elsif a.x < b.x
|
|
r=-1
|
|
elsif a.x > b.x
|
|
r=1
|
|
end
|
|
r
|
|
}
|
|
return systems
|
|
end
|
|
|
|
|
|
def select(m, b)
|
|
|
|
if ! m && b!=3
|
|
@selection.clear
|
|
return
|
|
end
|
|
|
|
case @main.mod
|
|
when "Shift"
|
|
found=false
|
|
last=@selection.array[0]
|
|
return if !last
|
|
sorted=hostsSorted
|
|
il=sorted.index(last)
|
|
im=sorted.index(m)
|
|
|
|
sorted=sorted.reverse if im>il
|
|
sorted.each { |i|
|
|
if i==m
|
|
found=true
|
|
end
|
|
if found
|
|
if i.isSel
|
|
break;
|
|
else
|
|
@selection.add(i)
|
|
end
|
|
|
|
end
|
|
}
|
|
when "Control"
|
|
if m && ! m.isSel
|
|
@selection.add(m)
|
|
else
|
|
@selection.del(m) if b!=3
|
|
end
|
|
|
|
else
|
|
if m && ! m.isSel
|
|
@selection.clear
|
|
@selection.add(m)
|
|
end
|
|
end
|
|
|
|
if b==3
|
|
showMenu
|
|
end
|
|
|
|
end
|
|
|
|
|
|
def parseEvent(w, e)
|
|
case e.class.to_s
|
|
when "Gdk::EventButton"
|
|
if e.event_type == Gdk::Event::Type::BUTTON2_PRESS
|
|
rs=Gdk::Rectangle.new(e.x, e.y, 1, 1)
|
|
|
|
m=nil
|
|
@hosts.each_value { |i|
|
|
x=i.rx; y=i.ry; w=i.rw; h=i.rh
|
|
r=Gdk::Rectangle.new(
|
|
x*@cx+@dx+@bx,
|
|
y*@cy+@dy+@by,
|
|
w*@cx+1, h*@cy+1)
|
|
|
|
m=i if r.intersect(rs)
|
|
break if m
|
|
}
|
|
|
|
elsif e.event_type == Gdk::Event::Type::BUTTON_PRESS
|
|
|
|
rs=Gdk::Rectangle.new(e.x, e.y, 1, 1)
|
|
|
|
m=nil
|
|
@hosts.each_value { |i|
|
|
x=i.rx; y=i.ry; w=i.rw; h=i.rh
|
|
r=Gdk::Rectangle.new(
|
|
x*@cx+@dx+@bx,
|
|
y*@cy+@dy+@by,
|
|
w*@cx+1, h*@cy+1)
|
|
|
|
m=i if r.intersect(rs)
|
|
break if m
|
|
}
|
|
|
|
if m==nil
|
|
@mx=e.x
|
|
@my=e.y
|
|
else
|
|
@mx=@my=nil
|
|
end
|
|
|
|
if e.button == 3
|
|
showMenu
|
|
@mx=@my=nil
|
|
select(m, e.button) if @selection.empty
|
|
|
|
else
|
|
select(m, e.button)
|
|
end
|
|
else
|
|
if @selRec
|
|
undrawSelRec
|
|
end
|
|
@mx=@my=nil
|
|
end
|
|
when "Gdk::EventMotion"
|
|
if @mx
|
|
drawSelRec(@mx, @my, e.x, e.y)
|
|
updateSelRec
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
def updateSelect
|
|
@selection.array.each { |i|
|
|
i.sel(self)
|
|
}
|
|
end
|
|
|
|
|
|
|
|
def updateSelRec
|
|
@hosts.each_value { |i|
|
|
state=false
|
|
x=i.x; y=i.y; w=i.rw; h=i.rh
|
|
_x=x*@cx+@dx+@bx
|
|
_y=y*@cy+@dy+@by
|
|
_w=w*@cx+1
|
|
_h=h*@cy+1
|
|
r=Gdk::Rectangle.new(_x, _y, _w, _h)
|
|
s=@selRec
|
|
if r.intersect(@selRec).to_a==r.to_a
|
|
state=true
|
|
end
|
|
|
|
if state
|
|
@selection.add(i) if ! i.isSel
|
|
else
|
|
@selection.del(i) if i.isSel
|
|
end
|
|
|
|
}
|
|
end
|
|
|
|
|
|
|
|
def drawSelRec(x1, y1, x2, y2)
|
|
return if @gc==nil
|
|
if @selRec
|
|
undrawSelRec
|
|
end
|
|
|
|
if x1>x2
|
|
t=x2; x2=x1; x1=t
|
|
end
|
|
|
|
if y1>y2
|
|
t=y2; y2=y1; y1=t
|
|
end
|
|
|
|
@selRec=Gdk::Rectangle.new(x1, y1, x2-x1, y2-y1)
|
|
|
|
@gc.function = Gdk::GC::XOR
|
|
@gc.fill = Gdk::GC::Fill::SOLID
|
|
@gc.rgb_fg_color = @grey
|
|
@gc.set_line_attributes(1, Gdk::GC::LineStyle::ON_OFF_DASH, Gdk::GC::CapStyle::ROUND, Gdk::GC::JoinStyle::ROUND)
|
|
|
|
return if @area.window==nil
|
|
|
|
@area.window.draw_rectangle(@gc, false, x1, y1, x2-x1, y2-y1)
|
|
@gc.function = Gdk::GC::COPY
|
|
|
|
|
|
end
|
|
|
|
|
|
def undrawSelRec
|
|
return if @gc==nil
|
|
if @selRec
|
|
@gc.function = Gdk::GC::XOR
|
|
@gc.fill = Gdk::GC::Fill::SOLID
|
|
@gc.rgb_fg_color = @grey
|
|
@gc.set_line_attributes(1, Gdk::GC::LineStyle::ON_OFF_DASH, Gdk::GC::CapStyle::ROUND, Gdk::GC::JoinStyle::ROUND)
|
|
|
|
return if @area.window==nil
|
|
|
|
@area.window.draw_rectangle(@gc, false, @selRec.x, @selRec.y, @selRec.width, @selRec.height)
|
|
@gc.function = Gdk::GC::COPY
|
|
|
|
@selRec=nil
|
|
end
|
|
end
|
|
|
|
|
|
def drawBoxs
|
|
@hosts.each { |k,v|
|
|
if @states[k]
|
|
v.draw(self, @green)
|
|
else
|
|
v.draw(self, @red)
|
|
end
|
|
}
|
|
end
|
|
|
|
|
|
def parseInkscape
|
|
|
|
@gw=@gh=nil
|
|
Zlib::GzipReader.open( @graphfile) do |aFile|
|
|
r=false
|
|
x=y=width=height=label=nil
|
|
tx=ty=nil
|
|
|
|
aFile.each_line do |line|
|
|
|
|
case line
|
|
|
|
when /transform="translate/
|
|
|
|
if !tx
|
|
tx=line.chomp.sub(/^.*translate.([-0-9.]+).*$/, '\1').to_i
|
|
ty=line.chomp.sub(/^.*translate.*,([-0-9.]+).*$/, '\1').to_i
|
|
end
|
|
|
|
when /width=/
|
|
if ! @gw
|
|
@gw=line.chomp.sub(/^.*"([-0-9.]+)".*$/, '\1').to_i
|
|
|
|
else
|
|
width=line.gsub(/[^0-9.]/, "").to_i
|
|
end
|
|
|
|
when /height/
|
|
if ! @gh
|
|
@gh=line.chomp.sub(/^.*"([-0-9.]+)".*$/, '\1').to_i
|
|
else
|
|
height=line.gsub(/[^0-9.]/, "").to_i
|
|
end
|
|
|
|
when /<rect/
|
|
|
|
x=y=width=height=label=nil
|
|
r=true
|
|
else
|
|
|
|
next if r==false
|
|
|
|
r=false if line =~ /\/>/
|
|
|
|
|
|
case line
|
|
when /label=/
|
|
label=line.chomp.sub(/^.*"#([^"].*)".*$/, '\1')
|
|
when /x=/
|
|
x=line.gsub(/[^0-9.]/, "").to_i
|
|
when /y=/
|
|
y=line.gsub(/[^0-9.]/, "").to_i
|
|
end
|
|
|
|
if ( !x || !y || !width || !height ) && label!=nil
|
|
$stderr.puts "rec : #{label} incomplet !"
|
|
else
|
|
if label
|
|
@hosts[label]=Host.new(
|
|
label, x+tx, y+ty, width, height)
|
|
@states[label]=false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
def parseGraphviz
|
|
@gw=@gh=tx=ty=gw=gh=nil
|
|
|
|
rw=1.0; rh=1.0
|
|
|
|
svg=RSVG::Handle.new_from_file(@graphfile)
|
|
svg.close
|
|
@gw=svg.width
|
|
@gh=svg.height
|
|
|
|
Zlib::GzipReader.open( @graphfile) do |aFile|
|
|
r=false
|
|
x=y=width=height=label=nil
|
|
|
|
aFile.each_line do |line|
|
|
case line
|
|
when /transform.*translate/
|
|
if !tx
|
|
tx=line.chomp.sub(/^.*translate.([-0-9.]+).*$/, '\1').to_i
|
|
ty=line.chomp.sub(/^.*translate.* ([-0-9.]+).*$/, '\1').to_i
|
|
end
|
|
#when /class=.*node.*title/
|
|
# label=line.chomp.sub(/^.*title>(.*)<.*$/, '\1')
|
|
when /^<title>[^%]*$/
|
|
label=line.chomp.sub(/^.*title>(.*)<.*$/, '\1')
|
|
when /polygon/
|
|
points=line.chomp.sub(/^.*points="(.*)".*$/, '\1')
|
|
points=points.split(" ")
|
|
x1=points[0].sub(/^([-0-9.]+).*$/, '\1').to_i
|
|
y1=points[0].sub(/^[-0-9.]+,([-0-9.]+)$/, '\1').to_i
|
|
x2=points[2].sub(/^([-0-9.]+).*$/, '\1').to_i
|
|
y2=points[2].sub(/^[-0-9.]+,([-0-9.]+)$/, '\1').to_i
|
|
if x1<x2
|
|
x=x1; width=x2-x1
|
|
else
|
|
x=x2; width=x1-x2
|
|
end
|
|
|
|
if y1<y2
|
|
y=y1; height=y2-y1
|
|
else
|
|
y=y2; height=y1-y2
|
|
end
|
|
|
|
if label
|
|
label.gsub!("-", "-")
|
|
@hosts[label]=Host.new(
|
|
label, (x+tx)*rw, (y+ty)*rh, width*rw, height*rh)
|
|
@states[label]=false
|
|
else
|
|
gw=width; gh=height
|
|
rw=@gw*1.0/gw; rh=@gh*1.0/gh
|
|
end
|
|
|
|
end
|
|
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
def close
|
|
|
|
|
|
if @graphTimeout
|
|
Gtk.timeout_remove(@graphTimeout)
|
|
@graphTimeout=nil
|
|
end
|
|
|
|
if @netTimeout
|
|
#p "remove netDetector"
|
|
Gtk.timeout_remove(@netTimeout)
|
|
@netTimeout=nil
|
|
end
|
|
|
|
@notebook.remove_page(1)
|
|
|
|
if @consolesNotebook
|
|
if @consoles
|
|
#@consolesNotebook.remove_page(@consolesNotebook.page_num(@consoles))
|
|
@consoles.close
|
|
@consoles.destroy
|
|
@consoles=nil
|
|
end
|
|
|
|
if @ssh
|
|
|
|
#@notebook.remove_page(@notebook.page_num(@ssh))
|
|
@ssh.close
|
|
@ssh.destroy
|
|
@ssh=nil
|
|
end
|
|
|
|
end
|
|
@consolesNotebook=nil
|
|
@notebook.remove_page(1)
|
|
@notebook.remove_page(1)
|
|
@notebook.set_page(0)
|
|
|
|
@hosts={}
|
|
@states={}
|
|
@graphfile=nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class Host
|
|
attr_reader :rectangle, :rectangleSmall, :name, :isSel
|
|
attr_reader :x, :y, :w, :h
|
|
attr_reader :rx, :ry, :rw, :rh
|
|
attr_accessor :vncViewer, :spiceViewer
|
|
|
|
def initialize(name, x, y, w, h)
|
|
@isSel=false
|
|
@name=name; @x=x; @y=y; @w=w; @h=h
|
|
@rx=@x; @ry=@y; @rw=@w; @rh=@h
|
|
@black = Gdk::Color.parse("black")
|
|
@vncViewer=nil
|
|
@spiceViewer=nil
|
|
end
|
|
|
|
def draw(panel, color)
|
|
|
|
@area=panel.area
|
|
@gc=panel.gc
|
|
|
|
return if !@gc || !panel.cx
|
|
|
|
@gc.function = Gdk::GC::COPY
|
|
@gc.fill = Gdk::GC::Fill::SOLID
|
|
@gc.rgb_fg_color = color
|
|
@gc.set_line_attributes(1, Gdk::GC::LineStyle::SOLID, Gdk::GC::CapStyle::ROUND, Gdk::GC::JoinStyle::ROUND)
|
|
|
|
cx=panel.cx; cy=panel.cy
|
|
dx=panel.dx; dy=panel.dy
|
|
bx=panel.bx; by=panel.by
|
|
|
|
return if @area.window==nil
|
|
|
|
begin
|
|
@area.window.draw_rectangle(@gc, false, @x*cx+dx+bx, @y*cy+dy+by, @w*cx+1, @h*cy+1)
|
|
rescue
|
|
p "Error in draw..."
|
|
p $!
|
|
end
|
|
|
|
@gc.rgb_fg_color = @black
|
|
end
|
|
|
|
def sel(panel)
|
|
color=panel.selColor
|
|
cx=panel.cx; cy=panel.cy
|
|
dx=panel.dx; dy=panel.dy
|
|
bx=panel.bx; by=panel.by
|
|
|
|
@isSel=true
|
|
|
|
@gc.function = Gdk::GC::XOR
|
|
@gc.fill = Gdk::GC::Fill::SOLID
|
|
@gc.rgb_fg_color = color
|
|
@gc.set_line_attributes(1, Gdk::GC::LineStyle::SOLID, Gdk::GC::CapStyle::ROUND, Gdk::GC::JoinStyle::ROUND)
|
|
|
|
|
|
return if @area.window==nil
|
|
|
|
#p "### update draw in sel method"
|
|
|
|
@area.window.draw_rectangle(@gc, true, @x*cx+dx+bx+2, @y*cy+dy+by+2, @w*cx+1-3, @h*cy+1-3)
|
|
@gc.function = Gdk::GC::COPY
|
|
|
|
end
|
|
|
|
def unsel(panel)
|
|
|
|
return if @gc==nil
|
|
color=panel.selColor
|
|
cx=panel.cx; cy=panel.cy
|
|
dx=panel.dx; dy=panel.dy
|
|
bx=panel.bx; by=panel.by
|
|
@isSel=false
|
|
@gc.function = Gdk::GC::XOR
|
|
@gc.fill = Gdk::GC::Fill::SOLID
|
|
@gc.rgb_fg_color = color
|
|
@gc.set_line_attributes(1, Gdk::GC::LineStyle::SOLID, Gdk::GC::CapStyle::ROUND, Gdk::GC::JoinStyle::ROUND)
|
|
|
|
return if @area.window==nil
|
|
|
|
@area.window.draw_rectangle(@gc, true, @x*cx+dx+bx+2, @y*cy+dy+by+2, @w*cx+1-3, @h*cy+1-3)
|
|
@gc.function = Gdk::GC::COPY
|
|
end
|
|
|
|
end
|
|
|
|
|
|
class Selection
|
|
def initialize(panel)
|
|
@sel=[]
|
|
@panel=panel
|
|
|
|
end
|
|
|
|
def add(m)
|
|
@sel.push(m) if ! @sel.include?(m)
|
|
m.sel(@panel)
|
|
@panel.updateMenus
|
|
end
|
|
|
|
def del(m)
|
|
@sel.delete(m)
|
|
m.unsel(@panel)
|
|
@panel.updateMenus
|
|
end
|
|
|
|
def clear
|
|
@sel.each { |i| i.unsel(@panel) }
|
|
@sel=[]
|
|
@panel.updateMenus
|
|
end
|
|
|
|
def array
|
|
return @sel
|
|
end
|
|
|
|
def empty
|
|
return @sel.size==0
|
|
end
|
|
|
|
def to_a
|
|
return @sel
|
|
end
|
|
end
|
|
|
|
class Gtk::Browser < Gtk::VBox
|
|
attr_accessor :banner
|
|
def initialize
|
|
super
|
|
pack_start(@text=Gtk::TextView.new, true, true)
|
|
@text.justification = Gtk::JUSTIFY_CENTER
|
|
@text.cursor_visible=false
|
|
|
|
end
|
|
def location=(url)
|
|
@url=url
|
|
@text.editable=true
|
|
@text.buffer.text="\n"
|
|
|
|
w=Gtk::Image.new(@banner)
|
|
w.show_all
|
|
bold = @text.buffer.create_tag(nil,
|
|
{
|
|
'weight' =>
|
|
Pango::Weight::BOLD
|
|
})
|
|
|
|
iter=@text.buffer.end_iter
|
|
anchor = @text.buffer.create_child_anchor(iter)
|
|
@text.add_child_at_anchor(w, anchor)
|
|
@text.buffer.insert(iter, "\n\nBienvenue !\n\n", bold)
|
|
@text.buffer.insert_at_cursor("\n\n Cliquez sur le bouton ci-dessous pour accéder à la documentation dans votre navigateur : \n\n")
|
|
iter=@text.buffer.end_iter
|
|
anchor = @text.buffer.create_child_anchor(iter)
|
|
b1=Gtk::Button.new("#{@url}")
|
|
b1.show
|
|
b1.signal_connect("clicked") { mySystem("xdg-open #{@url} &") }
|
|
@text.add_child_at_anchor(b1, anchor)
|
|
@text.buffer.insert_at_cursor("\n\n")
|
|
@text.editable=false
|
|
end
|
|
end
|
|
|
|
|
|
### begin: pterms
|
|
|
|
#!/usr/bin/env ruby
|
|
|
|
require 'gtk2'
|
|
|
|
if FileTest.exist?(ENV["VDN_PATH"]+"/distribs/hosts/"+ENV["HOST_RELEASE"]+"/vte.so")
|
|
#puts "load "+ENV["VDN_PATH"]+"/files/"+ENV["HOST_RELEASE"]+"/vte.so"
|
|
require ENV["VDN_PATH"]+"/distribs/hosts/"+ENV["HOST_RELEASE"]+"/vte.so"
|
|
else
|
|
require 'vte'
|
|
end
|
|
|
|
class String
|
|
def to_b; self.downcase=="true" || self=="1" ; end
|
|
end
|
|
|
|
|
|
class Console < Gtk::EventBox
|
|
attr_reader :eventbox, :name, :term, :vte, :isGrouped
|
|
attr_accessor :icoButton, :area, :barea
|
|
attr_accessor :x, :y
|
|
|
|
def initialize(term, stock)
|
|
@term=term
|
|
@panel=@term.panel
|
|
@stock=stock
|
|
super()
|
|
|
|
add(@frame=Gtk::Frame.new)
|
|
@frame.add(@vbox=Gtk::VBox.new)
|
|
@vbox.border_width=2
|
|
@vbox.pack_start(@eventbox=Gtk::EventBox.new,false,false)
|
|
@eventbox.height_request=18
|
|
@eventbox.add(@hbox=Gtk::HBox.new)
|
|
|
|
@hbox.pack_start(@label=Gtk::Label.new(), false, false)
|
|
@hbox.pack_start(f=Gtk::Frame.new, true, true)
|
|
f.shadow_type=Gtk::SHADOW_NONE
|
|
|
|
@bclose=addButton(@hbox, @panel.iclose,
|
|
"Close", "closeConsoleAccel", :whenCloseButton)
|
|
|
|
signal_connect('destroy') { |w| whenDestroy }
|
|
|
|
@vbox.pack_start(@hbox2=Gtk::HBox.new, true, true)
|
|
|
|
@vte=Vte::Terminal.new
|
|
|
|
@vte.signal_connect('child-exited') { |w| whenExited }
|
|
|
|
@vte.signal_connect('contents-changed') { |w|
|
|
Gtk.timeout_add(300) { @update=true; false; }
|
|
}
|
|
|
|
@scrollbar=Gtk::VScrollbar.new(@vte.adjustment)
|
|
|
|
p=props('rightBar').to_b
|
|
@hbox2.pack_start(@scrollbar, false, false) if !p
|
|
@hbox2.pack_start(@vte, true, true)
|
|
@hbox2.pack_start(@scrollbar, false, false) if p
|
|
|
|
signal_connect('enter_notify_event') { |w,e|
|
|
if @panel.props("focusFollowMouse").to_b
|
|
focus
|
|
end
|
|
|
|
}
|
|
|
|
signal_connect('leave-notify-event') { |w,e|
|
|
name="GDK_NOTIFY_ANCESTOR"
|
|
if e.detail.name == name
|
|
deselect(self)
|
|
end
|
|
}
|
|
|
|
|
|
signal_connect('button-press-event') { |w,e| focus }
|
|
|
|
# Button event (focus + paste clipboard)
|
|
|
|
@vte.signal_connect('button-press-event') { |w,e|
|
|
case e.button
|
|
when 1; focus
|
|
when 2; broadcastEvent(e)
|
|
end
|
|
false
|
|
}
|
|
|
|
# Button event (paste clipboard)
|
|
|
|
@vte.signal_connect('button-release-event') { |w,e|
|
|
broadcastEvent(e) if e.button == 2
|
|
}
|
|
|
|
# Key event
|
|
@leftAccel=Gtk::Accelerator.parse(
|
|
@panel.props("switchTermRightAccel"))
|
|
|
|
|
|
init(term)
|
|
end
|
|
|
|
def init(term)
|
|
@term=term
|
|
@pid=nil
|
|
@label.text=@term.name
|
|
|
|
@vte.set_size(80,24)
|
|
@vte.set_word_chars(".a-zA-Z_0-9//-")
|
|
@vte.set_colors(Gdk::Color.parse(props('fgColor')),
|
|
Gdk::Color.parse(props('bgColor')),[])
|
|
@vte.audible_bell=props('audibleBell').to_b
|
|
@vte.visible_bell=props('visibleBell').to_b
|
|
@vte.scrollback_lines=props('scrollbackLines').to_i
|
|
|
|
a=args(term.cmd)
|
|
|
|
#if ENV['GUI_INTERNAL'] == "1"
|
|
# @pid=@vte.fork_command(a[0], a)
|
|
#else
|
|
|
|
#$stderr.puts "a:#{a}"
|
|
|
|
@pid=@vte.fork_command(:argv => a)
|
|
#end
|
|
|
|
show_all
|
|
|
|
@bclose.hide if ! props("canClose").to_b
|
|
setFontArea
|
|
setHeader
|
|
|
|
end
|
|
|
|
def setHeader
|
|
if ! props("header").to_b ||
|
|
! @term.panel.props("globalHeaders").to_b
|
|
@eventbox.height_request=4
|
|
@hbox.hide
|
|
else
|
|
@eventbox.height_request=18
|
|
@hbox.show
|
|
end
|
|
end
|
|
|
|
def props(name)
|
|
@term.props(name)
|
|
end
|
|
|
|
def args(s)
|
|
r=[]
|
|
s.gsub(/'([^']*)'|"([^"]*)"|([^[:space:]]+)/) { |m|
|
|
r.push("#{$1}#{$2}#{$3}")
|
|
}
|
|
return r
|
|
end
|
|
|
|
def addButton(w,p,t,a,handler)
|
|
i=Gtk::Image.new(p)
|
|
w.pack_start(b=Gtk::ToolButton.new(i), false, false)
|
|
|
|
accel=props(a)
|
|
|
|
b.signal_connect('clicked') { |w,e| send(handler) }
|
|
return b
|
|
end
|
|
|
|
def broadcastEvent(e)
|
|
pterms=@term.panel
|
|
panelView=@term.panel
|
|
if @isGrouped && pterms.view.currentPanelView==panelView &&
|
|
self==panelView.selected
|
|
pterms.view.sendEvent(panelView, self, e)
|
|
end
|
|
false
|
|
end
|
|
|
|
def myClampPanel(wlen, adj, min, len)
|
|
value=adj.value
|
|
if min+len > value+wlen
|
|
delta=min+len-(value+wlen)
|
|
adj.value=value+delta
|
|
else
|
|
if min<value
|
|
adj.value=min
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
def clampPanel
|
|
a=allocation; x=a.x; y=a.y
|
|
p=parent.parent
|
|
myClampPanel(p.allocation.height, p.vadjustment, a.y, a.height)
|
|
myClampPanel(p.allocation.width, p.hadjustment, a.x, a.width)
|
|
end
|
|
|
|
def deselect(c)
|
|
return if @term.panel.selected!=c
|
|
color=@term.panel.cnormal
|
|
w=c.eventbox
|
|
w.modify_bg(Gtk::STATE_NORMAL,color) if ! w.destroyed?
|
|
@term.panel.selected=nil
|
|
term.panel.main.main.add_main_accel_group
|
|
end
|
|
|
|
def focus
|
|
@vte.has_focus=true
|
|
@vte.grab_focus
|
|
|
|
selected=@term.panel.selected
|
|
return if selected==self
|
|
|
|
deselect(selected) if selected
|
|
|
|
@term.panel.selected=self
|
|
|
|
color=@term.panel.cselect
|
|
@eventbox.modify_bg(Gtk::STATE_NORMAL,color)
|
|
|
|
|
|
term.panel.main.main.add_consoles_accel_group
|
|
|
|
clampPanel
|
|
end
|
|
|
|
def setFontArea
|
|
setFont(props("gridFont"))
|
|
end
|
|
|
|
def setFont(font)
|
|
@vte.set_font(font, Vte::TerminalAntiAlias::USE_DEFAULT)
|
|
end
|
|
|
|
def whenCloseButton
|
|
whenClose
|
|
end
|
|
|
|
def whenDestroy
|
|
whenClose
|
|
end
|
|
|
|
def whenExited
|
|
whenClose
|
|
end
|
|
|
|
def whenClose
|
|
if @term
|
|
@term.close
|
|
@term.panel.update
|
|
end
|
|
end
|
|
|
|
def close
|
|
return if ! parent # already closed (and stocked)
|
|
|
|
begin
|
|
Process.kill('TERM',@pid) if @pid && (@pid != -1)
|
|
rescue
|
|
end
|
|
|
|
deselect(self)
|
|
|
|
s=@term.panel.selected
|
|
@term.panel.selectTerm(self, "right") if !s||s==self
|
|
deselect(self) if @term.panel.selected==self
|
|
|
|
parent.remove(self)
|
|
|
|
@vte.reset(true, true)
|
|
@stock.push(self)
|
|
@term.panel.update
|
|
end
|
|
end
|
|
|
|
class ConsolesView < Gtk::Frame
|
|
attr_reader :main
|
|
attr_reader :iclose
|
|
attr_reader :cnormal, :cflash, :cselect
|
|
attr_reader :props, :stock, :accelsKeys
|
|
attr_accessor :selected
|
|
def initialize(main, list)
|
|
@main=main
|
|
super()
|
|
@selected=nil
|
|
@terms=[]
|
|
@stock=PtermsStock.new
|
|
@propsStack=[]
|
|
@x=@y=0
|
|
|
|
@props={
|
|
|
|
# Application property
|
|
|
|
"globalHeaders" => "true",
|
|
"focusFollowMouse" => "true",
|
|
|
|
# Main window properties
|
|
"tooltips" => "true",
|
|
|
|
# Panel properties
|
|
|
|
"gridNbCols" => "2",
|
|
|
|
# Terminal properties
|
|
|
|
"inGrid" => "true",
|
|
"gridFont" => "Monospace 8",
|
|
"zoomFont" => "Monospace 10",
|
|
|
|
"header" => "true",
|
|
"canClose" => "true",
|
|
|
|
"minWidth" => "100",
|
|
"minHeight" => "50",
|
|
|
|
"fgColor" => "black",
|
|
"bgColor" => "white",
|
|
|
|
"audibleBell" => "true",
|
|
"visibleBell" => "true",
|
|
"scrollbackLines" => "1000",
|
|
"rightBar" => "false",
|
|
|
|
# Accelerators
|
|
|
|
# Main window accels
|
|
"quitAccel" => "<Ctrl>x",
|
|
"toggleHeadersAccel" => "<Alt>h",
|
|
"toggleButtonsTextsAccel" => "<Alt>t",
|
|
"toggleFocusFollowMouseAccel" => "<Alt>f",
|
|
|
|
"switchTermLeftAccel" => "<Shift><Alt>Left",
|
|
"switchTermRightAccel" => "<Shift><Alt>Right",
|
|
"switchTermUpAccel" => "<Shift><Alt>Up",
|
|
"switchTermDownAccel" => "<Shift><Alt>Down",
|
|
|
|
"increaseZoomAccel" => "<Shift><Alt>KP_Add",
|
|
"decreaseZoomAccel" => "<Shift><Alt>KP_Subtract",
|
|
|
|
# Terminal accels
|
|
"groupToggleAccel" => "<Ctrl>g",
|
|
"moveAccel" => "<Ctrl>m",
|
|
"closeConsoleAccel" => "<Ctrl>q",
|
|
|
|
}
|
|
@accelsKeys=[]
|
|
@props.keys.each { |p|
|
|
next if (p=~/Accel/) == nil
|
|
@accelsKeys.push(Gtk::Accelerator.parse(props(p)))
|
|
}
|
|
# build small pixbufs (used by consoles)
|
|
|
|
w=9; h=9
|
|
@iclose=createPixbuf(Gtk::Stock::CLOSE, w, h)
|
|
|
|
@cnormal=Gdk::Color.parse("#E8E8E8")
|
|
@cselect=Gdk::Color.parse("#84D7E5")
|
|
@cflash=Gdk::Color.parse("#ff4242")
|
|
add(@grid=Gtk::ScrolledWindow.new)
|
|
@grid.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
|
|
@grid.add_with_viewport(@grid=Gtk::Table.new(1,1))
|
|
@grid.homogeneous=false
|
|
end
|
|
def props(name)
|
|
raise "Invalid property : #{name}" if ! @props[name]
|
|
@props[name]
|
|
end
|
|
def setProps(name, value)
|
|
raise "Invalid property : #{name}" if ! @props[name]
|
|
@props[name]=value
|
|
end
|
|
def createPixbuf(t,w,h)
|
|
return render_icon(t,s=Gtk::IconSize::MENU).scale(w, h)
|
|
end
|
|
def getPropsDup
|
|
return @props.dup
|
|
end
|
|
def addToGrid(widget, x, y)
|
|
@grid.attach(widget, x, x+1, y, y+1,
|
|
Gtk::EXPAND|Gtk::FILL,
|
|
Gtk::EXPAND|Gtk::FILL, 1, 1) if ! widget.parent
|
|
end
|
|
def selectTerm(c, direction)
|
|
end
|
|
def update
|
|
@terms.each { |t| redraw(t.view.vte) if t.view }
|
|
end
|
|
|
|
def redraw(widget)
|
|
Gtk.timeout_add(200) {
|
|
begin
|
|
widget.queue_draw_area(0, 0, 10000, 10000)
|
|
rescue
|
|
end
|
|
false
|
|
}
|
|
end
|
|
def addTerm(name, cmd)
|
|
|
|
#p "addTerm : #{name} #{cmd}"
|
|
|
|
@terms.push(t=Term.new(self, name, cmd))
|
|
n=props("gridNbCols").to_i
|
|
m=0
|
|
if ! @grid.children.empty?
|
|
@grid.children.each { |i|
|
|
x=i.term.x
|
|
y=i.term.y
|
|
if y*n+x > m
|
|
m=y*n+x
|
|
end
|
|
}
|
|
@y=m/n
|
|
@x=m%n+1
|
|
else
|
|
@x=@y=0
|
|
end
|
|
if @x >= n
|
|
@y=@y+1
|
|
@x=0
|
|
end
|
|
t.build(@x,@y)
|
|
update
|
|
redraw(t.view.vte)
|
|
@x=@x+1
|
|
if @x >= props("gridNbCols").to_i
|
|
@x=0; @y=@y+1
|
|
end
|
|
end
|
|
|
|
def close
|
|
@terms.each { |t|
|
|
t.close
|
|
}
|
|
end
|
|
end
|
|
|
|
class Term
|
|
attr_reader :name, :cmd, :panel
|
|
attr_reader :x, :y
|
|
attr_accessor :view
|
|
|
|
def initialize(panel, name, cmd)
|
|
@panel=panel
|
|
@props=panel.getPropsDup if panel
|
|
@name=name
|
|
@cmd=cmd
|
|
@view=nil
|
|
end
|
|
|
|
def props(name)
|
|
raise "Invalid property : #{name}" if ! @props[name]
|
|
@props[name]
|
|
end
|
|
|
|
def build(x,y)
|
|
@x=x; @y=y
|
|
@view=@panel.stock.pop(self)
|
|
@panel.addToGrid(@view, x, y)
|
|
w=@panel.props("minWidth").to_i
|
|
h=@panel.props("minHeight").to_i
|
|
@view.vte.set_size_request(w,h)
|
|
end
|
|
|
|
def close
|
|
@view.close if @view
|
|
@view=nil
|
|
end
|
|
end
|
|
|
|
|
|
class PtermsStock
|
|
def initialize
|
|
@stock=[]
|
|
end
|
|
|
|
def pop(term)
|
|
c=@stock.pop
|
|
if !c
|
|
c=Console.new(term, self)
|
|
else
|
|
c.init(term)
|
|
end
|
|
return c
|
|
end
|
|
|
|
def push(console)
|
|
@stock.push(console)
|
|
end
|
|
end
|
|
|
|
class ConsolesPanel < Gtk::EventBox
|
|
attr_reader :main
|
|
|
|
def initialize(main, cmd, list="", comment="")
|
|
@main=main
|
|
super()
|
|
@cmd=cmd
|
|
@list=list
|
|
@cv=ConsolesView.new(@main, list).show_all
|
|
add(@vbox=Gtk::VBox.new)
|
|
@comment=comment
|
|
|
|
|
|
signal_connect('leave-notify-event') { |w,e|
|
|
selected=@cv.selected
|
|
selected.deselect(selected) if selected
|
|
}
|
|
|
|
if @comment != ""
|
|
@vbox.pack_start(Gtk::Label.new(@comment), false, false)
|
|
end
|
|
|
|
@vbox.pack_start(@hbox=Gtk::HBox.new, false, false)
|
|
@hbox.pack_start(@toolbar=Gtk::HBox.new, true, true)
|
|
|
|
@vbox.add(@cv)
|
|
@cv.focus=true
|
|
|
|
|
|
#initBar
|
|
|
|
end
|
|
|
|
def addTerm(name, cmd=nil)
|
|
|
|
|
|
#p "addTerm name:#{name} cmd:#{cmd}"
|
|
cmd=@cmd+name if cmd == nil
|
|
#p "addTerm name:#{name} cmd:#{cmd}"
|
|
@cv.addTerm(name, cmd)
|
|
end
|
|
|
|
def setProps(name, value)
|
|
@cv.setProps(name, value)
|
|
end
|
|
|
|
def close
|
|
#p "close:cv:#{@cv}"
|
|
@cv.close
|
|
end
|
|
end
|
|
|
|
class SshPanel < ConsolesPanel
|
|
|
|
def initialize(main, cmd, list="", comment="")
|
|
super(main, cmd, list, comment)
|
|
end
|
|
|
|
def addTerm(name, cmd=nil)
|
|
#p "addTerm ssh:cv:#{@cv}"
|
|
user=@main.net.combo.active_text
|
|
#p "addTerm name:#{name} cmd:#{cmd}"
|
|
cmd=@cmd+user+"@"+name if cmd == nil
|
|
#p "addTerm name:#{name} cmd:#{cmd}"
|
|
@cv.addTerm(name, cmd)
|
|
end
|
|
|
|
end
|
|
|
|
def startNet
|
|
if ! $main
|
|
|
|
#p "Create network window"
|
|
net=Vdn.new
|
|
|
|
$main=net
|
|
net.startListener
|
|
|
|
trap("TERM") { r=net.whenQuit; Gtk::main_quit if r }
|
|
else
|
|
$main.clean
|
|
$main.open
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
### end: pterm
|
|
|
|
# main
|
|
|
|
#GC.disable
|
|
|
|
#p "start GC"
|
|
#$lock=true
|
|
|
|
#sleep 0.2
|
|
#GC.enable
|
|
#GC.start
|
|
#GC.disable
|
|
|
|
#$lock=false
|
|
#p "disable GC"
|
|
|
|
ENV['VDN_GUI']="1"
|
|
#puts "ENV['VDN_GUI']:#{ENV['VDN_GUI']}"
|
|
|
|
|
|
$LOG_FIFO = File.open("#{ENV['TMPDIR']}/vdn-#{ENV['USER']}-gui-log", "r+")
|
|
|
|
$VDN_PATH=File.dirname($0)
|
|
$VDN_PATH=File.dirname($VDN_PATH)
|
|
|
|
#require "#{$VDN_PATH}/bin/vdn-gui-pterms.rb"
|
|
#require "#{$VDN_PATH}/bin/vnc-viewer/vdn-vnc-viewer-lib.rb"
|
|
#require "#{$VDN_PATH}/bin/vdn-spice-viewer-lib.rb"
|
|
|
|
fifo="#{ENV['TMPDIR']}/vdn-gui-#{ENV['USER']}-fifo-ctrl"
|
|
#if File.exist?(fifo)
|
|
# mySystem("rm #{fifo}")
|
|
#end
|
|
|
|
startNet
|
|
|
|
Gtk.main_with_queue(100)
|