2009-12-19 17:30:00 +00:00
|
|
|
package App::ClusterSSH;
|
|
|
|
|
|
|
|
use 5.008.004;
|
|
|
|
use warnings;
|
|
|
|
use strict;
|
2014-08-10 10:36:22 +01:00
|
|
|
use version; our $VERSION = version->new('4.03_02');
|
2010-06-03 19:03:58 +01:00
|
|
|
|
|
|
|
use Carp;
|
|
|
|
|
|
|
|
use base qw/ App::ClusterSSH::Base /;
|
2010-06-18 23:17:42 +01:00
|
|
|
use App::ClusterSSH::Host;
|
2011-07-21 08:23:49 +01:00
|
|
|
use App::ClusterSSH::Config;
|
2011-08-31 21:01:12 +01:00
|
|
|
use App::ClusterSSH::Helper;
|
2011-11-21 22:03:54 +00:00
|
|
|
use App::ClusterSSH::Cluster;
|
2014-05-17 17:32:03 +01:00
|
|
|
use App::ClusterSSH::Getopt;
|
2011-08-31 21:01:12 +01:00
|
|
|
|
|
|
|
use FindBin qw($Script);
|
2010-06-03 19:03:58 +01:00
|
|
|
|
|
|
|
use POSIX ":sys_wait_h";
|
2010-06-18 22:10:33 +01:00
|
|
|
use POSIX qw/:sys_wait_h strftime mkfifo/;
|
|
|
|
use File::Temp qw/:POSIX/;
|
|
|
|
use Fcntl;
|
|
|
|
use Tk 800.022;
|
|
|
|
use Tk::Xlib;
|
|
|
|
use Tk::ROText;
|
|
|
|
require Tk::Dialog;
|
|
|
|
require Tk::LabEntry;
|
|
|
|
use X11::Protocol;
|
|
|
|
use X11::Protocol::Constants qw/ Shift Mod5 ShiftMask /;
|
|
|
|
use vars qw/ %keysymtocode %keycodetosym /;
|
|
|
|
use X11::Keysyms '%keysymtocode', 'MISCELLANY', 'XKB_KEYS', '3270', 'LATIN1',
|
|
|
|
'LATIN2', 'LATIN3', 'LATIN4', 'KATAKANA', 'ARABIC', 'CYRILLIC', 'GREEK',
|
|
|
|
'TECHNICAL', 'SPECIAL', 'PUBLISHING', 'APL', 'HEBREW', 'THAI', 'KOREAN';
|
|
|
|
use File::Basename;
|
|
|
|
use Net::hostent;
|
|
|
|
use Carp;
|
|
|
|
use Sys::Hostname;
|
|
|
|
use English;
|
2010-09-10 16:00:01 +01:00
|
|
|
use Socket;
|
2010-06-03 19:03:58 +01:00
|
|
|
|
|
|
|
# Notes on general order of processing
|
|
|
|
#
|
|
|
|
# parse cmd line options for extra config files
|
|
|
|
# load system configuration files
|
|
|
|
# load cfg files from options
|
|
|
|
# overlay rest of cmd line args onto options
|
|
|
|
# record all clusters
|
2014-02-17 15:39:20 -08:00
|
|
|
# parse given tags/hostnames and resolve to connections
|
2010-06-03 19:03:58 +01:00
|
|
|
# open terminals
|
|
|
|
# optionally open console if required
|
|
|
|
|
|
|
|
sub new {
|
|
|
|
my ( $class, %args ) = @_;
|
|
|
|
|
|
|
|
my $self = $class->SUPER::new(%args);
|
|
|
|
|
2014-07-05 20:25:14 +01:00
|
|
|
$self->{cluster} = App::ClusterSSH::Cluster->new( parent => $self, );
|
2014-06-28 11:40:00 +01:00
|
|
|
$self->{config} = App::ClusterSSH::Config->new( parent => $self, );
|
|
|
|
$self->{helper} = App::ClusterSSH::Helper->new( parent => $self, );
|
|
|
|
$self->{options} = App::ClusterSSH::Getopt->new( parent => $self, );
|
2011-07-21 08:23:49 +01:00
|
|
|
|
2010-06-03 19:03:58 +01:00
|
|
|
# catch and reap any zombies
|
2014-06-21 08:30:23 +01:00
|
|
|
$SIG{CHLD} = sub {
|
|
|
|
my $kid;
|
|
|
|
do {
|
|
|
|
$kid = waitpid( -1, WNOHANG );
|
|
|
|
$self->debug( 2, "REAPER currently returns: $kid" );
|
|
|
|
} until ( $kid == -1 || $kid == 0 );
|
|
|
|
};
|
2010-06-03 19:03:58 +01:00
|
|
|
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
2011-07-21 08:23:49 +01:00
|
|
|
sub config {
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{config};
|
|
|
|
}
|
|
|
|
|
2011-11-21 22:03:54 +00:00
|
|
|
sub cluster {
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{cluster};
|
|
|
|
}
|
|
|
|
|
2011-08-31 21:01:12 +01:00
|
|
|
sub helper {
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{helper};
|
|
|
|
}
|
|
|
|
|
2014-05-17 17:32:03 +01:00
|
|
|
sub options {
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{options};
|
|
|
|
}
|
|
|
|
|
|
|
|
sub getopts {
|
|
|
|
my ($self) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
return $self->options->getopts;
|
2014-05-17 17:32:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub add_option {
|
2014-06-28 11:40:00 +01:00
|
|
|
my ( $self, %args ) = @_;
|
2014-05-17 17:32:03 +01:00
|
|
|
return $self->{options}->add_option(%args);
|
2010-06-03 19:03:58 +01:00
|
|
|
}
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2013-02-15 08:26:41 +00:00
|
|
|
my %windows; # hash for all window definitions
|
|
|
|
my %menus; # hash for all menu definitions
|
|
|
|
my @servers; # array of servers provided on cmdline
|
|
|
|
my %servers; # hash of server cx info
|
2010-06-18 22:10:33 +01:00
|
|
|
my $xdisplay;
|
|
|
|
my %keyboardmap;
|
|
|
|
my $sysconfigdir = "/etc";
|
|
|
|
my %ssh_hostnames;
|
|
|
|
|
|
|
|
$keysymtocode{unknown_sym} = 0xFFFFFF; # put in a default "unknown" entry
|
|
|
|
$keysymtocode{EuroSign}
|
|
|
|
= 0x20AC; # Euro sign - missing from X11::Protocol::Keysyms
|
|
|
|
|
|
|
|
# and also map it the other way
|
|
|
|
%keycodetosym = reverse %keysymtocode;
|
|
|
|
|
|
|
|
# Set up UTF-8 on STDOUT
|
|
|
|
binmode STDOUT, ":utf8";
|
|
|
|
|
|
|
|
#use bytes;
|
|
|
|
|
|
|
|
### all sub-routines ###
|
|
|
|
|
|
|
|
# Pick a color based on a string.
|
|
|
|
sub pick_color {
|
|
|
|
my ($string) = @_;
|
|
|
|
my @components = qw(AA BB CC EE);
|
|
|
|
my $color = 0;
|
|
|
|
for ( my $i = 0; $i < length($string); $i++ ) {
|
|
|
|
$color += ord( substr( $string, $i, 1 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
srand($color);
|
|
|
|
my $ans = '\\#';
|
|
|
|
$ans .= $components[ int( 4 * rand() ) ];
|
|
|
|
$ans .= $components[ int( 4 * rand() ) ];
|
|
|
|
$ans .= $components[ int( 4 * rand() ) ];
|
|
|
|
return $ans;
|
|
|
|
}
|
|
|
|
|
|
|
|
# close a specific host session
|
|
|
|
sub terminate_host($) {
|
2014-06-28 11:40:00 +01:00
|
|
|
my ( $self, $svr ) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Killing session for $svr" );
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( !$servers{$svr} ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Session for $svr not found" );
|
2010-06-18 22:10:33 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Killing process $servers{$svr}{pid}" );
|
2010-06-18 22:10:33 +01:00
|
|
|
kill( 9, $servers{$svr}{pid} ) if kill( 0, $servers{$svr}{pid} );
|
|
|
|
delete( $servers{$svr} );
|
2014-06-21 08:30:23 +01:00
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# catch_all exit routine that should always be used
|
|
|
|
sub exit_prog() {
|
2014-06-21 08:30:23 +01:00
|
|
|
my ($self) = @_;
|
|
|
|
$self->debug( 3, "Exiting via normal routine" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-02-17 15:39:20 -08:00
|
|
|
# for each of the client windows, send a kill.
|
|
|
|
# to make sure we catch all children, even when they haven't
|
|
|
|
# finished starting or received the kill signal, do it like this
|
2010-06-18 22:10:33 +01:00
|
|
|
while (%servers) {
|
|
|
|
foreach my $svr ( keys(%servers) ) {
|
2014-07-05 20:25:14 +01:00
|
|
|
$self->terminate_host($svr);
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub evaluate_commands {
|
2011-11-17 22:53:06 +00:00
|
|
|
my ($self) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
my ( $return, $user, $port, $host );
|
|
|
|
|
|
|
|
# break apart the given host string to check for user or port configs
|
2014-06-28 11:40:00 +01:00
|
|
|
my $evaluate = $self->options->evaluate;
|
|
|
|
print "{evaluate}=", $evaluate, "\n";
|
2014-06-28 11:39:28 +01:00
|
|
|
$user = $1 if ( ${evaluate} =~ s/^(.*)@// );
|
|
|
|
$port = $1 if ( ${evaluate} =~ s/:(\w+)$// );
|
|
|
|
$host = ${evaluate};
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$user = $user ? "-l $user" : "";
|
2011-11-17 22:53:06 +00:00
|
|
|
if ( $self->config->{comms} eq "telnet" ) {
|
|
|
|
$port = $port ? " $port" : "";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$port = $port ? "-p $port" : "";
|
|
|
|
}
|
|
|
|
|
|
|
|
print STDERR "Testing terminal - running command:\n";
|
|
|
|
|
|
|
|
my $command = "$^X -e 'print \"Base terminal test\n\"; sleep 2'";
|
|
|
|
|
|
|
|
my $terminal_command = join( ' ',
|
|
|
|
$self->config->{terminal},
|
|
|
|
$self->config->{terminal_allow_send_events}, "-e " );
|
|
|
|
|
|
|
|
my $run_command = "$terminal_command $command";
|
|
|
|
|
|
|
|
print STDERR $run_command, $/;
|
|
|
|
|
|
|
|
system($run_command);
|
|
|
|
print STDERR "\nTesting comms - running command:\n";
|
|
|
|
|
|
|
|
my $comms_command = join( ' ',
|
|
|
|
$self->config->{ $self->config->{comms} },
|
|
|
|
$self->config->{ $self->config->{comms} . "_args" } );
|
|
|
|
|
|
|
|
if ( $self->config->{comms} eq "telnet" ) {
|
|
|
|
$comms_command .= " $host $port";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$comms_command
|
|
|
|
.= " $user $port $host hostname ; echo Got hostname via ssh; sleep 2";
|
|
|
|
}
|
|
|
|
|
|
|
|
print STDERR $comms_command, $/;
|
|
|
|
|
|
|
|
system($comms_command);
|
|
|
|
|
|
|
|
$run_command = "$terminal_command '$comms_command'";
|
|
|
|
print STDERR $run_command, $/;
|
|
|
|
|
|
|
|
system($run_command);
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->exit_prog;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub load_keyboard_map() {
|
2014-06-21 08:30:23 +01:00
|
|
|
my ($self) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# load up the keyboard map to convert keysyms to keyboardmap
|
|
|
|
my $min = $xdisplay->{min_keycode};
|
|
|
|
my $count = $xdisplay->{max_keycode} - $min;
|
|
|
|
my @keyboard = $xdisplay->GetKeyboardMapping( $min, $count );
|
|
|
|
|
|
|
|
# @keyboard arry
|
|
|
|
# 0 = plain key
|
|
|
|
# 1 = with shift
|
|
|
|
# 2 = with Alt-GR
|
|
|
|
# 3 = with shift + AltGr
|
|
|
|
# 4 = same as 2 - control/alt?
|
|
|
|
# 5 = same as 3 - shift-control-alt?
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 1, "Loading keymaps and keycodes" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2013-02-15 08:26:41 +00:00
|
|
|
my %keyboard_modifier_priority = (
|
|
|
|
'sa' => 3, # lowest
|
|
|
|
'a' => 2,
|
|
|
|
's' => 1,
|
|
|
|
'n' => 0, # highest
|
|
|
|
);
|
|
|
|
|
|
|
|
my %keyboard_stringlike_modifiers = reverse %keyboard_modifier_priority;
|
|
|
|
|
|
|
|
# try to associate $keyboard=X11->GetKeyboardMapping table with X11::Keysyms
|
|
|
|
foreach my $i ( 0 .. $#keyboard ) {
|
|
|
|
for my $modifier ( 0 .. 3 ) {
|
2014-01-04 15:07:34 +00:00
|
|
|
if ( defined( $keyboard[$i][$modifier] )
|
|
|
|
&& defined( $keycodetosym{ $keyboard[$i][$modifier] } ) )
|
|
|
|
{
|
2013-02-15 08:26:41 +00:00
|
|
|
|
|
|
|
# keyboard layout contains the keycode at $modifier level
|
|
|
|
if (defined(
|
|
|
|
$keyboardmap{ $keycodetosym{ $keyboard[$i][$modifier]
|
2014-01-13 18:44:12 +00:00
|
|
|
} }
|
2013-02-15 08:26:41 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
|
|
|
|
# we already have a mapping, let's see whether current one is better (lower shift state)
|
|
|
|
my ( $mod_code, $key_code )
|
|
|
|
= $keyboardmap{ $keycodetosym{ $keyboard[$i]
|
|
|
|
[$modifier] } } =~ /^(\D+)(\d+)$/;
|
|
|
|
|
|
|
|
# it is not easy to get around our own alien logic storing modifiers ;-)
|
|
|
|
if ( $modifier < $keyboard_modifier_priority{$mod_code} )
|
|
|
|
{
|
|
|
|
|
|
|
|
# YES! current keycode have priority over old one (phew!)
|
|
|
|
$keyboardmap{ $keycodetosym{ $keyboard[$i][$modifier]
|
|
|
|
} }
|
|
|
|
= $keyboard_stringlike_modifiers{$modifier}
|
|
|
|
. ( $i + $min );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# we don't yet have a mapping... piece of cake!
|
|
|
|
$keyboardmap{ $keycodetosym{ $keyboard[$i][$modifier] } }
|
|
|
|
= $keyboard_stringlike_modifiers{$modifier}
|
|
|
|
. ( $i + $min );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# we didn't get the code from X11::Keysyms
|
2014-01-04 15:07:34 +00:00
|
|
|
if ( defined( $keyboard[$i][$modifier] )
|
|
|
|
&& $keyboard[$i][$modifier] != 0 )
|
|
|
|
{
|
2013-02-15 08:26:41 +00:00
|
|
|
|
|
|
|
# ignore code=0
|
2014-06-28 11:40:00 +01:00
|
|
|
$self->debug(
|
|
|
|
2,
|
|
|
|
"Unknown keycode ",
|
|
|
|
$keyboard[$i][$modifier]
|
|
|
|
);
|
2013-02-15 08:26:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-02-14 21:12:40 +00:00
|
|
|
|
2014-02-17 15:39:20 -08:00
|
|
|
# don't know these two key combs yet...
|
2013-02-14 21:12:40 +00:00
|
|
|
#$keyboardmap{ $keycodetosym { $keyboard[$_][4] } } = $_ + $min;
|
|
|
|
#$keyboardmap{ $keycodetosym { $keyboard[$_][5] } } = $_ + $min;
|
2013-02-15 08:26:41 +00:00
|
|
|
|
2010-06-18 22:10:33 +01:00
|
|
|
#print "$_ => $keyboardmap{$_}\n" foreach(sort(keys(%keyboardmap)));
|
|
|
|
#print "keysymtocode: $keysymtocode{o}\n";
|
|
|
|
#die;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub get_keycode_state($) {
|
2014-06-28 11:40:00 +01:00
|
|
|
my ( $self, $keysym ) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
$keyboardmap{$keysym} =~ m/^(\D+)(\d+)$/;
|
|
|
|
my ( $state, $code ) = ( $1, $2 );
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "keyboardmap=:", $keyboardmap{$keysym}, ":" );
|
|
|
|
$self->debug( 2, "state=$state, code=$code" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
SWITCH: for ($state) {
|
|
|
|
/^n$/ && do {
|
|
|
|
$state = 0;
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
/^s$/ && do {
|
|
|
|
$state = Shift();
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
/^a$/ && do {
|
|
|
|
$state = Mod5();
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
/^sa$/ && do {
|
|
|
|
$state = Shift() + Mod5();
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
|
|
|
|
die("Should never reach here");
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "returning state=:$state: code=:$code:" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
return ( $state, $code );
|
|
|
|
}
|
|
|
|
|
|
|
|
sub resolve_names(@) {
|
2011-11-18 22:31:12 +00:00
|
|
|
my ( $self, @servers ) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, 'Resolving cluster names: started' );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
foreach (@servers) {
|
|
|
|
my $dirty = $_;
|
|
|
|
my $username = q{};
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, 'Checking tag ', $_ );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
if ( $dirty =~ s/^(.*)@// ) {
|
|
|
|
$username = $1;
|
|
|
|
}
|
2013-03-19 18:07:39 +00:00
|
|
|
|
|
|
|
my @tag_list = $self->cluster->get_tag($dirty);
|
|
|
|
|
2011-11-18 22:31:12 +00:00
|
|
|
if ( $self->config->{use_all_a_records}
|
2010-09-10 16:00:01 +01:00
|
|
|
&& $dirty !~ m/^(\d{1,3}\.?){4}$/
|
2013-03-25 13:13:03 +00:00
|
|
|
&& !@tag_list )
|
2010-09-10 16:00:01 +01:00
|
|
|
{
|
|
|
|
my $hostobj = gethostbyname($dirty);
|
|
|
|
if ( defined($hostobj) ) {
|
|
|
|
my @alladdrs = map { inet_ntoa($_) } @{ $hostobj->addr_list };
|
2014-05-13 15:22:18 +01:00
|
|
|
$self->cluster->register_tag( $dirty, @alladdrs );
|
2010-09-10 16:00:01 +01:00
|
|
|
if ( $#alladdrs > 0 ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, 'Expanded to ',
|
2014-06-28 11:40:00 +01:00
|
|
|
join( ' ', $self->cluster->get_tag($dirty) ) );
|
2014-05-13 15:22:18 +01:00
|
|
|
@tag_list = $self->cluster->get_tag($dirty);
|
2010-09-10 16:00:01 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-05-13 15:22:18 +01:00
|
|
|
# don't expand if there is only one record found
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, 'Only one A record' );
|
2010-09-10 16:00:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-25 13:13:03 +00:00
|
|
|
if (@tag_list) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, '... it is a cluster' );
|
2013-03-25 13:13:03 +00:00
|
|
|
foreach my $node (@tag_list) {
|
2010-06-18 22:10:33 +01:00
|
|
|
if ($username) {
|
|
|
|
$node =~ s/^(.*)@//;
|
|
|
|
$node = $username . '@' . $node;
|
|
|
|
}
|
|
|
|
push( @servers, $node );
|
|
|
|
}
|
|
|
|
$_ = q{};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-25 13:13:03 +00:00
|
|
|
# now run everything through the external command, if one is defined
|
|
|
|
if ( $self->config->{external_cluster_command} ) {
|
|
|
|
$self->debug( 4, 'External cluster command defined' );
|
|
|
|
|
|
|
|
# use a second array here in case of failure so previously worked
|
|
|
|
# out entries are not lost
|
|
|
|
my @new_servers;
|
|
|
|
eval {
|
|
|
|
@new_servers
|
2014-07-05 20:25:14 +01:00
|
|
|
= $self->cluster->get_external_clusters( @servers );
|
2013-03-25 13:13:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if ($@) {
|
2013-04-15 21:34:05 +01:00
|
|
|
warn $@, $/;
|
2013-03-25 13:13:03 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
@servers = @new_servers;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-18 22:10:33 +01:00
|
|
|
# now clean the array up
|
|
|
|
@servers = grep { $_ !~ m/^$/ } @servers;
|
|
|
|
|
2013-03-25 13:13:03 +00:00
|
|
|
if ( $self->config->{unique_servers} ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, 'removing duplicate server names' );
|
2013-03-25 13:13:03 +00:00
|
|
|
@servers = remove_repeated_servers(@servers);
|
2013-02-27 10:26:05 +00:00
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, 'leaving with ', $_ ) foreach (@servers);
|
|
|
|
$self->debug( 2, 'Resolving cluster names: completed' );
|
2010-06-18 22:10:33 +01:00
|
|
|
return (@servers);
|
|
|
|
}
|
|
|
|
|
2013-02-27 10:26:05 +00:00
|
|
|
sub remove_repeated_servers {
|
2013-03-25 13:13:03 +00:00
|
|
|
my %all = ();
|
|
|
|
@all{@_} = 1;
|
|
|
|
return ( keys %all );
|
2013-02-27 10:26:05 +00:00
|
|
|
}
|
|
|
|
|
2010-06-18 22:10:33 +01:00
|
|
|
sub change_main_window_title() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
my $number = keys(%servers);
|
2011-07-28 10:23:49 +01:00
|
|
|
$windows{main_window}->title( $self->config->{title} . " [$number]" );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub show_history() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
|
|
|
if ( $self->config->{show_history} ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$windows{history}->packForget();
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{show_history} = 0;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
$windows{history}->pack(
|
|
|
|
-fill => "x",
|
|
|
|
-expand => 1,
|
|
|
|
);
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{show_history} = 1;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub update_display_text($) {
|
2011-11-17 22:53:06 +00:00
|
|
|
my ( $self, $char ) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
return if ( !$self->config->{show_history} );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Dropping :$char: into display" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
SWITCH: {
|
|
|
|
foreach ($char) {
|
|
|
|
/^Return$/ && do {
|
|
|
|
$windows{history}->insert( 'end', "\n" );
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
|
|
|
|
/^BackSpace$/ && do {
|
|
|
|
$windows{history}->delete('end - 2 chars');
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
|
|
|
|
/^(:?Shift|Control|Alt)_(:?R|L)$/ && do {
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
|
|
|
|
length($char) > 1 && do {
|
|
|
|
$windows{history}
|
|
|
|
->insert( 'end', chr( $keysymtocode{$char} ) )
|
|
|
|
if ( $keysymtocode{$char} );
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
|
|
|
|
do {
|
|
|
|
$windows{history}->insert( 'end', $char );
|
|
|
|
last SWITCH;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2011-07-28 10:23:49 +01:00
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub send_text($@) {
|
2014-01-13 18:44:12 +00:00
|
|
|
my $self = shift;
|
|
|
|
my $svr = shift;
|
2010-06-18 22:10:33 +01:00
|
|
|
my $text = join( "", @_ );
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "servers{$svr}{wid}=$servers{$svr}{wid}" );
|
|
|
|
$self->debug( 3, "Sending to '$svr' text:$text:" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# command macro substitution
|
2014-01-13 18:44:12 +00:00
|
|
|
if ( $self->config->{macros_enabled} eq 'yes' ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-01-13 18:44:12 +00:00
|
|
|
# $svr contains a trailing space here, so ensure its stripped off
|
|
|
|
{
|
|
|
|
my $macro_servername = $self->config->{macro_servername};
|
|
|
|
my $servername = $svr;
|
|
|
|
$servername =~ s/\s+//;
|
|
|
|
$text =~ s/$macro_servername/$servername/xsmg;
|
|
|
|
}
|
|
|
|
$text =~ s/%h/hostname()/xsmeg;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-01-13 18:44:12 +00:00
|
|
|
# use connection username, else default to current username
|
|
|
|
{
|
|
|
|
my $macro_username = $self->config->{macro_username};
|
|
|
|
my $username = $servers{$svr}{username};
|
|
|
|
$username ||= getpwuid($UID);
|
|
|
|
$text =~ s/$macro_username/$username/xsmg;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
my $macro_newline = $self->config->{macro_newline};
|
|
|
|
$text =~ s/$macro_newline/\n/xsmg;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
my $macro_version = $self->config->{macro_version};
|
|
|
|
$text =~ s/$macro_version/$VERSION/xsmg;
|
|
|
|
}
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
foreach my $char ( split( //, $text ) ) {
|
|
|
|
next if ( !defined($char) );
|
|
|
|
my $ord = ord($char);
|
|
|
|
$ord = 65293 if ( $ord == 10 ); # convert 'Return' to sym
|
|
|
|
|
|
|
|
if ( !defined( $keycodetosym{$ord} ) ) {
|
|
|
|
warn("Unknown character in xmodmap keytable: $char ($ord)\n");
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
my $keysym = $keycodetosym{$ord};
|
|
|
|
my $keycode = $keysymtocode{$keysym};
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Looking for char :$char: with ord :$ord:" );
|
|
|
|
$self->debug( 2, "Looking for keycode :$keycode:" );
|
|
|
|
$self->debug( 2, "Looking for keysym :$keysym:" );
|
2014-06-28 11:40:00 +01:00
|
|
|
$self->debug( 2, "Looking for keyboardmap :",
|
|
|
|
$keyboardmap{$keysym}, ":" );
|
2014-06-21 08:30:23 +01:00
|
|
|
my ( $state, $code ) = $self->get_keycode_state($keysym);
|
|
|
|
$self->debug( 2, "Got state :$state: code :$code:" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
for my $event (qw/KeyPress KeyRelease/) {
|
2014-06-28 11:40:00 +01:00
|
|
|
$self->debug( 2,
|
|
|
|
"sending event=$event code=:$code: state=:$state:" );
|
2010-06-18 22:10:33 +01:00
|
|
|
$xdisplay->SendEvent(
|
|
|
|
$servers{$svr}{wid},
|
|
|
|
0,
|
|
|
|
$xdisplay->pack_event_mask($event),
|
|
|
|
$xdisplay->pack_event(
|
|
|
|
'name' => $event,
|
|
|
|
'detail' => $code,
|
|
|
|
'state' => $state,
|
|
|
|
'time' => time(),
|
|
|
|
'event' => $servers{$svr}{wid},
|
|
|
|
'root' => $xdisplay->root(),
|
|
|
|
'same_screen' => 1,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$xdisplay->flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
sub send_text_to_all_servers {
|
2014-01-13 18:44:12 +00:00
|
|
|
my $self = shift;
|
2010-06-18 22:10:33 +01:00
|
|
|
my $text = join( '', @_ );
|
|
|
|
|
|
|
|
foreach my $svr ( keys(%servers) ) {
|
2014-01-13 18:44:12 +00:00
|
|
|
$self->send_text( $svr, $text )
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $servers{$svr}{active} == 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub send_resizemove($$$$$) {
|
2014-06-28 11:40:00 +01:00
|
|
|
my ( $self, $win, $x_pos, $y_pos, $x_siz, $y_siz ) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3,
|
2010-06-18 22:10:33 +01:00
|
|
|
"Moving window $win to x:$x_pos y:$y_pos (size x:$x_siz y:$y_siz)" );
|
|
|
|
|
2014-06-28 11:40:00 +01:00
|
|
|
#$self->debug( 2, "resize move normal: ", $xdisplay->atom('WM_NORMAL_HINTS') );
|
|
|
|
#$self->debug( 2, "resize move size: ", $xdisplay->atom('WM_SIZE_HINTS') );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# set the window to have "user" set size & position, rather than "program"
|
|
|
|
$xdisplay->req(
|
|
|
|
'ChangeProperty',
|
|
|
|
$win,
|
|
|
|
$xdisplay->atom('WM_NORMAL_HINTS'),
|
|
|
|
$xdisplay->atom('WM_SIZE_HINTS'),
|
|
|
|
32,
|
|
|
|
'Replace',
|
|
|
|
|
2014-02-17 15:39:20 -08:00
|
|
|
# create data struct on-the-fly to set bitwise flags
|
2010-06-18 22:10:33 +01:00
|
|
|
pack( 'LLLLL' . 'x[L]' x 12, 1 | 2, $x_pos, $y_pos, $x_siz, $y_siz ),
|
|
|
|
);
|
|
|
|
|
|
|
|
$xdisplay->req(
|
|
|
|
'ConfigureWindow',
|
|
|
|
$win,
|
|
|
|
'x' => $x_pos,
|
|
|
|
'y' => $y_pos,
|
|
|
|
'width' => $x_siz,
|
|
|
|
'height' => $y_siz,
|
|
|
|
);
|
|
|
|
|
|
|
|
#$xdisplay->flush(); # dont flush here, but after all tiling worked out
|
|
|
|
}
|
|
|
|
|
|
|
|
sub open_client_windows(@) {
|
2011-07-28 10:23:49 +01:00
|
|
|
my $self = shift;
|
2010-06-18 22:10:33 +01:00
|
|
|
foreach (@_) {
|
|
|
|
next unless ($_);
|
|
|
|
|
2010-06-18 23:17:42 +01:00
|
|
|
my $server_object = App::ClusterSSH::Host->parse_host_string($_);
|
|
|
|
|
2010-09-10 08:32:03 +01:00
|
|
|
my $username = $server_object->get_username();
|
2013-03-25 13:13:03 +00:00
|
|
|
$username = $self->config->{user}
|
|
|
|
if ( !$username && $self->config->{user} );
|
2011-11-17 22:53:06 +00:00
|
|
|
my $port = $server_object->get_port();
|
|
|
|
$port = $self->config->{port} if ( $self->config->{port} );
|
|
|
|
my $server = $server_object->get_hostname();
|
|
|
|
my $master = $server_object->get_master();
|
2010-06-18 23:17:42 +01:00
|
|
|
|
2014-07-02 22:39:36 +01:00
|
|
|
my $given_server_name = $server_object->get_hostname();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# see if we can find the hostname - if not, drop it
|
2010-06-18 23:17:42 +01:00
|
|
|
my $realname = $server_object->get_realname();
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( !$realname ) {
|
|
|
|
my $text = "WARNING: '$_' unknown";
|
|
|
|
|
|
|
|
if (%ssh_hostnames) {
|
|
|
|
$text
|
|
|
|
.= " (unable to resolve and not in user ssh config file)";
|
|
|
|
}
|
|
|
|
|
|
|
|
warn( $text, $/ );
|
|
|
|
|
|
|
|
#next; # Debian bug 499935 - ignore warnings about hostname resolution
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "username=$username, server=$server, port=$port" );
|
2011-07-28 10:46:01 +01:00
|
|
|
|
2010-06-18 22:10:33 +01:00
|
|
|
my $color = '';
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{terminal_colorize} ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
my $c = pick_color($server);
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{terminal_bg_style} eq 'dark' ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$color = "-bg \\#000000 -fg $c";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$color = "-fg \\#000000 -bg $c";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my $count = q{};
|
|
|
|
while ( defined( $servers{ $server . q{ } . $count } ) ) {
|
|
|
|
$count++;
|
|
|
|
}
|
|
|
|
$server .= q{ } . $count;
|
|
|
|
|
|
|
|
$servers{$server}{connect_string} = $_;
|
|
|
|
$servers{$server}{givenname} = $given_server_name;
|
|
|
|
$servers{$server}{realname} = $realname;
|
2011-07-28 10:23:49 +01:00
|
|
|
$servers{$server}{username} = $self->config->{user};
|
2011-01-24 19:47:59 +00:00
|
|
|
$servers{$server}{username} = $username if ($username);
|
2011-06-24 22:25:16 +01:00
|
|
|
$servers{$server}{username} = $username || '';
|
2010-06-18 22:10:33 +01:00
|
|
|
$servers{$server}{port} = $port || '';
|
2011-07-28 10:23:49 +01:00
|
|
|
$servers{$server}{master} = $self->config->{mstr} || '';
|
2011-06-30 11:12:59 +01:00
|
|
|
$servers{$server}{master} = $master if ($master);
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Working on server $server for $_" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$servers{$server}{pipenm} = tmpnam();
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Set temp name to: $servers{$server}{pipenm}" );
|
2010-06-18 22:10:33 +01:00
|
|
|
mkfifo( $servers{$server}{pipenm}, 0600 )
|
|
|
|
or die("Cannot create pipe: $!");
|
|
|
|
|
2014-02-17 15:39:20 -08:00
|
|
|
# NOTE: the PID is re-fetched from the xterm window (via helper_script)
|
2010-06-18 22:10:33 +01:00
|
|
|
# later as it changes and we need an accurate PID as it is widely used
|
|
|
|
$servers{$server}{pid} = fork();
|
|
|
|
if ( !defined( $servers{$server}{pid} ) ) {
|
|
|
|
die("Could not fork: $!");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $servers{$server}{pid} == 0 ) {
|
|
|
|
# this is the child
|
|
|
|
# Since this is the child, we can mark any server unresolved without
|
|
|
|
# affecting the main program
|
|
|
|
$servers{$server}{realname} .= "==" if ( !$realname );
|
2011-11-17 22:53:06 +00:00
|
|
|
my $exec = join( ' ',
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{terminal},
|
|
|
|
$color,
|
|
|
|
$self->config->{terminal_args},
|
|
|
|
$self->config->{terminal_allow_send_events},
|
|
|
|
$self->config->{terminal_title_opt},
|
2011-11-17 22:53:06 +00:00
|
|
|
"'"
|
|
|
|
. $self->config->{title} . ': '
|
|
|
|
. $servers{$server}{connect_string} . "'",
|
|
|
|
'-font ' . $self->config->{terminal_font},
|
|
|
|
"-e " . $^X . ' -e ',
|
|
|
|
"'" . $self->helper->script( $self->config ) . "'",
|
|
|
|
" " . $servers{$server}{pipenm},
|
|
|
|
" " . $servers{$server}{givenname},
|
|
|
|
" '" . $servers{$server}{username} . "'",
|
|
|
|
" '" . $servers{$server}{port} . "'",
|
|
|
|
" '" . $servers{$server}{master} . "'",
|
2011-07-28 10:23:49 +01:00
|
|
|
);
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Terminal exec line:\n$exec\n" );
|
2010-06-18 22:10:33 +01:00
|
|
|
exec($exec) == 0 or warn("Failed: $!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-17 15:39:20 -08:00
|
|
|
# Now all the windows are open, get all their window IDs
|
2010-06-18 22:10:33 +01:00
|
|
|
foreach my $server ( keys(%servers) ) {
|
|
|
|
next if ( defined( $servers{$server}{active} ) );
|
|
|
|
|
|
|
|
# sleep for a moment to give system time to come up
|
|
|
|
select( undef, undef, undef, 0.1 );
|
|
|
|
|
|
|
|
# block on open so we get the text when it comes in
|
|
|
|
unless (
|
|
|
|
sysopen(
|
|
|
|
$servers{$server}{pipehl}, $servers{$server}{pipenm},
|
|
|
|
O_RDONLY
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
warn(
|
|
|
|
"Cannot open pipe for reading when talking to $server: $!\n");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# NOTE: read both the xterm pid and the window ID here
|
|
|
|
# get PID here as it changes from the fork above, and we need the
|
|
|
|
# correct PID
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Performing sysread" );
|
2010-06-18 22:10:33 +01:00
|
|
|
my $piperead;
|
|
|
|
sysread( $servers{$server}{pipehl}, $piperead, 100 );
|
|
|
|
( $servers{$server}{pid}, $servers{$server}{wid} )
|
|
|
|
= split( /:/, $piperead, 2 );
|
|
|
|
warn("Cannot determ pid of '$server' window\n")
|
|
|
|
unless $servers{$server}{pid};
|
|
|
|
warn("Cannot determ window ID of '$server' window\n")
|
|
|
|
unless $servers{$server}{wid};
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Done and closing pipe" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
close( $servers{$server}{pipehl} );
|
|
|
|
}
|
|
|
|
delete( $servers{$server}{pipehl} );
|
|
|
|
|
|
|
|
unlink( $servers{$server}{pipenm} );
|
|
|
|
delete( $servers{$server}{pipenm} );
|
|
|
|
|
|
|
|
$servers{$server}{active} = 1; # mark as active
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_activate_autoquit}
|
2010-06-18 22:10:33 +01:00
|
|
|
= 1; # activate auto_quit if in use
|
|
|
|
}
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "All client windows opened" );
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_total} = int( keys(%servers) );
|
|
|
|
|
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub get_font_size() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Fetching font size" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# get atom name<->number relations
|
|
|
|
my $quad_width = $xdisplay->atom("QUAD_WIDTH");
|
|
|
|
my $pixel_size = $xdisplay->atom("PIXEL_SIZE");
|
|
|
|
|
2011-11-17 22:53:06 +00:00
|
|
|
my $font = $xdisplay->new_rsrc;
|
2011-07-28 10:23:49 +01:00
|
|
|
my $terminal_font = $self->config->{terminal_font};
|
|
|
|
$xdisplay->OpenFont( $font, $terminal_font );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
my %font_info;
|
|
|
|
|
|
|
|
eval { (%font_info) = $xdisplay->QueryFont($font); }
|
2011-07-28 10:23:49 +01:00
|
|
|
|| die( "Fatal: Unrecognised font used ($terminal_font).\n"
|
2013-02-04 17:14:37 +00:00
|
|
|
. "Please amend \$HOME/.clusterssh/config with a valid font (see man page).\n"
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
|
|
|
|
2011-11-17 22:53:06 +00:00
|
|
|
$self->config->{internal_font_width}
|
|
|
|
= $font_info{properties}{$quad_width};
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->config->{internal_font_height}
|
2011-11-17 22:53:06 +00:00
|
|
|
= $font_info{properties}{$pixel_size};
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-17 22:53:06 +00:00
|
|
|
if ( !$self->config->{internal_font_width}
|
|
|
|
|| !$self->config->{internal_font_height} )
|
|
|
|
{
|
2011-07-28 10:23:49 +01:00
|
|
|
die( "Fatal: Unrecognised font used ($terminal_font).\n"
|
2013-02-04 17:14:37 +00:00
|
|
|
. "Please amend \$HOME/.clusterssh/config with a valid font (see man page).\n"
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Done with font size" );
|
2011-07-28 10:23:49 +01:00
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub show_console() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = shift;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Sending console to front" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_previous_state} = "mid-change";
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# fudge the counter to drop a redraw event;
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_map_count} -= 4;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$xdisplay->flush();
|
|
|
|
$windows{main_window}->update();
|
|
|
|
|
|
|
|
select( undef, undef, undef, 0.2 ); #sleep for a mo
|
|
|
|
$windows{main_window}->withdraw;
|
|
|
|
|
|
|
|
# Sleep for a moment to give WM time to bring console back
|
|
|
|
select( undef, undef, undef, 0.5 );
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{menu_send_autotearoff} ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$menus{send}->menu->tearOffMenu()->raise;
|
|
|
|
}
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{menu_host_autotearoff} ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$menus{hosts}->menu->tearOffMenu()->raise;
|
|
|
|
}
|
|
|
|
|
|
|
|
$windows{main_window}->deiconify;
|
|
|
|
$windows{main_window}->raise;
|
|
|
|
$windows{main_window}->focus( -force );
|
|
|
|
$windows{text_entry}->focus( -force );
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_previous_state} = "normal";
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# fvwm seems to need this (Debian #329440)
|
|
|
|
$windows{main_window}->MapWindow;
|
2011-07-28 10:23:49 +01:00
|
|
|
|
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2014-02-17 15:39:20 -08:00
|
|
|
# leave function def open here so we can be flexible in how it's called
|
2010-06-18 22:10:33 +01:00
|
|
|
sub retile_hosts {
|
2011-11-17 22:53:06 +00:00
|
|
|
my ( $self, $force ) = @_;
|
2011-07-28 10:23:49 +01:00
|
|
|
$force ||= "";
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Retiling windows" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
my %config;
|
|
|
|
|
2011-11-18 22:19:00 +00:00
|
|
|
if ( $self->config->{window_tiling} ne "yes" && !$force ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3,
|
2011-11-18 22:31:12 +00:00
|
|
|
"Not meant to be tiling; just reshow windows as they were" );
|
2011-11-17 22:53:06 +00:00
|
|
|
|
2011-11-18 22:31:12 +00:00
|
|
|
foreach my $server ( reverse( keys(%servers) ) ) {
|
|
|
|
$xdisplay->req( 'MapWindow', $servers{$server}{wid} );
|
|
|
|
}
|
|
|
|
$xdisplay->flush();
|
|
|
|
$self->show_console();
|
|
|
|
return;
|
2011-11-18 22:19:00 +00:00
|
|
|
}
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# ALL SIZES SHOULD BE IN PIXELS for consistency
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Count is currently ", $self->config->{internal_total} );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{internal_total} == 0 ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-18 22:19:00 +00:00
|
|
|
# If nothing to tile, don't bother doing anything, just show console
|
2011-07-28 10:23:49 +01:00
|
|
|
return $self->show_console();
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# work out terminal pixel size from terminal size & font size
|
|
|
|
# does not include any title bars or scroll bars - purely text area
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->config->{internal_terminal_cols}
|
|
|
|
= ( $self->config->{terminal_size} =~ /(\d+)x.*/ )[0];
|
|
|
|
$self->config->{internal_terminal_width}
|
2011-11-18 22:31:12 +00:00
|
|
|
= ( $self->config->{internal_terminal_cols}
|
|
|
|
* $self->config->{internal_font_width} )
|
2011-11-18 22:19:00 +00:00
|
|
|
+ $self->config->{terminal_decoration_width};
|
|
|
|
|
|
|
|
$self->config->{internal_terminal_rows}
|
|
|
|
= ( $self->config->{terminal_size} =~ /.*x(\d+)/ )[0];
|
|
|
|
$self->config->{internal_terminal_height}
|
2011-11-18 22:31:12 +00:00
|
|
|
= ( $self->config->{internal_terminal_rows}
|
|
|
|
* $self->config->{internal_font_height} )
|
2011-11-18 22:19:00 +00:00
|
|
|
+ $self->config->{terminal_decoration_height};
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# fetch screen size
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->config->{internal_screen_height} = $xdisplay->{height_in_pixels};
|
|
|
|
$self->config->{internal_screen_width} = $xdisplay->{width_in_pixels};
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# Now, work out how many columns of terminals we can fit on screen
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->config->{internal_columns} = int(
|
2011-11-18 22:31:12 +00:00
|
|
|
( $self->config->{internal_screen_width}
|
2011-11-18 22:19:00 +00:00
|
|
|
- $self->config->{screen_reserve_left}
|
|
|
|
- $self->config->{screen_reserve_right}
|
2010-06-18 22:10:33 +01:00
|
|
|
) / (
|
2011-11-18 22:31:12 +00:00
|
|
|
$self->config->{internal_terminal_width}
|
2011-11-18 22:19:00 +00:00
|
|
|
+ $self->config->{terminal_reserve_left}
|
|
|
|
+ $self->config->{terminal_reserve_right}
|
2010-06-18 22:10:33 +01:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
# Work out the number of rows we need to use to fit everything on screen
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->config->{internal_rows} = int(
|
2011-11-18 22:31:12 +00:00
|
|
|
( $self->config->{internal_total}
|
|
|
|
/ $self->config->{internal_columns}
|
|
|
|
) + 0.999
|
|
|
|
);
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Screen Columns: ", $self->config->{internal_columns} );
|
|
|
|
$self->debug( 2, "Screen Rows: ", $self->config->{internal_rows} );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# Now adjust the height of the terminal to either the max given,
|
|
|
|
# or to get everything on screen
|
|
|
|
{
|
|
|
|
my $height = int(
|
2011-11-18 22:19:00 +00:00
|
|
|
( ( $self->config->{internal_screen_height}
|
|
|
|
- $self->config->{screen_reserve_top}
|
|
|
|
- $self->config->{screen_reserve_bottom}
|
2010-06-18 22:10:33 +01:00
|
|
|
) - (
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->config->{internal_rows} * (
|
|
|
|
$self->config->{terminal_reserve_top}
|
|
|
|
+ $self->config->{terminal_reserve_bottom}
|
2010-06-18 22:10:33 +01:00
|
|
|
)
|
|
|
|
)
|
2011-11-18 22:19:00 +00:00
|
|
|
) / $self->config->{internal_rows}
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Terminal height=$height" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->config->{internal_terminal_height} = (
|
|
|
|
$height > $self->config->{internal_terminal_height}
|
|
|
|
? $self->config->{internal_terminal_height}
|
2010-06-18 22:10:33 +01:00
|
|
|
: $height
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->config->dump("noexit") if ( $self->options->debug > 1 );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# now we have the info, plot first window position
|
|
|
|
my @hosts;
|
|
|
|
my ( $current_x, $current_y, $current_row, $current_col ) = 0;
|
2011-11-18 22:19:00 +00:00
|
|
|
if ( $self->config->{window_tiling_direction} =~ /right/i ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Tiling top left going bot right" );
|
2011-11-18 22:31:12 +00:00
|
|
|
@hosts = sort( keys(%servers) );
|
|
|
|
$current_x = $self->config->{screen_reserve_left}
|
|
|
|
+ $self->config->{terminal_reserve_left};
|
|
|
|
$current_y = $self->config->{screen_reserve_top}
|
|
|
|
+ $self->config->{terminal_reserve_top};
|
2010-06-18 22:10:33 +01:00
|
|
|
$current_row = 0;
|
|
|
|
$current_col = 0;
|
|
|
|
}
|
|
|
|
else {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Tiling bot right going top left" );
|
2010-06-18 22:10:33 +01:00
|
|
|
@hosts = reverse( sort( keys(%servers) ) );
|
|
|
|
$current_x
|
2011-11-18 22:31:12 +00:00
|
|
|
= $self->config->{screen_reserve_right}
|
2011-11-18 22:19:00 +00:00
|
|
|
- $self->config->{internal_screen_width}
|
|
|
|
- $self->config->{terminal_reserve_right}
|
|
|
|
- $self->config->{internal_terminal_width};
|
2010-06-18 22:10:33 +01:00
|
|
|
$current_y
|
2011-11-18 22:31:12 +00:00
|
|
|
= $self->config->{screen_reserve_bottom}
|
2011-11-18 22:19:00 +00:00
|
|
|
- $self->config->{internal_screen_height}
|
|
|
|
- $self->config->{terminal_reserve_bottom}
|
|
|
|
- $self->config->{internal_terminal_height};
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-18 22:19:00 +00:00
|
|
|
$current_row = $self->config->{internal_rows} - 1;
|
|
|
|
$current_col = $self->config->{internal_columns} - 1;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Unmap windows (hide them)
|
|
|
|
# Move windows to new locatation
|
|
|
|
# Remap all windows in correct order
|
|
|
|
foreach my $server (@hosts) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3,
|
2010-06-18 22:10:33 +01:00
|
|
|
"x:$current_x y:$current_y, r:$current_row c:$current_col" );
|
|
|
|
|
2010-09-10 08:20:50 +01:00
|
|
|
# sf tracker 3061999
|
|
|
|
# $xdisplay->req( 'UnmapWindow', $servers{$server}{wid} );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-18 22:19:00 +00:00
|
|
|
if ( $self->config->{unmap_on_redraw} =~ /yes/i ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$xdisplay->req( 'UnmapWindow', $servers{$server}{wid} );
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Moving $server window" );
|
|
|
|
$self->send_resizemove(
|
2010-06-18 22:10:33 +01:00
|
|
|
$servers{$server}{wid},
|
2011-11-18 22:31:12 +00:00
|
|
|
$current_x,
|
|
|
|
$current_y,
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->config->{internal_terminal_width},
|
|
|
|
$self->config->{internal_terminal_height}
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$xdisplay->flush();
|
|
|
|
select( undef, undef, undef, 0.1 ); # sleep for a moment for the WM
|
|
|
|
|
2011-11-18 22:19:00 +00:00
|
|
|
if ( $self->config->{window_tiling_direction} =~ /right/i ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# starting top left, and move right and down
|
|
|
|
$current_x
|
2011-11-18 22:19:00 +00:00
|
|
|
+= $self->config->{terminal_reserve_left}
|
|
|
|
+ $self->config->{terminal_reserve_right}
|
|
|
|
+ $self->config->{internal_terminal_width};
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$current_col += 1;
|
2011-11-18 22:19:00 +00:00
|
|
|
if ( $current_col == $self->config->{internal_columns} ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$current_y
|
2011-11-18 22:19:00 +00:00
|
|
|
+= $self->config->{terminal_reserve_top}
|
|
|
|
+ $self->config->{terminal_reserve_bottom}
|
|
|
|
+ $self->config->{internal_terminal_height};
|
|
|
|
$current_x = $self->config->{screen_reserve_left}
|
|
|
|
+ $self->config->{terminal_reserve_left};
|
2010-06-18 22:10:33 +01:00
|
|
|
$current_row++;
|
|
|
|
$current_col = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# starting bottom right, and move left and up
|
|
|
|
|
|
|
|
$current_col -= 1;
|
|
|
|
if ( $current_col < 0 ) {
|
|
|
|
$current_row--;
|
2011-11-18 22:19:00 +00:00
|
|
|
$current_col = $self->config->{internal_columns};
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Now remap in right order to get overlaps correct
|
2011-11-18 22:19:00 +00:00
|
|
|
if ( $self->config->{window_tiling_direction} =~ /right/i ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
foreach my $server ( reverse(@hosts) ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Setting focus on $server" );
|
2010-06-18 22:10:33 +01:00
|
|
|
$xdisplay->req( 'MapWindow', $servers{$server}{wid} );
|
|
|
|
|
|
|
|
# flush every time and wait a moment (The WMs are so slow...)
|
|
|
|
$xdisplay->flush();
|
|
|
|
select( undef, undef, undef, 0.1 ); # sleep for a mo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
foreach my $server (@hosts) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Setting focus on $server" );
|
2010-06-18 22:10:33 +01:00
|
|
|
$xdisplay->req( 'MapWindow', $servers{$server}{wid} );
|
|
|
|
|
|
|
|
# flush every time and wait a moment (The WMs are so slow...)
|
|
|
|
$xdisplay->flush();
|
|
|
|
select( undef, undef, undef, 0.1 ); # sleep for a mo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# and as a last item, set focus back onto the console
|
2011-07-28 10:23:49 +01:00
|
|
|
return $self->show_console();
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub capture_terminal() {
|
2014-06-21 08:30:23 +01:00
|
|
|
my ($self) = @_;
|
|
|
|
$self->debug( 0, "Stub for capturing a terminal window" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-28 11:39:28 +01:00
|
|
|
return if ( $self->coptions->debug < 6 );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# should never see this - all experimental anyhow
|
|
|
|
|
|
|
|
foreach my $server ( keys(%servers) ) {
|
|
|
|
foreach my $data ( keys( %{ $servers{$server} } ) ) {
|
|
|
|
print "server $server key $data is $servers{$server}{$data}\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#return;
|
|
|
|
|
|
|
|
my %atoms;
|
|
|
|
|
|
|
|
for my $atom ( $xdisplay->req( 'ListProperties', $servers{loki}{wid} ) ) {
|
|
|
|
$atoms{ $xdisplay->atom_name($atom) }
|
|
|
|
= $xdisplay->req( 'GetProperty', $servers{loki}{wid},
|
|
|
|
$atom, "AnyPropertyType", 0, 200, 0 );
|
|
|
|
|
|
|
|
print $xdisplay->atom_name($atom), " ($atom) => ";
|
|
|
|
print "join here\n";
|
|
|
|
print join(
|
|
|
|
"\n",
|
|
|
|
$xdisplay->req(
|
|
|
|
'GetProperty', $servers{loki}{wid},
|
|
|
|
$atom, "AnyPropertyType", 0, 200, 0
|
|
|
|
)
|
|
|
|
),
|
|
|
|
"\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
print "list by number\n";
|
|
|
|
for my $atom ( 1 .. 90 ) {
|
|
|
|
print "$atom: ", $xdisplay->req( 'GetAtomName', $atom ), "\n";
|
|
|
|
print join(
|
|
|
|
"\n",
|
|
|
|
$xdisplay->req(
|
|
|
|
'GetProperty', $servers{loki}{wid},
|
|
|
|
$atom, "AnyPropertyType", 0, 200, 0
|
|
|
|
)
|
|
|
|
),
|
|
|
|
"\n";
|
|
|
|
}
|
|
|
|
print "\n";
|
|
|
|
|
|
|
|
print "size hints\n";
|
|
|
|
print join(
|
|
|
|
"\n",
|
|
|
|
$xdisplay->req(
|
|
|
|
'GetProperty', $servers{loki}{wid},
|
|
|
|
42, "AnyPropertyType", 0, 200, 0
|
|
|
|
)
|
|
|
|
),
|
|
|
|
"\n";
|
|
|
|
|
|
|
|
print "atom list by name\n";
|
|
|
|
foreach ( keys(%atoms) ) {
|
|
|
|
print "atom :$_: = $atoms{$_}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
print "geom\n";
|
|
|
|
print join " ", $xdisplay->req( 'GetGeometry', $servers{loki}{wid} ), $/;
|
|
|
|
print "attrib\n";
|
|
|
|
print join " ",
|
|
|
|
$xdisplay->req( 'GetWindowAttributes', $servers{loki}{wid} ),
|
|
|
|
$/;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub toggle_active_state() {
|
2011-11-21 22:39:47 +00:00
|
|
|
my ($self) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Toggling active state of all hosts" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
foreach my $svr ( sort( keys(%servers) ) ) {
|
|
|
|
$servers{$svr}{active} = not $servers{$svr}{active};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 09:53:38 +00:00
|
|
|
sub set_all_active() {
|
|
|
|
my ($self) = @_;
|
|
|
|
logmsg( 2, "Setting all hosts to be active" );
|
|
|
|
|
|
|
|
foreach my $svr ( keys(%servers) ) {
|
|
|
|
$servers{$svr}{active} = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sub set_half_inactive() {
|
|
|
|
my ($self) = @_;
|
|
|
|
logmsg( 2, "Setting approx half of all hosts to inactive" );
|
|
|
|
|
|
|
|
my(@keys) = keys(%servers);
|
|
|
|
$#keys /= 2;
|
|
|
|
foreach my $svr ( @keys ) {
|
|
|
|
$servers{$svr}{active} = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-18 22:10:33 +01:00
|
|
|
sub close_inactive_sessions() {
|
2011-11-21 22:39:47 +00:00
|
|
|
my ($self) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Closing all inactive sessions" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
foreach my $svr ( sort( keys(%servers) ) ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->terminate_host($svr) if ( !$servers{$svr}{active} );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
2011-11-21 22:39:47 +00:00
|
|
|
$self->build_hosts_menu();
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub add_host_by_name() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Adding host to menu here" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$windows{host_entry}->focus();
|
|
|
|
my $answer = $windows{addhost}->Show();
|
|
|
|
|
2014-07-05 20:25:14 +01:00
|
|
|
if ( !$answer || $answer ne "Add" ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$menus{host_entry} = "";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $menus{host_entry} ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "host=", $menus{host_entry} );
|
2011-11-18 22:31:12 +00:00
|
|
|
my @names
|
|
|
|
= $self->resolve_names( split( /\s+/, $menus{host_entry} ) );
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 0, 'Opening to: ', join( ' ', @names ) );
|
2011-11-21 22:36:25 +00:00
|
|
|
$self->open_client_windows(@names);
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2013-02-13 22:18:45 +00:00
|
|
|
if ( defined $menus{listbox} && $menus{listbox}->curselection() ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
my @hosts = $menus{listbox}->get( $menus{listbox}->curselection() );
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "host=", join( ' ', @hosts ) );
|
2011-11-21 22:36:25 +00:00
|
|
|
$self->open_client_windows( $self->resolve_names(@hosts) );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2011-11-21 22:39:47 +00:00
|
|
|
$self->build_hosts_menu();
|
2010-06-18 22:10:33 +01:00
|
|
|
$menus{host_entry} = "";
|
|
|
|
|
|
|
|
# retile, or bring console to front
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{window_tiling} eq "yes" ) {
|
|
|
|
return $self->retile_hosts();
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
else {
|
2011-07-28 10:23:49 +01:00
|
|
|
return $self->show_console();
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub build_hosts_menu() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Building hosts menu" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# first, empty the hosts menu from the 4th entry on
|
|
|
|
my $menu = $menus{bar}->entrycget( 'Hosts', -menu );
|
2014-07-07 17:14:48 +01:00
|
|
|
my $host_menu_static_items = 7;
|
2010-06-18 22:10:33 +01:00
|
|
|
$menu->delete( $host_menu_static_items, 'end' );
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "Menu deleted" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-02-17 15:39:20 -08:00
|
|
|
# add back the separator
|
2010-06-18 22:10:33 +01:00
|
|
|
$menus{hosts}->separator;
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "Parsing list" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
my $menu_item_counter = $host_menu_static_items;
|
|
|
|
foreach my $svr ( sort( keys(%servers) ) ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "Checking $svr and restoring active value" );
|
2010-06-18 22:10:33 +01:00
|
|
|
my $colbreak = 0;
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $menu_item_counter > $self->config->{max_host_menu_items} ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$colbreak = 1;
|
|
|
|
$menu_item_counter = 1;
|
|
|
|
}
|
|
|
|
$menus{hosts}->checkbutton(
|
|
|
|
-label => $svr,
|
|
|
|
-variable => \$servers{$svr}{active},
|
|
|
|
-columnbreak => $colbreak,
|
|
|
|
);
|
|
|
|
$menu_item_counter++;
|
|
|
|
}
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "Changing window title" );
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->change_main_window_title();
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Done" );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub setup_repeat() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
|
|
|
$self->config->{internal_count} = 0;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# if this is too fast then we end up with queued invocations
|
|
|
|
# with no time to run anything else
|
|
|
|
$windows{main_window}->repeat(
|
|
|
|
500,
|
|
|
|
sub {
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_count} = 0
|
2011-11-17 22:53:06 +00:00
|
|
|
if ( $self->config->{internal_count} > 60000 )
|
|
|
|
; # reset if too high
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_count}++;
|
2010-06-18 22:10:33 +01:00
|
|
|
my $build_menu = 0;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug(
|
2011-11-17 22:53:06 +00:00
|
|
|
5,
|
|
|
|
"Running repeat;count=",
|
|
|
|
$self->config->{internal_count}
|
|
|
|
);
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-28 11:40:00 +01:00
|
|
|
#$self->debug( 3, "Number of servers in hash is: ", scalar( keys(%servers) ) );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
foreach my $svr ( keys(%servers) ) {
|
|
|
|
if ( defined( $servers{$svr}{pid} ) ) {
|
|
|
|
if ( !kill( 0, $servers{$svr}{pid} ) ) {
|
|
|
|
$build_menu = 1;
|
|
|
|
delete( $servers{$svr} );
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 0, "$svr session closed" );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
warn("Lost pid of $svr; deleting\n");
|
|
|
|
delete( $servers{$svr} );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# get current number of clients
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_total} = int( keys(%servers) );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-28 11:40:00 +01:00
|
|
|
#$self->debug( 3, "Number after tidy is: ", $config{internal_total} );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# get current number of clients
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_total} = int( keys(%servers) );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-28 11:40:00 +01:00
|
|
|
#$self->debug( 3, "Number after tidy is: ", $config{internal_total} );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# If there are no hosts in the list and we are set to autoquit
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{internal_total} == 0
|
|
|
|
&& $self->config->{auto_quit} =~ /yes/i )
|
2010-06-18 22:10:33 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
# and some clients were actually opened...
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{internal_activate_autoquit} ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Autoquitting" );
|
|
|
|
$self->exit_prog;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# rebuild host menu if something has changed
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->build_hosts_menu() if ($build_menu);
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# clean out text area, anyhow
|
|
|
|
$menus{entrytext} = "";
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
#$self->debug( 3, "repeat completed" );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
);
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Repeat setup" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
### Window and menu definitions ###
|
|
|
|
|
|
|
|
sub create_windows() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "create_windows: started" );
|
2013-02-15 08:26:41 +00:00
|
|
|
$windows{main_window}
|
|
|
|
= MainWindow->new( -title => "ClusterSSH", -class => 'cssh', );
|
2010-06-18 22:10:33 +01:00
|
|
|
$windows{main_window}->withdraw; # leave withdrawn until needed
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( defined( $self->config->{console_position} )
|
|
|
|
&& $self->config->{console_position} =~ /[+-]\d+[+-]\d+/ )
|
2010-06-18 22:10:33 +01:00
|
|
|
{
|
2011-07-28 10:23:49 +01:00
|
|
|
$windows{main_window}->geometry( $self->config->{console_position} );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$menus{entrytext} = "";
|
|
|
|
$windows{text_entry} = $windows{main_window}->Entry(
|
|
|
|
-textvariable => \$menus{entrytext},
|
|
|
|
-insertborderwidth => 4,
|
|
|
|
-width => 25,
|
2013-02-15 08:26:41 +00:00
|
|
|
-class => 'cssh',
|
2010-06-18 22:10:33 +01:00
|
|
|
)->pack(
|
|
|
|
-fill => "x",
|
|
|
|
-expand => 1,
|
|
|
|
);
|
|
|
|
|
|
|
|
$windows{history} = $windows{main_window}->Scrolled(
|
|
|
|
"ROText",
|
|
|
|
-insertborderwidth => 4,
|
2011-07-28 10:23:49 +01:00
|
|
|
-width => $self->config->{history_width},
|
|
|
|
-height => $self->config->{history_height},
|
2010-06-18 22:10:33 +01:00
|
|
|
-state => 'normal',
|
|
|
|
-takefocus => 0,
|
2013-02-15 08:26:41 +00:00
|
|
|
-class => 'cssh',
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
|
|
|
$windows{history}->bindtags(undef);
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{show_history} ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
$windows{history}->pack(
|
|
|
|
-fill => "x",
|
|
|
|
-expand => 1,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-06-28 11:40:00 +01:00
|
|
|
$windows{main_window}->bind( '<Destroy>' => sub { $self->exit_prog } );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# remove all Paste events so we set them up cleanly
|
|
|
|
$windows{main_window}->eventDelete('<<Paste>>');
|
|
|
|
|
|
|
|
# Set up paste events from scratch
|
2011-11-17 22:53:06 +00:00
|
|
|
if ( $self->config->{key_paste} && $self->config->{key_paste} ne "null" )
|
|
|
|
{
|
|
|
|
$windows{main_window}->eventAdd(
|
|
|
|
'<<Paste>>' => '<' . $self->config->{key_paste} . '>' );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2011-11-17 22:53:06 +00:00
|
|
|
if ( $self->config->{mouse_paste}
|
|
|
|
&& $self->config->{mouse_paste} ne "null" )
|
|
|
|
{
|
|
|
|
$windows{main_window}->eventAdd(
|
|
|
|
'<<Paste>>' => '<' . $self->config->{mouse_paste} . '>' );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$windows{main_window}->bind(
|
|
|
|
'<<Paste>>' => sub {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "PASTE EVENT" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$menus{entrytext} = "";
|
|
|
|
my $paste_text = '';
|
|
|
|
|
|
|
|
# SelectionGet is fatal if no selection is given
|
|
|
|
Tk::catch {
|
|
|
|
$paste_text = $windows{main_window}->SelectionGet;
|
|
|
|
};
|
|
|
|
|
|
|
|
if ( !length($paste_text) ) {
|
|
|
|
warn("Got empty paste event\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Got text :", $paste_text, ":" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->update_display_text($paste_text);
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# now sent it on
|
|
|
|
foreach my $svr ( keys(%servers) ) {
|
2014-01-13 18:44:12 +00:00
|
|
|
$self->send_text( $svr, $paste_text )
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $servers{$svr}{active} == 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
$windows{help} = $windows{main_window}->Dialog(
|
|
|
|
-popover => $windows{main_window},
|
|
|
|
-overanchor => "c",
|
|
|
|
-popanchor => "c",
|
2013-02-15 08:26:41 +00:00
|
|
|
-class => 'cssh',
|
2010-06-18 22:10:33 +01:00
|
|
|
-font => [
|
|
|
|
-family => "interface system",
|
|
|
|
-size => 10,
|
|
|
|
],
|
|
|
|
-text =>
|
|
|
|
"Cluster Administrator Console using SSH\n\nVersion: $VERSION.\n\n"
|
|
|
|
. "Bug/Suggestions to http://clusterssh.sf.net/",
|
|
|
|
);
|
|
|
|
|
|
|
|
$windows{manpage} = $windows{main_window}->DialogBox(
|
|
|
|
-popanchor => "c",
|
|
|
|
-overanchor => "c",
|
|
|
|
-title => "Cssh Documentation",
|
|
|
|
-buttons => ['Close'],
|
2013-02-15 08:26:41 +00:00
|
|
|
-class => 'cssh',
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
|
|
|
|
2011-04-12 09:40:20 +01:00
|
|
|
my $manpage = `pod2text -l -q=\"\" $0 2>/dev/null`;
|
2011-11-17 22:53:06 +00:00
|
|
|
if ( !$manpage ) {
|
|
|
|
$manpage
|
|
|
|
= "Help is missing.\nSee that command 'pod2text' is installed and in PATH.";
|
2011-04-12 09:40:20 +01:00
|
|
|
}
|
2010-06-18 22:10:33 +01:00
|
|
|
$windows{mantext}
|
|
|
|
= $windows{manpage}->Scrolled( "Text", )->pack( -fill => 'both' );
|
|
|
|
$windows{mantext}->insert( 'end', $manpage );
|
|
|
|
$windows{mantext}->configure( -state => 'disabled' );
|
|
|
|
|
|
|
|
$windows{addhost} = $windows{main_window}->DialogBox(
|
|
|
|
-popover => $windows{main_window},
|
|
|
|
-popanchor => 'n',
|
|
|
|
-title => "Add Host(s) or Cluster(s)",
|
|
|
|
-buttons => [ 'Add', 'Cancel' ],
|
|
|
|
-default_button => 'Add',
|
2013-02-15 08:26:41 +00:00
|
|
|
-class => 'cssh',
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
|
|
|
|
2014-07-05 20:25:14 +01:00
|
|
|
my @tags = $self->cluster->list_tags();
|
|
|
|
my @external_tags = map { "$_ *" } $self->cluster->list_external_clusters();
|
|
|
|
push (@tags, @external_tags);
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{max_addhost_menu_cluster_items}
|
2014-07-05 20:25:14 +01:00
|
|
|
&& scalar @tags )
|
2010-06-18 22:10:33 +01:00
|
|
|
{
|
2014-07-05 20:25:14 +01:00
|
|
|
if (scalar @tags
|
2013-02-15 08:26:41 +00:00
|
|
|
< $self->config->{max_addhost_menu_cluster_items} )
|
2010-06-18 22:10:33 +01:00
|
|
|
{
|
|
|
|
$menus{listbox} = $windows{addhost}->Listbox(
|
|
|
|
-selectmode => 'extended',
|
2014-07-05 20:25:14 +01:00
|
|
|
-height => scalar @tags,
|
2013-02-15 08:26:41 +00:00
|
|
|
-class => 'cssh',
|
2010-06-18 22:10:33 +01:00
|
|
|
)->pack();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$menus{listbox} = $windows{addhost}->Scrolled(
|
|
|
|
'Listbox',
|
|
|
|
-scrollbars => 'e',
|
|
|
|
-selectmode => 'extended',
|
2011-11-17 22:53:06 +00:00
|
|
|
-height => $self->config->{max_addhost_menu_cluster_items},
|
2013-02-15 08:26:41 +00:00
|
|
|
-class => 'cssh',
|
2010-06-18 22:10:33 +01:00
|
|
|
)->pack();
|
|
|
|
}
|
2014-07-05 20:25:14 +01:00
|
|
|
$menus{listbox}->insert( 'end', sort @tags );
|
|
|
|
|
|
|
|
if(@external_tags) {
|
|
|
|
$menus{addhost_text} = $windows{addhost}->add(
|
|
|
|
'Label',
|
|
|
|
-class => 'cssh',
|
|
|
|
-text => '* is external',
|
|
|
|
)->pack();
|
|
|
|
|
|
|
|
#$menus{addhost_text}->insert('end','lkjh lkjj sdfl jklsj dflj ');
|
|
|
|
}
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$windows{host_entry} = $windows{addhost}->add(
|
|
|
|
'LabEntry',
|
|
|
|
-textvariable => \$menus{host_entry},
|
|
|
|
-width => 20,
|
|
|
|
-label => 'Host',
|
|
|
|
-labelPack => [ -side => 'left', ],
|
2013-02-15 08:26:41 +00:00
|
|
|
-class => 'cssh',
|
2010-06-18 22:10:33 +01:00
|
|
|
)->pack( -side => 'left' );
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "create_windows: completed" );
|
2011-07-28 10:23:49 +01:00
|
|
|
|
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub capture_map_events() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# pick up on console minimise/maximise events so we can do all windows
|
|
|
|
$windows{main_window}->bind(
|
|
|
|
'<Map>' => sub {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "Entering MAP" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
my $state = $windows{main_window}->state();
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug(
|
2011-11-17 22:53:06 +00:00
|
|
|
3,
|
|
|
|
"state=$state previous=",
|
|
|
|
$self->config->{internal_previous_state}
|
|
|
|
);
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "Entering MAP" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{internal_previous_state} eq $state ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "repeating the same" );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{internal_previous_state} eq "mid-change" ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "dropping out as mid-change" );
|
2010-06-18 22:10:33 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug(
|
2011-11-17 22:53:06 +00:00
|
|
|
3,
|
|
|
|
"state=$state previous=",
|
|
|
|
$self->config->{internal_previous_state}
|
|
|
|
);
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{internal_previous_state} eq "iconic" ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "running retile" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-21 22:36:25 +00:00
|
|
|
$self->retile_hosts();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "done with retile" );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{internal_previous_state} ne $state ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "resetting prev_state" );
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{internal_previous_state} = $state;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
# $windows{main_window}->bind(
|
|
|
|
# '<Unmap>' => sub {
|
2014-06-21 08:30:23 +01:00
|
|
|
# $self->debug( 3, "Entering UNMAP" );
|
2010-06-18 22:10:33 +01:00
|
|
|
#
|
|
|
|
# my $state = $windows{main_window}->state();
|
2014-06-21 08:30:23 +01:00
|
|
|
# $self->debug( 3,
|
2010-06-18 22:10:33 +01:00
|
|
|
# "state=$state previous=$config{internal_previous_state}" );
|
|
|
|
#
|
|
|
|
# if ( $config{internal_previous_state} eq $state ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
# $self->debug( 3, "repeating the same" );
|
2010-06-18 22:10:33 +01:00
|
|
|
# }
|
|
|
|
#
|
|
|
|
# if ( $config{internal_previous_state} eq "mid-change" ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
# $self->debug( 3, "dropping out as mid-change" );
|
2010-06-18 22:10:33 +01:00
|
|
|
# return;
|
|
|
|
# }
|
|
|
|
#
|
|
|
|
# if ( $config{internal_previous_state} eq "normal" ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
# $self->debug( 3, "withdrawing all windows" );
|
2010-06-18 22:10:33 +01:00
|
|
|
# foreach my $server ( reverse( keys(%servers) ) ) {
|
|
|
|
# $xdisplay->req( 'UnmapWindow', $servers{$server}{wid} );
|
|
|
|
# if ( $config{unmap_on_redraw} =~ /yes/i ) {
|
|
|
|
# $xdisplay->req( 'UnmapWindow',
|
|
|
|
# $servers{$server}{wid} );
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
# $xdisplay->flush();
|
|
|
|
# }
|
|
|
|
#
|
|
|
|
# if ( $config{internal_previous_state} ne $state ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
# $self->debug( 3, "resetting prev_state" );
|
2010-06-18 22:10:33 +01:00
|
|
|
# $config{internal_previous_state} = $state;
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
# );
|
2011-07-28 10:23:49 +01:00
|
|
|
|
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# for all key event, event hotkeys so there is only 1 key binding
|
|
|
|
sub key_event {
|
2011-11-17 22:53:06 +00:00
|
|
|
my ($self) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
my $event = $Tk::event->T;
|
|
|
|
my $keycode = $Tk::event->k;
|
|
|
|
my $keysymdec = $Tk::event->N;
|
|
|
|
my $keysym = $Tk::event->K;
|
2011-11-17 22:53:06 +00:00
|
|
|
my $state = $Tk::event->s || 0;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$menus{entrytext} = "";
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "=========" );
|
|
|
|
$self->debug( 3, "event =$event" );
|
|
|
|
$self->debug( 3, "keysym =$keysym (state=$state)" );
|
|
|
|
$self->debug( 3, "keysymdec=$keysymdec" );
|
|
|
|
$self->debug( 3, "keycode =$keycode" );
|
|
|
|
$self->debug( 3, "state =$state" );
|
|
|
|
$self->debug( 3, "codetosym=$keycodetosym{$keysymdec}" )
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $keycodetosym{$keysymdec} );
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "symtocode=$keysymtocode{$keysym}" );
|
|
|
|
$self->debug( 3, "keyboard =$keyboardmap{ $keysym }" )
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $keyboardmap{$keysym} );
|
|
|
|
|
|
|
|
#warn("debug stop point here");
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{use_hotkeys} eq "yes" ) {
|
2010-06-18 22:10:33 +01:00
|
|
|
my $combo = $Tk::event->s . $Tk::event->K;
|
|
|
|
|
|
|
|
$combo =~ s/Mod\d-//;
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "combo=$combo" );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-17 22:53:06 +00:00
|
|
|
foreach my $hotkey ( grep( /key_/, keys( %{ $self->config } ) ) ) {
|
2011-07-28 10:23:49 +01:00
|
|
|
my $key = $self->config->{$hotkey};
|
2010-06-18 22:10:33 +01:00
|
|
|
next if ( $key eq "null" ); # ignore disabled keys
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "key=:$key:" );
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $combo =~ /^$key$/ ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, "matched combo" );
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $event eq "KeyRelease" ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Received hotkey: $hotkey" );
|
2014-01-13 18:44:12 +00:00
|
|
|
$self->send_text_to_all_servers('%s')
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $hotkey eq "key_clientname" );
|
2014-01-13 18:44:12 +00:00
|
|
|
$self->send_text_to_all_servers('%h')
|
2013-04-21 22:13:54 +01:00
|
|
|
if ( $hotkey eq "key_localname" );
|
2014-01-13 18:44:12 +00:00
|
|
|
$self->send_text_to_all_servers('%u')
|
2013-04-21 22:05:17 +01:00
|
|
|
if ( $hotkey eq "key_username" );
|
2011-11-21 22:36:25 +00:00
|
|
|
$self->add_host_by_name()
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $hotkey eq "key_addhost" );
|
2011-11-21 22:36:25 +00:00
|
|
|
$self->retile_hosts("force")
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $hotkey eq "key_retilehosts" );
|
2013-04-21 22:09:43 +01:00
|
|
|
$self->show_history() if ( $hotkey eq "key_history" );
|
2014-06-28 11:40:00 +01:00
|
|
|
$self->exit_prog() if ( $hotkey eq "key_quit" );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# look for a <Control>-d and no hosts, so quit
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->exit_prog()
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $state =~ /Control/ && $keysym eq "d" and !%servers );
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->update_display_text( $keycodetosym{$keysymdec} )
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $event eq "KeyPress" && $keycodetosym{$keysymdec} );
|
|
|
|
|
|
|
|
# for all servers
|
|
|
|
foreach ( keys(%servers) ) {
|
|
|
|
|
|
|
|
# if active
|
|
|
|
if ( $servers{$_}{active} == 1 ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3,
|
2010-06-18 22:10:33 +01:00
|
|
|
"Sending event $event with code $keycode (state=$state) to window $servers{$_}{wid}"
|
|
|
|
);
|
|
|
|
|
|
|
|
$xdisplay->SendEvent(
|
|
|
|
$servers{$_}{wid},
|
|
|
|
0,
|
|
|
|
$xdisplay->pack_event_mask($event),
|
|
|
|
$xdisplay->pack_event(
|
|
|
|
'name' => $event,
|
|
|
|
'detail' => $keycode,
|
|
|
|
'state' => $state,
|
|
|
|
'time' => time(),
|
|
|
|
'event' => $servers{$_}{wid},
|
|
|
|
'root' => $xdisplay->root(),
|
|
|
|
'same_screen' => 1,
|
|
|
|
)
|
|
|
|
) || warn("Error returned from SendEvent: $!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$xdisplay->flush();
|
2011-07-28 10:23:49 +01:00
|
|
|
|
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub create_menubar() {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ($self) = @_;
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "create_menubar: started" );
|
2013-02-15 08:26:41 +00:00
|
|
|
$menus{bar} = $windows{main_window}->Menu();
|
|
|
|
$windows{main_window}->configure( -menu => $menus{bar}, );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$menus{file} = $menus{bar}->cascade(
|
|
|
|
-label => 'File',
|
|
|
|
-menuitems => [
|
|
|
|
[ "command",
|
|
|
|
"Show History",
|
2014-06-28 11:40:00 +01:00
|
|
|
-command => sub { $self->show_history; },
|
2011-07-28 10:23:49 +01:00
|
|
|
-accelerator => $self->config->{key_history},
|
2010-06-18 22:10:33 +01:00
|
|
|
],
|
|
|
|
[ "command",
|
|
|
|
"Exit",
|
2014-06-28 11:40:00 +01:00
|
|
|
-command => sub { $self->exit_prog },
|
2011-07-28 10:23:49 +01:00
|
|
|
-accelerator => $self->config->{key_quit},
|
2010-06-18 22:10:33 +01:00
|
|
|
]
|
|
|
|
],
|
|
|
|
-tearoff => 0,
|
|
|
|
);
|
|
|
|
|
|
|
|
$menus{hosts} = $menus{bar}->cascade(
|
|
|
|
-label => 'Hosts',
|
|
|
|
-tearoff => 1,
|
|
|
|
-menuitems => [
|
|
|
|
[ "command",
|
|
|
|
"Retile Windows",
|
2013-02-15 08:26:41 +00:00
|
|
|
-command => sub { $self->retile_hosts },
|
2011-07-28 10:23:49 +01:00
|
|
|
-accelerator => $self->config->{key_retilehosts},
|
2010-06-18 22:10:33 +01:00
|
|
|
],
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
# [ "command", "Capture Terminal", -command => sub { $self->capture_terminal), ],
|
2014-06-20 09:53:38 +00:00
|
|
|
[ "command",
|
|
|
|
"Set all active",
|
|
|
|
-command => sub { $self->set_all_active() },
|
|
|
|
],
|
|
|
|
[ "command",
|
|
|
|
"Set half inactive",
|
|
|
|
-command => sub { $self->set_half_inactive() },
|
|
|
|
],
|
2010-06-18 22:10:33 +01:00
|
|
|
[ "command",
|
|
|
|
"Toggle active state",
|
2013-02-15 08:26:41 +00:00
|
|
|
-command => sub { $self->toggle_active_state() },
|
2010-06-18 22:10:33 +01:00
|
|
|
],
|
|
|
|
[ "command",
|
|
|
|
"Close inactive sessions",
|
2013-02-15 08:26:41 +00:00
|
|
|
-command => sub { $self->close_inactive_sessions() },
|
2010-06-18 22:10:33 +01:00
|
|
|
],
|
|
|
|
[ "command",
|
|
|
|
"Add Host(s) or Cluster(s)",
|
2013-02-15 08:26:41 +00:00
|
|
|
-command => sub { $self->add_host_by_name, },
|
2011-07-28 10:23:49 +01:00
|
|
|
-accelerator => $self->config->{key_addhost},
|
2010-06-18 22:10:33 +01:00
|
|
|
],
|
|
|
|
'',
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
$menus{send} = $menus{bar}->cascade(
|
|
|
|
-label => 'Send',
|
|
|
|
-tearoff => 1,
|
|
|
|
);
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->populate_send_menu();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
$menus{help} = $menus{bar}->cascade(
|
|
|
|
-label => 'Help',
|
|
|
|
-menuitems => [
|
|
|
|
[ 'command', "About", -command => sub { $windows{help}->Show } ],
|
|
|
|
[ 'command', "Documentation",
|
|
|
|
-command => sub { $windows{manpage}->Show }
|
|
|
|
],
|
|
|
|
],
|
|
|
|
-tearoff => 0,
|
|
|
|
);
|
|
|
|
|
2011-11-21 22:36:25 +00:00
|
|
|
$windows{main_window}->bind( '<KeyPress>' => [ $self => 'key_event' ], );
|
2013-02-15 08:26:41 +00:00
|
|
|
$windows{main_window}
|
|
|
|
->bind( '<KeyRelease>' => [ $self => 'key_event' ], );
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "create_menubar: completed" );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub populate_send_menu_entries_from_xml {
|
2011-07-28 10:23:49 +01:00
|
|
|
my ( $self, $menu, $menu_xml ) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
foreach my $menu_ref ( @{ $menu_xml->{menu} } ) {
|
|
|
|
if ( $menu_ref->{menu} ) {
|
|
|
|
$menus{ $menu_ref->{title} }
|
|
|
|
= $menu->cascade( -label => $menu_ref->{title}, );
|
2011-11-17 22:53:06 +00:00
|
|
|
$self->populate_send_menu_entries_from_xml(
|
|
|
|
$menus{ $menu_ref->{title} }, $menu_ref, );
|
2010-06-18 22:10:33 +01:00
|
|
|
if ( $menu_ref->{detach} && $menu_ref->{detach} =~ m/y/i ) {
|
|
|
|
$menus{ $menu_ref->{title} }->menu->tearOffMenu()->raise;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
my $accelerator = undef;
|
|
|
|
if ( $menu_ref->{accelerator} ) {
|
|
|
|
$accelerator = $menu_ref->{accelerator};
|
|
|
|
}
|
2014-01-13 18:44:12 +00:00
|
|
|
if ( $menu_ref->{toggle} ) {
|
|
|
|
$menus{send}->checkbutton(
|
|
|
|
-label => 'Use Macros',
|
|
|
|
-variable => \$self->config->{macros_enabled},
|
|
|
|
-offvalue => 'no',
|
|
|
|
-onvalue => 'yes',
|
|
|
|
-accelerator => $accelerator,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
my $command = undef;
|
|
|
|
if ( $menu_ref->{command} ) {
|
|
|
|
$command = sub {
|
|
|
|
$self->send_text_to_all_servers(
|
|
|
|
$menu_ref->{command}[0] );
|
|
|
|
};
|
|
|
|
}
|
|
|
|
$menu->command(
|
|
|
|
-label => $menu_ref->{title},
|
|
|
|
-command => $command,
|
|
|
|
-accelerator => $accelerator,
|
|
|
|
);
|
|
|
|
}
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub populate_send_menu {
|
2011-11-17 22:53:06 +00:00
|
|
|
my ($self) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# my @menu_items = ();
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( !-r $self->config->{send_menu_xml_file} ) {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, 'Using default send menu' );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-01-13 18:44:12 +00:00
|
|
|
$menus{send}->checkbutton(
|
|
|
|
-label => 'Use Macros',
|
|
|
|
-variable => \$self->config->{macros_enabled},
|
|
|
|
-offvalue => 'no',
|
|
|
|
-onvalue => 'yes',
|
|
|
|
-accelerator => $self->config->{key_macros_enable},
|
|
|
|
);
|
|
|
|
|
2010-06-18 22:10:33 +01:00
|
|
|
$menus{send}->command(
|
2014-01-13 18:44:12 +00:00
|
|
|
-label => 'Remote Hostname',
|
|
|
|
-command => sub {
|
|
|
|
$self->send_text_to_all_servers(
|
|
|
|
$self->config->{macro_servername} );
|
|
|
|
},
|
2013-04-21 22:09:43 +01:00
|
|
|
-accelerator => $self->config->{key_clientname},
|
|
|
|
);
|
|
|
|
$menus{send}->command(
|
2014-01-13 18:44:12 +00:00
|
|
|
-label => 'Local Hostname',
|
|
|
|
-command => sub {
|
|
|
|
$self->send_text_to_all_servers(
|
|
|
|
$self->config->{macro_hostname} );
|
|
|
|
},
|
2013-04-21 22:13:54 +01:00
|
|
|
-accelerator => $self->config->{key_localname},
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
2013-04-21 22:05:17 +01:00
|
|
|
$menus{send}->command(
|
2014-01-13 18:44:12 +00:00
|
|
|
-label => 'Username',
|
|
|
|
-command => sub {
|
|
|
|
$self->send_text_to_all_servers(
|
|
|
|
$self->config->{macro_username} );
|
|
|
|
},
|
2013-04-21 22:05:17 +01:00
|
|
|
-accelerator => $self->config->{key_username},
|
|
|
|
);
|
2014-01-13 18:44:12 +00:00
|
|
|
$menus{send}->command(
|
|
|
|
-label => 'Test Text',
|
|
|
|
-command => sub {
|
|
|
|
$self->send_text_to_all_servers( 'echo ClusterSSH Version: '
|
|
|
|
. $self->config->{macro_version}
|
|
|
|
. $self->config->{macro_newline} );
|
|
|
|
},
|
|
|
|
);
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug(
|
2010-06-18 22:10:33 +01:00
|
|
|
2,
|
|
|
|
'Using xml send menu definition from ',
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->config->{send_menu_xml_file}
|
2010-06-18 22:10:33 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
eval { require XML::Simple; };
|
|
|
|
die 'Cannot load XML::Simple - has it been installed? ', $@ if ($@);
|
|
|
|
|
|
|
|
my $xml = XML::Simple->new( ForceArray => 1, );
|
2011-07-28 10:23:49 +01:00
|
|
|
my $menu_xml = $xml->XMLin( $self->config->{send_menu_xml_file} );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 3, 'xml send menu: ', $/, $xml->XMLout($menu_xml) );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
if ( $menu_xml->{detach} && $menu_xml->{detach} =~ m/y/i ) {
|
|
|
|
$menus{send}->menu->tearOffMenu()->raise;
|
|
|
|
}
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->populate_send_menu_entries_from_xml( $menus{send}, $menu_xml );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
return $self;
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub run {
|
2010-06-18 23:17:42 +01:00
|
|
|
my ($self) = @_;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-05-17 17:32:03 +01:00
|
|
|
$self->getopts;
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
### main ###
|
|
|
|
|
|
|
|
# only get xdisplay if we got past usage and help stuff
|
|
|
|
$xdisplay = X11::Protocol->new();
|
|
|
|
|
|
|
|
if ( !$xdisplay ) {
|
|
|
|
die("Failed to get X connection\n");
|
|
|
|
}
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "VERSION: $VERSION" );
|
2011-11-24 21:48:35 +00:00
|
|
|
|
2014-06-28 11:40:00 +01:00
|
|
|
$self->config->{ssh_args} = $self->options->options
|
|
|
|
if ( $self->options->options );
|
2011-11-25 22:09:33 +00:00
|
|
|
|
2014-06-28 11:39:28 +01:00
|
|
|
$self->config->{terminal_args} = $self->options->term_args
|
|
|
|
if ( $self->options->term_args );
|
2011-11-25 22:09:33 +00:00
|
|
|
|
|
|
|
if ( $self->config->{terminal_args} =~ /-class (\w+)/ ) {
|
|
|
|
$self->config->{terminal_allow_send_events}
|
|
|
|
= "-xrm '$1.VT100.allowSendEvents:true'";
|
|
|
|
}
|
|
|
|
|
2014-06-28 11:40:00 +01:00
|
|
|
$self->config->dump() if ( $self->options->dump_config );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-27 18:17:22 +01:00
|
|
|
$self->evaluate_commands() if ( $self->options->evaluate );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-18 22:19:00 +00:00
|
|
|
$self->get_font_size();
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->load_keyboard_map();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-11-21 22:03:54 +00:00
|
|
|
# read in normal cluster files
|
2014-06-28 11:39:28 +01:00
|
|
|
$self->config->{extra_cluster_file} .= ',' . $self->options->cluster_file
|
|
|
|
if ( $self->options->cluster_file );
|
|
|
|
$self->config->{extra_tag_file} .= ',' . $self->options->tag_file
|
|
|
|
if ( $self->options->tag_file );
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2013-03-25 13:13:03 +00:00
|
|
|
$self->cluster->get_cluster_entries( split /,/,
|
|
|
|
$self->config->{extra_cluster_file} || '' );
|
|
|
|
$self->cluster->get_tag_entries( split /,/,
|
|
|
|
$self->config->{extra_tag_file} || '' );
|
2011-11-21 22:03:54 +00:00
|
|
|
|
2014-06-27 18:17:22 +01:00
|
|
|
if ( $self->options->list ) {
|
2011-11-21 22:03:54 +00:00
|
|
|
print( 'Available cluster tags:', $/ );
|
|
|
|
print "\t", $_, $/ foreach ( sort( $self->cluster->list_tags ) );
|
2013-03-19 18:07:39 +00:00
|
|
|
|
2014-08-10 10:36:22 +01:00
|
|
|
my @external_clusters = $self->cluster->list_external_clusters;
|
|
|
|
if(@external_clusters) {
|
|
|
|
print( 'Available external command tags:', $/ );
|
|
|
|
print "\t", $_, $/ foreach ( sort( @external_clusters ) );
|
|
|
|
}
|
2014-07-05 20:25:14 +01:00
|
|
|
|
2013-03-25 13:13:03 +00:00
|
|
|
$self->debug(
|
|
|
|
4,
|
|
|
|
"Full clusters dump: ",
|
|
|
|
$self->_dump_args_hash( $self->cluster->dump_tags )
|
|
|
|
);
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->exit_prog();
|
2011-11-21 22:03:54 +00:00
|
|
|
}
|
2010-09-09 21:22:53 +01:00
|
|
|
|
2010-06-18 22:10:33 +01:00
|
|
|
if (@ARGV) {
|
2011-11-18 22:31:12 +00:00
|
|
|
@servers = $self->resolve_names(@ARGV);
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-01-04 15:07:34 +00:00
|
|
|
|
|
|
|
#if ( my @default = $self->cluster->get_tag('default') ) {
|
2011-11-21 22:03:54 +00:00
|
|
|
if ( $self->cluster->get_tag('default') ) {
|
2011-11-18 22:31:12 +00:00
|
|
|
@servers
|
2014-01-04 15:07:34 +00:00
|
|
|
|
|
|
|
# = $self->resolve_names( @default );
|
2011-11-21 22:03:54 +00:00
|
|
|
= $self->resolve_names( $self->cluster->get_tag('default') );
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->create_windows();
|
|
|
|
$self->create_menubar();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->change_main_window_title();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Capture map events" );
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->capture_map_events();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 0, 'Opening to: ', join( ' ', @servers ) );
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->open_client_windows(@servers);
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# Check here if we are tiling windows. Here instead of in func so
|
|
|
|
# can be tiled from console window if wanted
|
2011-07-28 10:23:49 +01:00
|
|
|
if ( $self->config->{window_tiling} eq "yes" ) {
|
|
|
|
$self->retile_hosts();
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
else {
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->show_console();
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->build_hosts_menu();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Sleeping for a mo" );
|
2010-06-18 22:10:33 +01:00
|
|
|
select( undef, undef, undef, 0.5 );
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Sorting focus on console" );
|
2010-06-18 22:10:33 +01:00
|
|
|
$windows{text_entry}->focus();
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Marking main window as user positioned" );
|
2010-06-18 22:10:33 +01:00
|
|
|
$windows{main_window}->positionfrom('user')
|
|
|
|
; # user puts it somewhere, leave it there
|
|
|
|
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Setting up repeat" );
|
2011-07-28 10:23:49 +01:00
|
|
|
$self->setup_repeat();
|
2010-06-18 22:10:33 +01:00
|
|
|
|
|
|
|
# Start event loop
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->debug( 2, "Starting MainLoop" );
|
2010-06-18 22:10:33 +01:00
|
|
|
MainLoop();
|
|
|
|
|
|
|
|
# make sure we leave program in an expected way
|
2014-06-21 08:30:23 +01:00
|
|
|
$self->exit_prog();
|
2010-06-18 22:10:33 +01:00
|
|
|
}
|
|
|
|
|
2009-12-19 17:30:00 +00:00
|
|
|
1;
|
|
|
|
|
|
|
|
__END__
|
|
|
|
|
2010-06-20 20:23:41 +01:00
|
|
|
=pod
|
|
|
|
|
2009-12-19 17:30:00 +00:00
|
|
|
=head1 NAME
|
|
|
|
|
2010-06-20 20:23:41 +01:00
|
|
|
App::ClusterSSH - A container for functions of the ClusterSSH programs
|
2009-12-19 17:30:00 +00:00
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
2010-06-20 20:23:41 +01:00
|
|
|
There is nothing in this module for public consumption. See documentation
|
2011-06-30 11:12:59 +01:00
|
|
|
for F<cssh>, F<crsh>, F<ctel>, F<ccon>, or F<cscp> instead.
|
2010-06-20 20:23:41 +01:00
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
2014-02-17 15:39:20 -08:00
|
|
|
This is the core for App::ClusterSSH. You should probably look at L<cssh>
|
2010-06-20 20:23:41 +01:00
|
|
|
instead.
|
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2010-06-20 20:23:41 +01:00
|
|
|
These methods are listed here to tidy up Pod::Coverage test reports but
|
2010-06-18 23:25:49 +01:00
|
|
|
will most likely be moved into other modules. There are some notes within
|
|
|
|
the code until this time.
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2010-06-18 23:25:49 +01:00
|
|
|
=over 2
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2010-06-18 23:25:49 +01:00
|
|
|
=item REAPER
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2010-06-18 23:25:49 +01:00
|
|
|
=item add_host_by_name
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item add_option
|
|
|
|
|
2010-06-18 23:25:49 +01:00
|
|
|
=item build_hosts_menu
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2010-06-18 23:25:49 +01:00
|
|
|
=item capture_map_events
|
|
|
|
|
|
|
|
=item capture_terminal
|
|
|
|
|
|
|
|
=item change_main_window_title
|
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item close_inactive_sessions
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item config
|
2011-07-21 08:23:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item helper
|
2011-08-31 21:01:12 +01:00
|
|
|
|
2011-11-24 21:48:35 +00:00
|
|
|
=item cluster
|
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item create_menubar
|
|
|
|
|
|
|
|
=item create_windows
|
|
|
|
|
|
|
|
=item dump_config
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item getopts
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item list_tags
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item evaluate_commands
|
2010-09-09 21:22:53 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item exit_prog
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item get_clusters
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item get_font_size
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item get_keycode_state
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item key_event
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item load_config_defaults
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item load_configfile
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item load_keyboard_map
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item logmsg
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item new
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item open_client_windows
|
2009-12-19 17:30:00 +00:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item options
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item parse_config_file
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item pick_color
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item populate_send_menu
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item populate_send_menu_entries_from_xml
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2013-02-27 10:26:05 +00:00
|
|
|
=item remove_repeated_servers
|
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item resolve_names
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item retile_hosts
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item run
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item send_resizemove
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item send_text
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item send_text_to_all_servers
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-07-09 20:25:42 +01:00
|
|
|
=item set_all_active
|
|
|
|
|
|
|
|
=item set_half_inactive
|
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item setup_repeat
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item show_console
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item show_history
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item terminate_host
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item toggle_active_state
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item update_display_text
|
2010-06-18 23:25:49 +01:00
|
|
|
|
2014-06-29 12:49:37 +01:00
|
|
|
=item write_default_user_config
|
2010-06-18 23:25:49 +01:00
|
|
|
|
|
|
|
=back
|
2009-12-19 17:30:00 +00:00
|
|
|
|
|
|
|
=head1 BUGS
|
|
|
|
|
|
|
|
Please report any bugs or feature requests to C<bug-app-clusterssh at rt.cpan.org>, or through
|
|
|
|
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-ClusterSSH>. I will be notified, and then you'll
|
|
|
|
automatically be notified of progress on your bug as I make changes.
|
|
|
|
|
|
|
|
=head1 SUPPORT
|
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command.
|
|
|
|
|
|
|
|
perldoc App::ClusterSSH
|
|
|
|
|
|
|
|
You can also look for information at:
|
|
|
|
|
|
|
|
=over 4
|
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker
|
|
|
|
|
|
|
|
L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-ClusterSSH>
|
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation
|
|
|
|
|
|
|
|
L<http://annocpan.org/dist/App-ClusterSSH>
|
|
|
|
|
|
|
|
=item * CPAN Ratings
|
|
|
|
|
|
|
|
L<http://cpanratings.perl.org/d/App-ClusterSSH>
|
|
|
|
|
|
|
|
=item * Search CPAN
|
|
|
|
|
|
|
|
L<http://search.cpan.org/dist/App-ClusterSSH/>
|
|
|
|
|
|
|
|
=back
|
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS
|
|
|
|
|
2010-06-20 20:23:41 +01:00
|
|
|
Please see the THANKS file from the original distribution.
|
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
|
|
|
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
|
|
|
2009-12-19 17:30:00 +00:00
|
|
|
=head1 COPYRIGHT & LICENSE
|
|
|
|
|
2010-06-20 17:55:24 +01:00
|
|
|
Copyright 1999-2010 Duncan Ferguson, all rights reserved.
|
2009-12-19 17:30:00 +00:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
2010-06-20 20:23:41 +01:00
|
|
|
under the terms of either: the GNU General Public License as published
|
|
|
|
by the Free Software Foundation; or the Artistic License.
|
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information.
|
2009-12-19 17:30:00 +00:00
|
|
|
|
|
|
|
=cut
|
|
|
|
|
2010-06-20 20:23:41 +01:00
|
|
|
1;
|