3 # A GTK based console program
5 # usage: gtkconsole [<callsign>] [<host> <port>]
7 # Copyright (c) 2006-2007 Dirk Koopman G1TLH
16 # search local then perl directories
18 # root of directory tree for this system
20 $root = $ENV{'DXSPIDER_ROOT'} if $ENV{'DXSPIDER_ROOT'};
32 use vars qw(@modules $font);
34 @modules = (); # is the list of modules that need init calling
35 # on them. It is set up by each 'use'ed module
36 # that has Gtk stuff in it
39 our @month = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
42 our $main; # the main screen
43 our $scr_width; # calculated screen dimensions
45 our ($dx, $cmd, $ann, $wcy, $wwv, $chat); # scrolling list windows
46 our $bot; # the cmd entry window
47 our $date; # the current date
50 our $annwin; # the announcement window handle
51 our $dxwin; # the dx spot window handle
52 our $wwvwin; # wwv window handle
53 our $wcywin; # wcy window handle
54 our $chatwin; # chat window handle
57 our ($wantann, $wantdx, $wantwwv, $wantwcy, $wantchat) = (1, 1, 1, 1, 1);
59 require "$root/local/DXVars.pm" if -e "$root/local/DXVars.pm";
61 our ($version, $subversion, $build);
62 require "$root/perl/Version.pm";
64 our $VERSION = "$version.$subversion build $build";
66 # read in the user data
67 our $userfn = "$ENV{HOME}/.gtkconsole_data";
68 our $user = read_user_data();
71 our $host = 'localhost';
75 # read in gtkconsole file
78 Gtk2::Rc->set_default_files("$root/gtkconsole/gtkconsolerc", "$ENV{HOME}/.gtkconsolerc", ".gtkconsolerc");
79 Gtk2::Rc->reparse_all;
81 # sort out a callsign, host and port, looking in order
83 # 2. any defaults in the user data;
84 # 3. poke about in any spider tree that we can find
88 $call = uc shift @ARGV;
89 $host = shift @ARGV if @ARGV;
90 $port = shift @ARGV if @ARGV;
94 $call = $main::myalias;
98 my $node = $user->{clusters}->{$user->{node}};
100 if ($node->{call} || $user->{call}) {
101 $host = $node->{host};
102 $port ||= $node->{port};
106 if (-e "$root/local/Listeners.pm") {
107 require "$root/local/Listeners.pm";
108 $host = $main::listen->[0]->[0];
109 $port = $main::listen->[0]->[1];
110 $host ||= '127.0.0.1';
111 $host = "127.0.0.1" if !$host && ($host eq '0.0.0.0' || $host eq '::');
120 die "You need a callsign ($call), a hostname($host) and a port($port) to proceed" unless $call && $host && $port;
126 gtk_create_main_screen();
128 $main->set_title("DXSpider gtkconsole $VERSION - $call \@ $host:$port");
130 # connect and send stuff
131 my $sock = IO::Socket::INET->new(PeerAddr=>$host, PeerPort=>$port);
132 die "Cannot connect to $/$port ($!)\n" unless $sock;
134 sendmsg($passwd) if $passwd;
136 sendmsg('set/page 500');
137 sendmsg('set/nobeep');
139 my $sock_helper = Gtk2::Helper->add_watch($sock->fileno, 'in', \&tophandler, $sock);
153 $_[0]->set_text(cldatetime(time));
159 my ($self, $data) = @_;
160 my $msg = $self->get_text;
171 my ($fd, $condx, $socket) = @_;
173 my $offset = defined $rbuf ? length $rbuf : 0;
174 my $l = sysread($socket, $rbuf, 1024, $offset);
177 while ($rbuf =~ s/^([^\015\012]*)\015?\012//) {
195 # this is truely evil and I bet there is a better way...
198 if ($line =~ /^'\w{2,4}',/) {
199 $list = eval qq([$line]);
201 $list = ['cmd', $line];
205 my $cmd = shift @$list;
206 my $handle = "handle_$cmd";
207 if (__PACKAGE__->can($handle)) {
208 __PACKAGE__->$handle($list);
210 unshift @$list, $cmd;
211 __PACKAGE__->handle_def($list);
220 my ($t, $ts) = (time, '');
222 $s = ref $ref ? join ', ',@$ref : $ref;
224 if (($cmd->{lasttime}||0) != $t) {
226 $cmd->{lasttime} = $t;
230 $cmd->add_data([$ts, $s]);
237 my ($t, $ts) = (time, '');
239 $s = ref $ref ? join(', ', @$ref) : $ref;
240 if (($cmd->{lasttime}||0) != $t) {
242 $cmd->{lasttime} = $t;
244 $cmd->add_data([$ts, $s]);
251 my ($t, $ts) = (time, '');
253 if (($dx->{lasttime}||0) != $t) {
255 $dx->{lasttime} = $t;
257 $dx->add_data([$ts, @$ref[0,1,15,3,4,16], stim($ref->[2]) ]);
265 my ($t, $ts) = (time, '');
267 # $s = ref $ref ? (join ', ',@$ref) : $ref;
269 if (($ann->{lasttime}||0) != $t) {
271 $ann->{lasttime} = $t;
275 $ann->add_data([$ts, @$ref[3,1,2]]);
284 # $s = ref $ref ? join ', ',@$ref : $ref;
288 $wcy->add_data([tim(), @$ref[10,4,5,3,6,2,7,8,9,1] ]);
297 # $s = ref $ref ? join ', ',@$ref : $ref;
300 $wwv->add_data([tim(), @$ref[6,2,3,4,5,1] ]);
309 my ($t, $ts) = (time, '');
311 $s = ref $ref ? (join ', ',@$ref) : $ref;
313 if (($ann->{lasttime}||0) != $t) {
315 $ann->{lasttime} = $t;
319 $chat->add_data([$ts, @$ref[3,1,2]]);
332 $sock->print("$msg\n");
337 my $t = shift || time;
338 return sprintf "%02d:%02d:%02d", (gmtime($t))[2,1,0];
343 my $t = shift || time;
344 return sprintf "%02d:%02d", (gmtime($t))[2,1];
347 # get a zulu time in cluster format (2300Z)
351 $t = defined $t ? $t : time;
353 my ($sec,$min,$hour) = $dst ? localtime($t): gmtime($t);
354 my $buf = sprintf "%02d%02d%s", $hour, $min, ($dst) ? '' : 'Z';
358 # get a cluster format date (23-Jun-1998)
362 $t = defined $t ? $t : time;
364 my ($sec,$min,$hour,$mday,$mon,$year) = $dst ? localtime($t) : gmtime($t);
366 my $buf = sprintf "%2d-%s-%04d", $mday, $month[$mon], $year;
370 # return a cluster style date time
375 my $date = cldate($t, $dst);
376 my $time = ztime($t, $dst);
377 return "$date $time";
385 my $fh = new IO::File $userfn;
395 print "$userfn missing or unreadable, starting afresh!\n";
399 'LOCAL' => {host => '127.0.0.1', port => 7300},
400 'GB7DJK' => {host => 'gb7djk.dxcluster.net', port => 7300},
401 'WR3D' => {host => 'wr3d.dxcluster.net', port => 7300},
402 'GB7BAA' => {host => 'gb7baa.dxcluster.net', port => 7300},
405 call => $main::myalias,
416 my $fh = new IO::File ">$userfn";
418 my $dd = new Data::Dumper([ $u ]);
422 $fh->print($dd->Dumpxs);
429 sub def_menu_callback
440 sub gtk_create_main_screen
442 $main = new Gtk2::Window('toplevel');
443 my $scr = $main->get_screen;
444 $scr_width = $scr->get_width;
445 $scr_width = 700 if $scr_width > 700;
446 $scr_height = int ($scr->get_height * 0.66);
447 $main->set_default_size($scr_width, $scr_height);
448 $main->signal_connect('delete_event', sub { Gtk2->main_quit; });
451 my $vbox = new Gtk2::VBox(0, 1);
456 item_type => '<Branch>',
459 callback => sub { Gtk2->main_quit; },
460 callback_action => 1,
461 accelerator => '<ctrl>Q',
466 item_type =>'<Branch>',
469 item_type => '<CheckMenuItem>',
470 callback => sub { set_win(\$wantdx, $@)},
473 item_type => '<CheckItem>',
474 callback => sub { set_win(\$wantann, $@)},
477 item_type => '<CheckItem>',
478 callback => sub { set_win(\$wantchat, $@)},
481 item_type => '<CheckItem>',
482 callback => sub { set_win(\$wantwwv, $@)},
485 item_type => '<CheckItem>',
486 callback => sub { set_win(\$wantwcy, $@)},
492 item_type => '<Branch>',
495 callback_action => 9,
502 my $menu = Gtk2::SimpleMenu->new(menu_tree => $menutree, default_callback => \&def_menu_callback, user_data => $user);
503 $vbox->pack_start($menu->{widget}, 0, 1, 0);
506 # a paned hbox is packed as the bottom of the vbox
507 # my $bhpane = Gtk2::HPaned->new;
508 # $vbox->pack_end($bhpane, 1, 1, 0);
510 # now create the lh and rh panes
511 # my $lhvpane = Gtk2::VPaned->new;
512 # my $rhvpane = Gtk2::VPaned->new;
513 # $bhpane->pack1($lhvpane, 1, 0);
514 # $bhpane->pack2($rhvpane, 1, 0);
518 # my $lhvbox = Gtk2::VBox->new(0, 1);
519 $cmd = Screen::List->new(fields => [
521 Information => 'ttlong',
523 size => [$scr_width, $scr_height * 0.66],
525 $vbox->pack_start($cmd->widget, 1, 1, 0);
528 # callsign and current date and time
529 my $hbox = new Gtk2::HBox;
530 my $calllabel = new Gtk2::Label($call);
531 my $date = new Gtk2::Label(cldatetime(time));
532 $date->{tick} = Glib::Timeout->add(1000, \&updatetime, $date);
533 $hbox->pack_start( $calllabel, 0, 1, 0 );
534 $hbox->pack_end($date, 0, 1, 0);
535 $vbox->pack_start($hbox, 0, 1, 0);
536 $vbox->pack_start(Gtk2::HSeparator->new, 0, 1, 0);
539 $bot = new Gtk2::Entry;
540 $bot->set_editable(1);
541 $bot->signal_connect('activate', \&bothandler);
542 $bot->can_default(1);
543 $vbox->pack_end($bot, 0, 1, 0);
544 # $lhvpane->pack2($lhvbox, 1, 0);
553 $annwin = new Gtk2::Window('toplevel');
554 $ann = Screen::List->new(fields =>[
558 Announcement => 'ttlesslong',
561 frame => 'Announcements',
562 size => [$scr_width * 0.85, $scr_height * 0.25],
564 $annwin->add($ann->widget);
568 $chatwin = new Gtk2::Window('toplevel');
569 $chat = Screen::List->new(fields =>[
573 Chat => 'ttlesslong',
577 size => [$scr_width * 0.85, $scr_height * 0.25],
579 $chatwin->add($chat->widget);
583 $dxwin = new Gtk2::Window('toplevel');
584 $dx = Screen::List->new(fields => [
589 'Remarks' => 'ttshort',
594 policy => [qw(never automatic)],
598 size => [$scr_width * 0.9, $scr_height * 0.25],
600 # $rhvpane->pack1($dx->widget, 1, 0);
601 $dxwin->add($dx->widget);
605 $wwvwin = new Gtk2::Window('toplevel');
606 # my $rhvbox = Gtk2::VBox->new(0, 1);
607 $wwv = Screen::List->new( fields =>[
613 Remarks => 'ttshort',
617 policy => ['never', 'automatic'],
620 $wwvwin->add($wwv->widget);
623 # $rhvbox->pack_start($wwv->widget, 1, 1, 0);
626 $wcywin = new Gtk2::Window('toplevel');
627 $wcy = Screen::List->new(fields => [
641 policy => ['never', 'automatic'],
645 # $rhvbox->pack_start($wcy->widget, 1, 1, 0);
646 # $rhvbox->set_size_request($scr_width * 0.45, $scr_height * 0.33);
647 # $rhvpane->pack2($rhvbox, 1, 0);
648 $wcywin->add($wcy->widget);