#!/usr/bin/perl # # ivybanner, a banner to launch demos using ivy # # Author: Daniel Etienne # # ivybanner is derived from the toccata-banner application # written by Johnny Accot and Michelle Jacomi and maintained # by Christophe Mertz # # $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; my $smallsized = 0; my $coef = 1; # 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; my %apps; my $currentlogfile; # parse options #------------------------ Getopt::Long::Configure('pass_through'); &usage unless Getopt::Long::GetOptions(\%opt, 'conf=s', 'testdir=s', '-dir=s', 'nocursor', 'help', 'override', 'smallsize' ); &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 = "."; } if ($opt{smallsize}) { $width = 640; $height = 480; $smallsized = 1; $coef = 0.620; @fontspec24 = (-font => '-b&h-lucida-bold-i-normal-sans-15-150-100-100-p-216-iso8859-1'); @fontspec17 = (-font => '-adobe-helvetica-medium-r-normal--11-80-100-100-p-60-iso10646-1'); } # 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 () { 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); $mw->title ('ivybanner'); $mw->client ('ivybanner'); $mw->resizable(0,0); #$mw->scale($maingroup, $winW/1280, $winH/1024); if $smallsized; 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, $tlog, $tlog2); $fm1 = $mw->Frame->pack(-expand => 1, -fill => 'both'); my @buttonattr = (-width => 8*$coef, -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); if ($opt{smallsize}){ $fm1->Label(-image => $logo_bg)->place(-x => -120, -y => -144); }else{ $fm1->Label(-image => $logo_bg)->place(-x => 0, -y => 0); } $fm1->Button(-text => 'demos', -command => [\&demosframe, $demosdir], @buttonattr)->place(-x => 800*$coef, -y => 100*$coef); $fm1->Button(-text => 'tests', -command => [\&demosframe, $testsdir], @buttonattr)->place(-x => 800*$coef, -y => 330*$coef); $fm1->Button(-text => 'quit', @buttonattr, -command => [sub {exit(0)}])->place(-x => 800*$coef, -y => 560*$coef); 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'); my $lb_logo; $fm2->Frame(-background => $darkbg, -relief => 'groove', -borderwidth => 5, -width => $width+20*$coef, -height => 160*$coef) ->place(-x => -10*$coef, -y => -10*$coef); if ($opt{smallsize}){ $lb_logo = $fm2->Label(-image => $logo_small, -borderwidth => 0)->place(-x => 225, -y => -16); }else{ $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*$coef; my $x = 70*$coef; my $h = 50*$coef; my $w = 130*$coef; my $dx = 15*$coef; my $dy = 10*$coef; my @placeattr = (-x => 2*$coef, -y => 2*$coef); my @lab_placeattr = (-x => $w - 8*$coef, -y => 10*$coef ); my @frameattr = (-relief => 'flat', -highlightthickness => 3*$coef*$coef, -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*$coef, -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*$coef; 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*$coef, 160*$coef, $width-40*$coef, 640*$coef); my $fmh = 90*$coef; my $fmw = 180*$coef; my $butw = 14*$coef; 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*$coef, -y => 5*$coef); @frameattr = (-relief => 'flat', -highlightthickness => 3*$coef*$coef, -highlightbackground => $hlbg, -height => $fmh, -width => $fmw, -background => $bg); my @rbuttonattr = (-width => $butw, -height => 4*$coef, -borderwidth => 1, @fontspec17, -relief => 'flat', -highlightthickness => 0, -background => $bg, -foreground => $fg, -activeforeground => $fg, -activebackground => $bg, -selectcolor => $selcolor, ); my @buttonattr = (-width => $butw, -height => 4*$coef, -borderwidth => 1, @fontspec17, -relief => 'flat', -highlightthickness => 3*$coef*$coef, -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 = (); @file_liste = sort { (stat("$path/$a"))[10] <=> (stat("$path/$b"))[10] } @file_liste; foreach my $file (@file_liste) { print "file=$file mtime=", (stat("$path/$file"))[10] ,"\n"; 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*$coef; my @buttonattr = (-width => 6, -height => 2, -borderwidth => 1, @fontspec24, -relief => 'flat', -highlightthickness => 3*$coef*$coef, -highlightbackground => $hlbg, -activebackground => $bg, -activeforeground => $fg, -background => $bg, -foreground => $fg); $fm2->Frame(-background => $darkbg, -relief => 'groove', -borderwidth => 5*$coef, -width => $width+20*$coef, -height => $height)->place(-x => -10*$coef, -y => $y - 30*$coef); $fm2->Button(@buttonattr, -text => "back", -command => sub { $selected_demo = undef; $selected_button = undef; $fm2->destroy; $fm1->pack(@packinfo); })->place(-x => 70*$coef, -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*$coef, -y => $y); $view_button = $fm2->Button(@buttonattr, -state => 'disabled', -command => sub {&viewConfig($path, $selected_demo)}, -text => "view\nconfig")->place(-x => 670*$coef, -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*$coef, -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*$coef, -highlightbackground => $hlbg, @fontspec17, -height => 28, -width => 102, -scrollbars => 'oe'); $t->Subwidget('yscrollbar')->configure(-width => 40*$coef, -borderwidth => 3*$coef, -relief => 'flat', -highlightthickness => 3*$coef, -troughcolor => $darkbg, -highlightbackground => $hlbg, -activebackground => $hlbg, -background => $bg); $t->place(-x => 50*$coef*$coef*$coef, -y => 120*$coef); $t->tagConfigure('comment', -foreground => 'gray70'); open(C_FILE, "cpp -traditional $dir/$file|"); while () { 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*$coef, -height => 2, -borderwidth => 1, @fontspec24, -relief => 'flat', -highlightthickness => 3*$coef, -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*$coef*$coef*$coef, -y => 30*$coef); $fm3->Button(@buttonattr, -text => "back", -command => sub { $fm3->destroy; $fm2->pack(@packinfo); })->place(-x => 70*$coef, -y => 680*$coef); } # end viewConfig sub viewLog { my $file; my $dir; my @packinfo = $fm2->packInfo; $fm2->packForget(); $fm3 = $mw->Frame(-background => $darkbg)->pack(-expand => 1, -fill => 'both'); 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*$coef, -height => 2, -borderwidth => 1, @fontspec24, -relief => 'flat', -highlightthickness => 3*$coef, -highlightbackground => $hlbg, -background => $bg, -foreground => $fg); my @buttonattr = (@labelattr, -width => 8, -activebackground => $bg, -activeforeground => $fg); my $l = $fm3->Label(@labelattr, )->place(-x => 50*$coef*$coef*$coef, -y => 30*$coef); $fm3->Button(@buttonattr, -text => "back", -command => sub { $fm3->destroy; $fm2->pack(@packinfo); })->place(-x => 70*$coef, -y => 680*$coef); my $select_button = $fm3->Button(@buttonattr, -text => "select...", -command => \&selectappname, )->place(-x => 400*$coef, -y => 680*$coef); my $prev_button = $fm3->Button(@buttonattr, -text => "previous\nlog", )->place(-x => 600*$coef, -y => 680*$coef); my $next_button = $fm3->Button(@buttonattr, -text => "next\nlog", -state => 'disabled', )->place(-x => 800*$coef, -y => 680*$coef); if (@logfiles <= 1) { $prev_button->configure(-state => 'disabled'); $next_button->configure(-state => 'disabled'); } $prev_button->configure(-command => sub { $tlog2->destroy if Tk::Exists($tlog2); $cnt--; &readlog($logfiles[$cnt], $dates{$logfiles[$cnt]}, $l) if $cnt >= 0; $prev_button->configure(-state => 'disabled') if $cnt <= 0; $next_button->configure(-state => 'normal'); }); $next_button->configure(-command => sub { $tlog2->destroy if Tk::Exists($tlog2); $cnt++; &readlog($logfiles[$cnt], $dates{$logfiles[$cnt]}, $l) if $cnt <= $#logfiles; $next_button->configure(-state => 'disabled') if $cnt >= $#logfiles; $prev_button->configure(-state => 'normal'); }); &readlog($logfiles[$cnt], $dates{$logfiles[$cnt]}, $l) if @logfiles > 0; } # end viewLog sub selectappname { my $w = shift; my $tl = $mw->Toplevel(-background => $darkbg); $tl->title('messages selection'); $tl->resizable(0, 0); my $fm = $tl->Frame(-background => $darkbg, -highlightthickness => 3, -highlightbackground => $hlbg, )->pack(-side => 'top', -padx => 0, -pady => 0); my $fm1 = $fm->Frame(-background => $darkbg)->pack(-side => 'top', -padx => 10, -pady => 10); my $fm2 = $fm->Frame(-background => $darkbg)->pack(-side => 'bottom'); my @labelattr = (-relief => 'flat', -background => $darkbg, -foreground => $fg, -borderwidth => 0, -highlightthickness => 0, -height => 2, @fontspec24); my @buttonattr = (-relief => 'flat', -background => $bg, -foreground => $fg, -borderwidth => 1, -highlightbackground => $hlbg, -highlightthickness => 3*$coef, -height => 2, -activebackground => $bg, -activeforeground => $fg, @fontspec24); my @cbuttonattr = (@buttonattr, @fontspec17); my $i = 0; my $selapp = 'all'; for my $app (keys(%apps), 'all') { my $col = $i % 3; my $row = int($i/3); $fm1->Radiobutton(@cbuttonattr, -selectcolor => $hlbg, -text => $app, -variable => \$selapp, -value => $app, )->grid(-row => $row, -column => $col, -padx => 5, -pady => 5, -sticky => 'nsew'); $i++; } $fm2->Button(@buttonattr, -text => 'yes', -command => sub { if ($selapp eq 'all') { $tlog2->destroy if Tk::Exists($tlog2); } else { &readpartiallog($selapp); } $tl->destroy; }, )->pack(-side => 'left', -padx => 20, -pady => 20, -expand => 1, -fill => 'both'); $fm2->Button(@buttonattr, -text => 'cancel', -command => sub { $tl->destroy }, )->pack(-side => 'left', -padx => 20, -pady => 20, -expand => 1, -fill => 'both'); # placement at window center $tl->update; my ($x, $y) = ($mw->rootx, $mw->rooty); $x += int($width/2 - $tl->width/2); $y += int($height/2 - $tl->height/2); $tl->geometry('+'.$x.'+'.$y); $tl->grab; } # end selectappname sub readlog { # il est plus rapide de recréer un widget Text que de le vider de son # contenu et le remettre à jour !! my ($file, $date, $l) = @_; $file = $logdir."/".$file; $currentlogfile = $file; $tlog2->destroy if Tk::Exists($tlog2); $fm3->update; $tlog = $fm3->Scrolled('Text', -background => $bg, -relief => 'sunken', -foreground => $fg, @fontspec17, -height => 28, -width => 102, -borderwidth => 2, -highlightthickness => 3*$coef, -highlightbackground => $hlbg, -state => 'disabled', -scrollbars => 'oe'); $tlog->Subwidget('yscrollbar')->configure(-width => 40*$coef, -borderwidth => 3*$coef, -relief => 'flat', -highlightthickness => 3*$coef, -troughcolor => $darkbg, -highlightbackground => $hlbg, -activebackground => $hlbg, -background => $bg); $tlog->tagConfigure('bold', -foreground => $hlbg); $tlog->place(-x => 50*$coef*$coef*$coef, -y => 120*$coef); $l->configure(-text => "loading..."); $l->update; %apps = (); open(FILE, $file) or warn "cannot read file '$file'\n"; $tlog->configure(-state => 'normal'); $tlog->update; while () { my @msg; my $i = 0; while (/\c[\[1m(.*?)\c[\[m([^\c[]*)/g) { my $app = $1; my $msg = $2; #print "app=[$app] [$msg]\n"; if ($app =~ /^\S+\s*$/) { $apps{$app} = 1 if $i == 0; $tlog->insert('end', "$app", 'bold', "$msg"); } else { $tlog->insert('end', "$app $msg"); } $i++; } } $tlog->see('end'); $tlog->configure(-state => 'disabled'); $l->configure(-text => $date); close FILE; } # end readlog sub readpartiallog { my ($selapp) = @_; $tlog2->destroy if Tk::Exists($tlog2); $fm3->update; $tlog2 = $fm3->Scrolled('Text', -background => $bg, -relief => 'sunken', -foreground => $fg, @fontspec17, -height => 28, -width => 102, -borderwidth => 2, -highlightthickness => 3*$coef, -highlightbackground => $hlbg, -state => 'disabled', -scrollbars => 'oe'); $tlog2->Subwidget('yscrollbar')->configure(-width => 40*$coef, -borderwidth => 3*$coef, -relief => 'flat', -highlightthickness => 3*$coef, -troughcolor => $darkbg, -highlightbackground => $hlbg, -activebackground => $hlbg, -background => $bg); $tlog2->tagConfigure('bold', -foreground => $hlbg); $tlog2->place(-x => 50*$coef*$coef*$coef, -y => 120*$coef); $tlog2->configure(-state => 'normal'); open(FILE, $currentlogfile) or warn "cannot read file '$currentlogfile'\n"; while () { my @msg; my $i = 0; while (/\c[\[1m(.*?)\c[\[m([^\c[]*)/g) { my $app = $1; last if $i == 0 and $app ne $selapp; my $msg = $2; #print "app=[$app] [$msg]\n"; if ($app =~ /^\S+\s*$/) { $tlog2->insert('end', "$app", 'bold', "$msg"); } else { $tlog2->insert('end', "$app $msg"); } $i++; } } $tlog2->see('end'); $tlog2->configure(-state => 'disabled'); $tlog2->update; } # end readpartiallog 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 configuration file; default=/etc/ivybanner.conf\n"; print " -dir fugue configs directory\n"; print " -testdir tests directory\n"; print " -smallsize display IvyBanner in 640x480 instead of 1024x768\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] [-smallsize] =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 agent is detected on the bus. See ivylaunch(1) man page. =item B<-smallsize> display IvyBanner in 640x480 instead of 1024x768. =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 =head1 HISTORY ivybanner is derived from the toccata-banner application written by Johnny Accot and Michelle Jacomi.