summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--background.gifbin0 -> 24678 bytes
-rw-r--r--ivybanner828
-rw-r--r--ivybanner.conf11
-rw-r--r--logo.gifbin0 -> 4386 bytes
4 files changed, 839 insertions, 0 deletions
diff --git a/background.gif b/background.gif
new file mode 100644
index 0000000..ce0af36
--- /dev/null
+++ b/background.gif
Binary files differ
diff --git a/ivybanner b/ivybanner
new file mode 100644
index 0000000..083b6b3
--- /dev/null
+++ b/ivybanner
@@ -0,0 +1,828 @@
+#!/usr/bin/perl
+#
+# ivybanner, a banner to launch demos using ivy
+#
+# Author: Daniel Etienne <etienne@cena.fr>
+#
+# ivybanner is derived from the toccata-banner application
+# written by Johnny Accot and Michelle Jacomi and maintained
+# by Christophe Mertz <mertz@cena.fr>
+#
+# $Id$
+#
+
+use strict;
+use Tk;
+use Getopt::Long;
+use vars qw(%opt);
+# where you may find image files
+use lib "/usr/share/ivybanner";
+
+
+
+# variables definition
+#------------------------
+
+my $logdir = "/tmp";
+my $logfile = "ivybanner-";
+
+my $conffile = "/etc/ivybanner.conf";
+my $width = 1024;
+my $height = 768;
+
+# the following variables can be overloaded in configuration file
+my $ivylaunch_command = "/usr/bin/ivylaunch";
+my $default_domain;
+my @ivyports = (2010, 3009, 3110, 3945);
+my $default_port = 3110;
+
+# font spec
+my @fontspec24 = (-font =>
+ '-b&h-lucida-bold-i-normal-sans-24-240-100-100-p-216-iso8859-1');
+my @fontspec17 = (-font =>
+ '-adobe-helvetica-bold-r-normal--17-120-100-100-p-92-iso10646-1');
+
+# colors spec
+my $darkbg = '#1E161B';
+my $bg = '#5C5655';
+my $hlbg = '#7CC452';
+my $fg = '#FCFAFC';
+my $selcolor = 'yellow';
+
+# misc
+my $demosdir;
+my $testsdir;
+my $selected_button;
+my $selected_demo;
+my $view_button;
+my $launch_button;
+
+# parse options
+#------------------------
+&usage unless Getopt::Long::GetOptions(\%opt, 'conf=s', 'testdir=s', '-dir=s',
+ 'nocursor', 'help', 'override');
+&usage if $opt{help};
+
+if ($opt{conf}) {
+ if (not -f $opt{conf}) {
+ die "No such file $opt{conf}\n";
+ } elsif (not -r $opt{conf}) {
+ die "File $opt{conf} is unreadable\n";
+ } else {
+ $conffile = $opt{conf};
+ }
+}
+
+if ($opt{dir}) {
+ $demosdir = $opt{dir};
+} elsif ($ENV{'IVYCONFIGSDIR'}) {
+ $demosdir = $ENV{'IVYCONFIGSDIR'};
+} else {
+ $demosdir = ".";
+}
+
+
+if ($opt{testdir}) {
+ $testsdir = $opt{testdir};
+} elsif ($ENV{'IVYTESTSDIR'}) {
+ $testsdir = $ENV{'IVYTESTSDIR'};
+} else {
+ $testsdir = ".";
+}
+
+
+# test directories
+#----------------------------
+
+for ($demosdir, $testsdir) {
+ if (not -d $_) {
+ die "No such directory $_\n";
+ } elsif (not -r $_) {
+ die "Directory $_ is unreadable\n";
+ }
+}
+
+# parse configuration file
+#--------------------------
+
+if (open S, $conffile) {
+ while (<S>) {
+ if (/^ivylaunch_command\s*:\s*([\w\/-]+)/) {
+ $ivylaunch_command = $1;
+ } elsif (/^default_domain\s*:\s*(.*)/) {
+ $default_domain = $1;
+ } elsif (/^4ports\s*:\s*(.*)/) {
+ my $ports = $1;
+ @ivyports = split(/\s*,\s*/, $ports);
+ } elsif (/^default_port\s*:\s*([\w\/-]+)/) {
+ $default_port = $1;
+ }
+ }
+ close S;
+}
+
+$ivylaunch_command .= " -override" if $opt{override};
+
+# build the presentation frame
+#------------------------------
+
+my $mw = MainWindow->new (-bg => 'black');
+if ($opt{nocursor}) {
+ open(CURSOR, ">/tmp/cursor-ivybanner");
+ print CURSOR "#define cursor_width 1\n";
+ print CURSOR "#define cursor_height 1\n";
+ print CURSOR "#define cursor_x_hot 0\n";
+ print CURSOR "#define cursor_y_hot 0 \n";
+ print CURSOR "static char cursor_bits[] = { 0x20};\n";
+ close(CURSOR);
+ $mw->configure(-cursor => ['@'.'/tmp/cursor-ivybanner',
+ '/tmp/cursor-ivybanner',
+ 'black', 'black']);
+ unlink("/tmp/cursor-ivybanner");
+} else {
+ $mw->configure(-cursor => 'circle');
+}
+$mw->geometry ($width."x".$height."--0+0");
+$mw->title ('ivybanner');
+$mw->client ('ivybanner');
+
+$mw->resizable(0,0);
+
+
+my $logo_small =$mw->Photo ('logo-small',
+ -file => Tk::findINC('logo.gif'));
+my $logo_bg = $mw->Photo ('logo_bg',
+ -file => Tk::findINC('background.gif'));
+
+my ($fm1, $fm2, $fm3);
+$fm1 = $mw->Frame->pack(-expand => 1, -fill => 'both');
+
+my @buttonattr = (-width => 8, -height => 3,
+ -borderwidth => 1,
+ @fontspec24,
+ -relief => 'flat',
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ -activebackground => $bg,
+ -activeforeground => $fg,
+ -background => $bg,
+ -foreground => $fg);
+
+$fm1->Label(-image => $logo_bg)->place(-x => 0, -y => 0);
+$fm1->Button(-text => 'demos',
+ -command => [\&demosframe, $demosdir],
+ @buttonattr)->place(-x => 800, -y => 100);
+$fm1->Button(-text => 'tests',
+ -command => [\&demosframe, $testsdir],
+ @buttonattr)->place(-x => 800, -y => 330);
+$fm1->Button(-text => 'quit',
+ @buttonattr,
+ -command => [sub {exit(0)}])->place(-x => 800, -y => 560);
+
+print "--- Environment variables\n";
+print "\$IVYCONFIGSDIR=",$ENV{'IVYCONFIGSDIR'},"\n";
+print "\$IVYTESTSDIR=",$ENV{'IVYTESTSDIR'},"\n";
+print "--- Parameters\n";
+print "configuration file : $conffile\n";
+print "declared ports : ",join(',', @ivyports),"\n";
+print "default domain : $default_domain\n";
+print "default port : $default_port \n";
+print "demos directory : $demosdir \n";
+print "tests directory : $testsdir \n";
+print "ivylaunch command : $ivylaunch_command \n";
+print "======================================================\n";
+
+
+MainLoop;
+
+
+sub execute {
+ my ($path, $demo, $port, $domain) = @_;
+ unless (defined $demo) {
+ $mw->bell;
+ return;
+ }
+ $mw->withdraw;
+
+ my $command = $ivylaunch_command;
+ $command .= " -b $domain:$port" if $port;
+ my ($sec,$min,$hour,$mday,$mon,$year) = localtime();
+ my $now_string = sprintf ("%02d%02d%02d_%02d:%02d:%02d",
+ $year-100, 1+$mon, $mday,$hour,$min,$sec);
+ my $tmp_file_prefix = $logdir."/".$logfile ;
+
+ print "===========================================================\n";
+ print "Ivy demos launched at ".localtime()."\n";
+ print "Selected config is $demo on bus $domain:$port\n";
+ print "Traces are in $tmp_file_prefix$now_string\n";
+ print "Run $command $path/$demo\n";
+ system ("$command $path/$demo 2>&1 | tee $tmp_file_prefix$now_string");
+ $mw->deiconify;
+ $mw->raise;
+
+} # end execute
+
+
+sub demosframe {
+ my ($path) = @_;
+ my @packinfo = $fm1->packInfo;
+ $fm1->packForget();
+ $fm2 = $mw->Frame(-background => $darkbg)->pack(-expand => 1, -fill => 'both');
+
+ $fm2->Frame(-background => $darkbg, -relief => 'groove', -borderwidth => 5,
+ -width => $width+20, -height => 160)
+ ->place(-x => -10, -y => -10);
+
+ my $lb_logo = $fm2->Label(-image => $logo_small,
+ -borderwidth => 0)->place(-x => 390, -y => 26);
+ # Note that we use a decorative frame for each widget because frame size can be
+ # set in pixel unit whereas buttons family manages size in characters number
+ # (so, the size depends on used font)
+
+ # ivy network parameters frames
+ #--------------------------------------------------
+ my $y = 25;
+ my $x = 70;
+ my $h = 50;
+ my $w = 130;
+ my $dx = 15;
+ my $dy = 10;
+ my @placeattr = (-x => 2, -y => 2);
+ my @lab_placeattr = (-x => $w - 8, -y => 10 );
+ my @frameattr = (-relief => 'flat',
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ -highlightcolor => $hlbg,
+ -height => $h,
+ -width => $w,
+ -background => $bg);
+ my @labelattr = (-width => 9, -height => 2,
+ -borderwidth => 1,
+ -relief => 'flat',
+ -highlightthickness => 0,
+ -background => $bg,
+ -foreground => $fg);
+ my @cbuttonattr = (@labelattr,
+ @fontspec17,
+ -activeforeground => $fg,
+ -activebackground => $bg,
+ -selectcolor => $selcolor);
+ my @entryattr = (-width => 15,
+ -state => 'disable',
+ @fontspec17,
+ -background => $bg);
+ my $fm_localhost = $fm2->Frame(@frameattr)->place(-x => $x, -y => $y);
+ my $fm_default = $fm2->Frame(@frameattr)->place(-x => $x+$w+$dx, -y => $y);
+ my ($dom_default, $dom_local, $dom_own);
+ my $fm_ownnet = $fm2->Frame(@frameattr,
+ -width => 2*$w+$dx)->place(-x => $x, -y => $y+$h+$dy);
+ my $cb_local = $fm_localhost->Checkbutton(@cbuttonattr,
+ -variable => \$dom_local,
+ -text => 'localhost')->place(@placeattr);
+ my $cb_default = $fm_default->Checkbutton(@cbuttonattr,
+ -variable => \$dom_default,
+ -text => "default\ndomain")->place(@placeattr);
+ if (defined($default_domain)) {
+ $cb_default->select;
+ } else {
+ $cb_default->configure(-state => 'disabled');
+ }
+ my $cb_ownnet =
+ $fm_ownnet->Checkbutton(-text => "other\ndomain",
+ -variable => \$dom_own,
+ @cbuttonattr)->place(@placeattr);
+
+ my $en_ownnet =
+ $fm_ownnet->Entry(@entryattr)->place(@lab_placeattr);
+
+ $cb_ownnet->configure(-command => sub {
+ my $v = $cb_ownnet->cget(-variable);
+ if ($$v == 1) {
+ $en_ownnet->configure(-state => 'normal', -background => $fg);
+ } else {
+ $en_ownnet->configure(-state => 'disable', -background => $bg);
+ }
+ });
+
+ # ivy port parameters frames
+ #--------------------------------------------------
+ $x = 540;
+ my @ports = (@ivyports);
+ my $port = $default_port;
+ my @fm_port;
+ $fm_port[0] = $fm2->Frame(@frameattr)->place(-x => $x, -y => $y);
+ $fm_port[1] = $fm2->Frame(@frameattr)->place(-x => $x+$w+$dx, -y => $y);
+ $fm_port[2] = $fm2->Frame(@frameattr)->place(-x => $x+2*$w+2*$dx, -y => $y);
+ $fm_port[3] = $fm2->Frame(@frameattr)->place(-x => $x, -y => $y+$dy+$h);
+ my $fm_ownport = $fm2->Frame(@frameattr,
+ width => 2*$w+$dx)->place(-x => $x+$w+$dx,
+ -y => $y+$h+$dy);
+ my $en_ownport =
+ $fm_ownport->Entry(@entryattr)->place(@lab_placeattr);
+ for (my $i=0; $i < @fm_port; $i++) {
+ $fm_port[$i]->Radiobutton(@cbuttonattr,
+ -variable => \$port,
+ -value => $ports[$i],
+ -command => sub {
+ $en_ownport->configure(-state => 'disable',
+ -background => $bg)},
+ -text => $ports[$i])->place(@placeattr);
+ }
+
+ $fm_ownport->Radiobutton(@cbuttonattr,
+ -value => 'own',
+ -variable => \$port,
+ -command => sub {
+ $en_ownport->configure(-state => 'normal',
+ -background => $fg)},
+ -text => "other\nport")->place(@placeattr);
+
+ # demos frame
+ #--------------------------------------------------
+ my @bbox = (40, 160, $width-40, 640);
+ my $fmh = 90;
+ my $fmw = 180;
+ my $butw = 14;
+ my $max_columns = int(($bbox[2]-$bbox[0])/$fmw);
+ my $max_rows = int(($bbox[3]-$bbox[1])/$fmh);
+ my $maxnb = $max_columns*$max_rows;
+ @placeattr = (-x => 10, -y => 5);
+ @frameattr = (-relief => 'flat',
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ -height => $fmh,
+ -width => $fmw,
+ -background => $bg);
+ my @rbuttonattr = (-width => $butw, -height => 4,
+ -borderwidth => 1,
+ @fontspec17,
+ -relief => 'flat',
+ -highlightthickness => 0,
+ -background => $bg,
+ -foreground => $fg,
+ -activeforeground => $fg,
+ -activebackground => $bg,
+ -selectcolor => $selcolor,
+ );
+ my @buttonattr = (-width => $butw, -height => 4,
+ -borderwidth => 1,
+ @fontspec17,
+ -relief => 'flat',
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ -activebackground => $bg,
+ -activeforeground => $fg,
+ -background => $bg,
+ -foreground => $fg);
+
+ my $c = 1;
+ my $r = 1;
+ opendir PREFIX, $path;
+ my @file_liste = grep /:/, readdir PREFIX;
+ closedir PREFIX;
+ my @cleanfilelist = ();
+ foreach my $file (@file_liste) {
+ next unless (-f $path."/".$file);
+ next if ($file =~ /\~$/);
+ next if ($file =~ /^\./);
+ next if ($file =~ /\%$/);
+ push(@cleanfilelist, $file);
+ }
+ my $demosnb = @cleanfilelist;
+ if ($demosnb > $maxnb) {
+ splice(@cleanfilelist, $maxnb-1);
+ }
+ my $maxc = $max_columns;
+ for my $i (1, 4, 9, 16, 25) {
+ if ($demosnb <= $i) {
+ $maxc = sqrt($i);
+ last;
+ }
+ }
+ $dx = ($bbox[2] - $bbox[0] - $maxc*$fmw)/($maxc+1);
+ $dy = ($bbox[3] - $bbox[1] - $maxc*$fmh)/($maxc+1);
+ $x = $bbox[0] + $dx;
+ $y = $bbox[1] + $dy;
+ #print "maxc=$maxc x=$x y=$y dx=$dx dy=$dy\n";
+ my ($xi, $yi);
+ for my $file (@cleanfilelist) {
+ my @fields = split(/:/, $file);
+ my ($category, $extinfo);
+ if (@fields == 1) {
+ $category = $fields[0];
+ } elsif (@fields > 1) {
+ ($category, $extinfo) = ($fields[-2], $fields[-1]);
+ }
+ my $len = length($category);
+ if ($len >= $butw) {
+ $category = substr($category, 0, $butw)."\n".substr($category, $butw);
+ }
+ $len = length($extinfo);
+ if ($len > $butw) {
+ $extinfo = substr($extinfo, 0, $butw)."\n".substr($extinfo, $butw);
+ }
+ ($xi, $yi) = ($x + ($c-1)*($dx+$fmw), $y + ($r-1)*($dy+$fmh));
+ my $b = $fm2->Button(@buttonattr,
+ -text => "$category\n$extinfo")->place(-x => $xi, -y => $yi);
+ $b->configure(-command => sub {
+ if (&ison($b)) {
+ &off($b);
+ } else {
+ &on($b, $file);
+ }
+ });
+
+ if ($c >= $maxc) {
+ $c=1;
+ $r++;
+ } else {
+ $c++;
+ }
+ }
+ if ($demosnb > $maxnb) {
+ ($xi, $yi) = ($x + ($c-1)*($dx+$fmw), $y + ($r-1)*($dy+$fmh));
+ my $fm_demo = $fm2->Frame(@frameattr)->place(-x => $xi, -y => $yi);
+ $fm_demo->Radiobutton(@rbuttonattr,
+ -state => "disabled",
+ -value => 0,
+ -text => "and many\nmore...")->place(@placeattr);
+
+ }
+
+ # control buttons bottom frame
+ #--------------------------------------------------
+ $y = 680;
+ my @buttonattr = (-width => 6, -height => 2,
+ -borderwidth => 1,
+ @fontspec24,
+ -relief => 'flat',
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ -activebackground => $bg,
+ -activeforeground => $fg,
+ -background => $bg,
+ -foreground => $fg);
+ $fm2->Frame(-background => $darkbg, -relief => 'groove',
+ -borderwidth => 5,
+ -width => $width+20,
+ -height => $height)->place(-x => -10, -y => $y - 30);
+ $fm2->Button(@buttonattr,
+ -text => "back",
+ -command => sub {
+ $selected_demo = undef;
+ $selected_button = undef;
+ $fm2->destroy;
+ $fm1->pack(@packinfo);
+ })->place(-x => 70, -y => $y);
+# $fm2->Button(@buttonattr,
+# -command => sub {},
+# -text => "kill")->place(-x => 290, -y => $y);
+ $fm2->Button(@buttonattr,
+ -command => \&viewLog,
+ -text => "view\nlog")->place(-x => 510, -y => $y);
+ $view_button =
+ $fm2->Button(@buttonattr,
+ -state => 'disabled',
+ -command => sub {&viewConfig($path, $selected_demo)},
+ -text => "view\nconfig")->place(-x => 670, -y => $y);
+ $launch_button =
+ $fm2->Button(@buttonattr,
+ -state => 'disabled',
+ -command => sub {
+ my $p = $port;
+ my $d;
+ if ($port eq 'own') {
+ $p = $en_ownport->get();
+ }
+ $d .= "127, " if $dom_local;
+ $d .= $default_domain."," if $dom_default;
+ $d .= $en_ownnet->get() if $dom_own;
+ $d =~ s/,\s*$// if $d;
+ $d =~ s/\s+// if $d;
+ #print "port=$p domain=$d\n";
+ &execute($path, $selected_demo, $p, $d);
+ },
+ -text => "launch")->place(-x => 830, -y => $y);
+
+} # end demosframe
+
+
+sub viewConfig {
+ my ($dir, $file) = @_;
+ unless ($file) {
+ $mw->bell;
+ return;
+ }
+ my @packinfo = $fm2->packInfo;
+ $fm2->packForget();
+ $fm3 = $mw->Frame(-background => $darkbg)->pack(-expand => 1, -fill => 'both');
+ my $t = $fm3->Scrolled('Text',
+ -background => $bg,
+ -relief => 'sunken',
+ -foreground => $fg,
+ -borderwidth => 2,
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ @fontspec17,
+ -height => 28,
+ -width => 102,
+ -scrollbars => 'oe');
+ $t->Subwidget('yscrollbar')->configure(-width => 40,
+ -borderwidth => 3,
+ -relief => 'flat',
+ -highlightthickness => 3,
+ -troughcolor => $darkbg,
+ -highlightbackground => $hlbg,
+ -activebackground => $hlbg,
+ -background => $bg);
+
+ $t->place(-x => 50, -y => 120);
+ $t->tagConfigure('comment', -foreground => 'gray70');
+ open(C_FILE, "cpp -traditional $dir/$file|");
+ while (<C_FILE>) {
+ next if /^\s*$/;
+ if (/^\s*\#/) {
+ $t->insert('end',$_."\n", 'comment');
+ } else {
+ $t->insert('end',$_."\n");
+ }
+ }
+ close C_FILE;
+ $t->configure(-state => 'disabled');
+ my @labelattr = (-width => 40,
+ -height => 2,
+ -borderwidth => 1,
+ @fontspec24,
+ -relief => 'flat',
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ -background => $bg,
+ -foreground => $fg);
+ my @buttonattr = (@labelattr,
+ -width => 8,
+ -activebackground => $bg,
+ -activeforeground => $fg);
+ my $text1 = "content of $file";
+ my $text2 = "in $dir";
+ my $len1 = length($text1);
+ my $len2 = length($text2);
+
+ $fm3->Label(-text => "$text1\n$text2",
+ @labelattr,
+ -width => ($len1 > $len2) ? $len1 : $len2,
+ )->place(-x => 50, -y => 30);
+ $fm3->Button(@buttonattr,
+ -text => "back",
+ -command => sub {
+ $fm3->destroy;
+ $fm2->pack(@packinfo);
+ })->place(-x => 70, -y => 680);
+
+} # end viewConfig
+
+
+sub viewLog {
+ my $file;
+ my $dir;
+ my @packinfo = $fm2->packInfo;
+ $fm2->packForget();
+ $fm3 = $mw->Frame(-background => $darkbg)->pack(-expand => 1, -fill => 'both');
+ my $t = $fm3->Scrolled('Text',
+ -background => $bg,
+ -relief => 'sunken',
+ -foreground => $fg,
+ @fontspec17,
+ -height => 28,
+ -width => 102,
+ -borderwidth => 2,
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ -state => 'disabled',
+ -scrollbars => 'oe');
+ $t->Subwidget('yscrollbar')->configure(-width => 40,
+ -borderwidth => 3,
+ -relief => 'flat',
+ -highlightthickness => 3,
+ -troughcolor => $darkbg,
+ -highlightbackground => $hlbg,
+ -activebackground => $hlbg,
+ -background => $bg);
+
+ $t->tagConfigure('bold', -foreground => $hlbg);
+ $t->place(-x => 50, -y => 120);
+ opendir PREFIX, $logdir;
+ my @files = readdir PREFIX;
+ closedir PREFIX;
+ my %logfiles;
+ my %dates;
+ my @logfiles;
+ for (@files) {
+ next unless /^$logfile(\d\d)(\d\d)(\d\d)_(\d\d):(\d\d):(\d\d)/;
+ push(@logfiles, $_);
+ $logfiles{$_} = $1.$2.$3.$4.$5.$6;
+ $dates{$_} = "$3/$2/$1 $4:$5:$6";
+ }
+ my @logfiles = sort {$logfiles{$a} <=> $logfiles{$b}} (@logfiles);
+ my $cnt = $#logfiles;
+
+
+ my @labelattr = (-width => 40,
+ -height => 2,
+ -borderwidth => 1,
+ @fontspec24,
+ -relief => 'flat',
+ -highlightthickness => 3,
+ -highlightbackground => $hlbg,
+ -background => $bg,
+ -foreground => $fg);
+ my @buttonattr = (@labelattr,
+ -width => 8,
+ -activebackground => $bg,
+ -activeforeground => $fg);
+
+ my $l = $fm3->Label(@labelattr,
+ )->place(-x => 50, -y => 30);
+
+ &readlog($logfiles[$cnt], $dates{$logfiles[$cnt]}, $t, $l) if @logfiles > 0;
+
+
+ $fm3->Button(@buttonattr,
+ -text => "back",
+ -command => sub {
+ $fm3->destroy;
+ $fm2->pack(@packinfo);
+ })->place(-x => 70, -y => 680);
+ my $prev_button =
+ $fm3->Button(@buttonattr,
+ -text => "prev",
+ )->place(-x => 600, -y => 680);
+ my $next_button =
+ $fm3->Button(@buttonattr,
+ -text => "next",
+ -state => 'disabled',
+ )->place(-x => 800, -y => 680);
+ if (@logfiles <= 1) {
+ $prev_button->configure(-state => 'disabled');
+ $next_button->configure(-state => 'disabled');
+ }
+ $prev_button->configure(-command => sub {
+ $cnt--;
+ &readlog($logfiles[$cnt], $dates{$logfiles[$cnt]}, $t, $l) if $cnt >= 0;
+ $prev_button->configure(-state => 'disabled') if $cnt <= 0;
+ $next_button->configure(-state => 'normal');
+ });
+
+ $next_button->configure(-command => sub {
+ $cnt++;
+ &readlog($logfiles[$cnt], $dates{$logfiles[$cnt]}, $t, $l)
+ if $cnt <= $#logfiles;
+ $next_button->configure(-state => 'disabled') if $cnt >= $#logfiles;
+ $prev_button->configure(-state => 'normal');
+ });
+
+
+} # end viewLog
+
+sub readlog {
+ my ($file, $date, $t, $l) = @_;
+ $file = $logdir."/".$file;
+ $l->configure(-text => $date);
+ open(FILE, $file) or warn "cannot read file '$file'\n";
+ $t->configure(-state => 'normal');
+ $t->delete('0.0', 'end');
+ while (<FILE>) {
+ my @msg;
+ while (/\c[\[1m(.*?)\c[\[m([^\c[]*)/g) {
+ $t->insert('end', $1, 'bold');
+ $t->insert('end', $2);
+ }
+ }
+ $t->see('end');
+ $t->configure(-state => 'disabled');
+ close FILE;
+
+} # end readlog
+
+
+sub ison {
+ my $b = shift;
+ return 1 if $selected_button eq $b;
+
+} # end ison
+
+
+sub on {
+ my ($b, $file) = @_;
+ &off($selected_button) if defined $selected_button;
+ $selected_button = $b;
+ $selected_demo = $file;
+ $b->configure(-foreground => $selcolor, -highlightbackground => $selcolor,
+ -activeforeground => $selcolor);
+ $view_button->configure(-state => 'normal');
+ $launch_button->configure(-state => 'normal');
+
+} # end on
+
+
+sub off {
+ my $b = shift;
+ $b->configure(-foreground => $fg, -highlightbackground => $hlbg,
+ -activeforeground => $fg);
+ $view_button->configure(-state => 'disabled');
+ $launch_button->configure(-state => 'disabled');
+ $selected_demo = undef;
+ $selected_button = undef;
+
+} # end off
+
+
+sub usage {
+ print "Usage : ivybanner [-help] [-nocursor] [-override] [-conf configfile]\n";
+ print " [-dir fugueconfdir] [-testdir testsdir]\n";
+ print "\n";
+ print "Options :\n";
+ print " -override option passed to ivylaunch. if true, global agents\n";
+ print " which are already connected will be overriden\n";
+ print " -nocursor hide mouse cursor\n";
+ print " -conf <file> configuration file; default=/etc/ivybanner.conf\n";
+ print " -dir <dir> fugue configs directory\n";
+ print " -testdir <dir> tests directory\n";
+ print "\n";
+ exit 0;
+}
+
+
+__END__
+
+=head1 NAME
+
+ivybanner - an interface for ivy launcher
+
+=head1 SYNOPSIS
+
+ivybanner [-help] [-nocursor] [-override] [-conf configfile] [-dir fugueconfdir] [-testdir testsdir]
+
+=head1 DESCRIPTION
+
+ivybanner provides an interface for selecting ivy parameters (domain and port number) and selecting the configuration file with the applications to be launched on ivy.
+
+The aim of ivybanner is to automate the launching of Ivy demonstrations.
+
+The main page of ivybanner allows to activate the "Demos" or "Tests" launching page or quit.
+
+=head1 OPTIONS
+
+=over
+
+=item B<-nocursor>
+
+Hide mouse cursor (for touchscreen usage).
+
+=item B<-conf> file
+
+Specify configuration file. Default is /etc/ivybanner.conf
+
+=item B<-dir> directory
+
+Specify fugue configurations directory. Default is current directory unless the $IVYCONFIGSDIR variable is set.
+
+=item B<-testdir> file
+
+Specify tests directory. Default is current directory unless the $IVYTESTSDIR variable is set.
+
+=item B<-override>
+
+Infer ivylaunch behavior when a B<global> agent is detected on the bus. See ivylaunch(1) man page.
+
+
+=back
+
+=head1 FILENAME FORMAT
+
+To be detected by ivybanner, the files placed in the demos or tests directory must respect the following name format :
+
+ [string0:]string1:string2
+
+The label of ivybanner demos buttons will be contained string1 and string2.
+
+=head1 FILE FORMAT
+
+The format of fugue configuration files is described in ivylaunch(1) man page.
+
+=head1 LOG FILES
+
+/tmp/ivybanner-yymmdd_hh:mm:ss
+
+=head1 SEE ALSO
+
+ivylaunch(1), ivycontrolpanel(1)
+
+=head1 AUTHOR
+
+Daniel Etienne <etienne@cena.fr>
+
+=head1 HISTORY
+
+ivybanner is derived from the toccata-banner application written by Johnny Accot and Michelle Jacomi.
+
+
diff --git a/ivybanner.conf b/ivybanner.conf
new file mode 100644
index 0000000..9f33c70
--- /dev/null
+++ b/ivybanner.conf
@@ -0,0 +1,11 @@
+# ivylaunch command and options; default is /usr/bin/ivylaunch
+#ivylaunch_command :
+
+# 4 selectable ports
+4ports : 2010, 3009, 3110, 3945
+
+# pre-selected port
+default_port : 3110
+
+# default domain; may be your broadcast address
+#default_domain : 10.192.36.255
diff --git a/logo.gif b/logo.gif
new file mode 100644
index 0000000..53c6c51
--- /dev/null
+++ b/logo.gif
Binary files differ