X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;ds=inline;f=techtalk-pse.pl;h=b495911fe6c9deba4f1cd172195a0ff2f3e5b2a6;hb=HEAD;hp=5ea122c7b21667dd147293ffbead72cd8e1b63a5;hpb=332c08fd5e4d290e75087945048c802733dfc88d;p=techtalk-pse.git
diff --git a/techtalk-pse.pl b/techtalk-pse.pl
index 5ea122c..b495911 100755
--- a/techtalk-pse.pl
+++ b/techtalk-pse.pl
@@ -3,7 +3,7 @@
# @configure_input@
#
# Tech Talk PSE
-# Copyright (C) 2010 Red Hat Inc.
+# Copyright (C) 2010-2012 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,12 +23,16 @@ use warnings;
use strict;
use utf8;
+use POSIX qw(setsid);
use Pod::Usage;
use Getopt::Long;
use Cwd qw(getcwd abs_path);
use Glib qw(TRUE FALSE);
-use Gtk2 -init;
-use Gtk2::MozEmbed;
+use Glib::Object::Introspection;
+use Gtk3 -init;
+use Gtk3::WebKit;
+
+Glib::Object::Introspection->setup(basename => "Vte", version => "2.91", package => "Vte");
=encoding utf8
@@ -66,10 +70,26 @@ there is a discussion on L.
=head1 RUNNING THE TOOL FROM THE COMMAND LINE
-A Tech Talk PSE talk is not a single file, but a directory full of
-files. (If you want to start a new talk, see the L section
-below). To display or run the talk, change into the directory
-containing all those files and run the C command:
+Tech Talk PSE talks are just directories containing C<*.html>,
+C<*.sh> (shell script) and C<*.term> (terminal) files:
+
+ 0010-introduction.html
+ 0500-demonstration.sh
+ 0600-command-line.term
+ 9900-conclusion.html
+
+The filenames that Tech Talk PSE considers to be slides have to match
+the regular expression:
+
+ ^(\d+)(?:-.*)\.(html|sh|term)$
+
+(any other file or subdirectory is ignored). Shell scripts and
+terminal files I be executable.
+
+=head2 DISPLAYING AN EXISTING TALK
+
+To display or run a talk, change into the directory containing all
+those files and run the C command:
cd /path/to/talk/; techtalk-pse
@@ -115,15 +135,6 @@ The default is to start at the first slide in the talk.
=cut
-my $splash = 1;
-
-=item B<--no-splash>
-
-Don't display the initial "splash" screen which advertises Tech Talk
-PSE to your audience. Just go straight into the talk.
-
-=cut
-
my $verbose;
=item B<--verbose>
@@ -141,13 +152,9 @@ Display version number and exit.
=cut
-my $mozembed;
-
GetOptions ("help|?" => \$help,
"last" => \$last,
- "mozembed" => \$mozembed,
"n=s" => \$start,
- "splash!" => \$splash,
"start=s" => \$start,
"verbose" => \$verbose,
"version" => \$version,
@@ -165,26 +172,6 @@ if ($version) {
die "techtalk-pse: cannot use --start and --last options together\n"
if defined $last && defined $start;
-# --mozembed runs Gtk2::MozEmbed as a subprocess, because MozEmbed
-# is very crashy.
-if ($mozembed) {
- my $w = Gtk2::Window->new ();
- my $moz = Gtk2::MozEmbed->new ();
-
- $w->signal_connect (delete_event => sub {
- Gtk2->main_quit;
- return FALSE;
- });
-
- $w->set_default_size (600, 400);
- $w->add ($moz);
- $w->show_all ();
- $moz->load_url ($ARGV[0]);
- Gtk2->main;
-
- exit 0;
-}
-
die "techtalk-pse: too many arguments\n" if @ARGV >= 2;
# Get the true name of the program.
@@ -202,143 +189,739 @@ if (@ARGV > 0) {
}
}
+# Get the talk directory and set environment variable $talkdir
+# which is inherited by all the scripts.
+my $talkdir = getcwd;
+$ENV{talkdir} = $talkdir;
+
# Get the files.
my @files;
my %files;
-my %groups;
+my $current;
+my $pid;
+my $pipeline;
+my $fullscreen = 1;
+my $width;
+my $height;
+
+&reread_directory ();
+
+print STDERR "read ", 0+@files, " files\n" if $verbose;
+if (@files == 0) {
+ warn "techtalk-pse: no files found, continuing anyway ...\n"
+}
+
+my $w = Gtk3::Window->new ("toplevel");
+my $vbox = Gtk3::VBox->new ();
+my $webkit = Gtk3::WebKit::WebView->new ();
+my $vte = Vte::Terminal->new ();
+my $notebook = Gtk3::Notebook->new ();
+my $splash = make_splash_page ();
+my $emptylabel = Gtk3::Label->new ();
+
+my $webkitscroll = Gtk3::ScrolledWindow->new();
+$webkitscroll->add ($webkit);
+$webkitscroll->set_policy('automatic', 'automatic');
+
+my $webkitpage = $notebook->append_page ($webkitscroll);
+my $shpage = $notebook->append_page ($emptylabel);
+my $vtepage = $notebook->append_page ($vte);
+my $splashpage = $notebook->append_page ($splash);
+
+my ($bbox, $bquit, $breload, $bnext, $bback, $brestart) = make_button_bar ();
+
+$vbox->pack_start($bbox, 0, 0, 0);
+$vbox->pack_start($notebook, 1, 1, 0);
+
+$notebook->set_show_tabs(0);
+$notebook->set_show_border(0);
+
+# Default font size is almost certainly too small
+# for audience to see.
+# XXX we should make font size configurable via
+# @ARGV.
+# XXX any way we can scale WebKit programmatically
+# to set base size which CSS is relative to ?
+# NB careful setting it too big, because it will
+# force a min size on the terminal. Scaling 1.3
+# is biggest we can do while fitting 1024x768
+$vte->set_font_scale(1.3);
+
+# When an external command exits, automatically
+# go to the next slide
+$vte->signal_connect (
+ 'child-exited' => sub {
+ if ($pid) {
+ $pid = 0;
+ &switch_slide("NEXT");
+ }
+ });
+
+# Exit if the window is closed
+$w->signal_connect (
+ destroy => sub {
+ Gtk3::main_quit;
+ return FALSE;
+ });
+
+$w->signal_connect (
+ 'window-state-event' => sub {
+ if (!$fullscreen) {
+ $w->resize ($width, $height);
+ $w->move (500, 500);
+ }
+ return FALSE;
+ });
+
+
+# Handle left/right arrows, page up/down & home/end
+# as slide navigation commands. But not when there
+# is a shell running
+$w->signal_connect (
+ 'key-press-event' => sub {
+ my $src = shift;
+ my $ev = shift;
+
+ # If a shell is running, don't trap keys
+ if ($pid) {
+ return 0;
+ }
+
+ if ($ev->keyval == &Gtk3::Gdk::KEY_Right ||
+ $ev->keyval == &Gtk3::Gdk::KEY_Page_Down) {
+ &switch_slide("NEXT");
+ return 1;
+ } elsif ($ev->keyval == &Gtk3::Gdk::KEY_Left ||
+ $ev->keyval == &Gtk3::Gdk::KEY_Page_Up) {
+ &switch_slide("PREV");
+ return 1;
+ } elsif ($ev->keyval == &Gtk3::Gdk::KEY_Home) {
+ &switch_slide("FIRST");
+ return 1;
+ } elsif ($ev->keyval == &Gtk3::Gdk::KEY_End) {
+ &switch_slide("LAST");
+ return 1;
+ } elsif ($ev->keyval == &Gtk3::Gdk::KEY_q ||
+ $ev->keyval == &Gtk3::Gdk::KEY_Escape) {
+ Gtk3::main_quit;
+ return 1;
+ }
+ return 0;
+ });
+
+
+$w->add ($vbox);
+
+$w->show_all ();
+window_fullscreen ();
+
+&update_slide();
+
+Gtk3::main();
+
+exit 0;
+
sub reread_directory
{
@files = ();
- %groups = ();
+ my $i = 0;
foreach (glob ("*")) {
- if (/^(\d+)([A-Z])?(?:-.*)\.(html|sh)$/) {
+ if (/^(\d+)(?:-.*)\.(html|sh|term)$/) {
print STDERR "reading $_\n" if $verbose;
my $seq = $1;
- my $pos = $2 || "A";
- my $ext = $3;
+ my $ext = $2;
warn "techtalk-pse: $_: command file is not executable (+x)\n"
- if $ext eq "sh" && ! -x $_;
+ if ($ext eq "sh" || $ext eq "term") && ! -x $_;
- my $h = { name => $_, seq => $1, pos => $2, ext => $3 };
+ my $h = { name => $_, seq => $1, ext => $2, i => $i };
push @files, $h;
$files{$_} = $h;
-
- $groups{$seq} = [] unless exists $groups{$seq};
- push @{$groups{$seq}}, $h;
+ $i++;
} else {
print STDERR "ignoring $_\n" if $verbose;
}
}
+
+ if (@files > 0) {
+ $files[0]->{first} = 1;
+ $files[$#files]->{last} = 1;
+ }
+
+ # Work out what slide we're starting on.
+ if (@files && !$current) {
+ if ($start) {
+ foreach my $file (@files) {
+ if ($file->{name} =~ /^$start/) {
+ $current = $file;
+ last;
+ }
+ }
+ } elsif ($last) {
+ $current = $files[$#files];
+ }
+ if (!$current) {
+ $current = $files[0];
+ }
+ }
}
-reread_directory ();
-print STDERR "read ", 0+@files, " files\n" if $verbose;
-if (@files == 0) {
- warn "techtalk-pse: no files found, continuing anyway ...\n"
+
+sub window_fullscreen
+{
+ $w->set_decorated (0);
+ $w->fullscreen ();
+ $fullscreen = 1;
}
-# Work out what slide we're starting on.
-my $current;
-if (defined $current) {
- die "start slide not implemented yet XXX"
+sub window_in_corner
+{
+ $w->set_decorated (1);
+ $w->unfullscreen ();
+ $fullscreen = 0;
+
+ my $gwin = $w->get_window();
+ my $monitor = $w->get_display()->get_monitor_at_window($gwin);
+ my $geom = $monitor->get_geometry();
+
+ $width = $geom->{width} / 2;
+ $height = $geom->{height} / 4;
}
-elsif (@files) {
- $current = $files[0];
+
+sub run_process
+{
+ my @ret = $vte->spawn_sync('default', ".", ["./" . $current->{name}], [], 'default');
+ $pid = $ret[1];
}
-# else $current is undefined
-
-if ($splash) {
- my $w = Gtk2::AboutDialog->new;
- $w->set_authors ("Richard W.M. Jones");
- $w->set_comments (
- "Superior technical demonstration software\n".
- "\n".
- "Keys\n".
- "â â Go back one slide\n".
- "â â Go forward one slide\n"
- );
- $w->set_program_name ("Tech Talk Platinum Supreme Edition (PSE)");
- $w->set_version ("@VERSION@");
- $w->set_website ("http://people.redhat.com/~rjones");
- $w->set_license ("GNU General Public License v2 or above");
- $w->signal_connect (destroy => sub { Gtk2->main_quit });
- $w->show_all;
- Gtk2->main;
+
+sub kill_process
+{
+ print STDERR "sending TERM signal to process group $pid\n"
+ if $verbose;
+ kill "TERM", -$pid;
+
+ # Clears out any current displayed text
+ $vte->reset(1, 1);
+ $vte->set_default_colors();
+ $pid = 0;
}
-my $quit;
-while (!$quit) {
- if (defined $current) {
- my $go = show_slide ($current);
- if (defined $go && ($go eq "PREV" || $go eq "NEXT")) {
- print STDERR "go = $go\n" if $verbose;
- my $i = 0;
- FOUND: {
- foreach (@files) {
- last FOUND if $files[$i]->{name} eq $current->{name};
- $i++;
- }
- die "internal error: cannot find \$current in \@files"
- }
- print STDERR "found current entry at i = $i\n" if $verbose;
- $i-- if $go eq "PREV" && $i > 0;
- $i++ if $go eq "NEXT" && $i+1 < @files;
- $current = $files[$i];
- }
+sub switch_slide
+{
+ my $action = shift;
+
+ window_fullscreen ();
+
+ if ($pid) {
+ kill_process ();
+ }
+ if ($pipeline) {
+ $pipeline->set_state('ready');
+ $pipeline = undef;
+ }
+ print STDERR "action = $action\n" if $verbose;
+
+ my $i = defined $current ? $current->{i} : 0;
+
+ print STDERR "i = $i\n" if $verbose;
+ if ($action eq "PREV") {
+ if (defined $current) {
+ $i--;
+ } else {
+ $i = $#files;
+ }
+ } elsif ($action eq "NEXT") {
+ $i++;
+ } elsif ($action eq "FIRST") {
+ $i = 0;
+ } elsif ($action eq "LAST") {
+ $i = $#files;
+ } elsif ($action =~ /^I_(\d+)$/) {
+ $i = $1;
+ }
+
+ $i = 0 if $i < 0;
+ if ($i > $#files) {
+ $current = undef;
} else {
- print "No slides found. Press any key to reload directory ...\n";
- $_ = ;
+ $current = $files[$i];
}
- reread_directory ();
+ &update_slide ();
- if (defined $current && !exists $files{$current->{name}}) {
- # Current slide was deleted.
- undef $current;
- $current = $files[0] if @files;
- }
}
-sub show_slide {
- my $slide = shift;
-
- if ($slide->{ext} eq "html") {
- # MozEmbed is incredibly crashy, so we run ourself as a
- # subprocess, so when it segfaults we don't care.
- my $cwd = getcwd;
- my $url = "file://" . $cwd . "/" . $slide->{name};
- my @cmd = ($0, "--mozembed", $url);
- system (@cmd);
- die "failed to execute subcommand: $!\n" if $? == -1;
- if ($? & 127) {
- # Subcommand probably segfaulted, just continue to next slide.
- return "NEXT";
- } else {
- my $r = $? >> 8;
- if ($r == 0) {
- return "NEXT";
- } elsif ($r == 1) {
- return "PREV";
- } elsif ($r == 2) {
- return "QUIT";
- }
- }
+sub update_slide
+{
+ if ($current) {
+ # Display an HTML page.
+ if ($current->{ext} eq "html") {
+ $notebook->set_current_page ($webkitpage);
+ my $name = $current->{name};
+ my $url = "file://$talkdir/$name";
+
+ $webkit->load_uri ($url);
+ $webkit->grab_focus ();
+ }
+ # Run a shell command.
+ elsif ($current->{ext} eq "sh") {
+ window_in_corner ();
+
+ $notebook->set_current_page ($shpage);
+ run_process ();
+ }
+ # Open a VTE terminal.
+ elsif ($current->{ext} eq "term") {
+ $notebook->set_current_page ($vtepage);
+ $vte->grab_focus ();
+ run_process ();
+ }
+ } else {
+ $notebook->set_current_page ($splashpage);
+ }
+
+ if ($pid) {
+ $brestart->show ();
+ } else {
+ $brestart->hide ();
}
- elsif ($slide->{ext} eq "sh") {
- system ("PATH=.:\$PATH " . $slide->{name});
- return "NEXT";
+
+ if (defined $current) {
+ $bquit->hide ();
+ $breload->hide ();
+ $bnext->set_sensitive (1);
+ $bback->set_sensitive (!exists $current->{first});
+ } else {
+ $bquit->show ();
+ if (@files) {
+ $breload->hide ();
+ } else {
+ $breload->show ();
+ }
+ $bnext->set_sensitive (0);
+ $bback->set_sensitive (int(@files));
+ }
+}
+
+
+sub make_splash_page {
+ my $box = Gtk3::VBox->new();
+
+ my $title = Gtk3::Label->new ("Tech Talk Platinum Supreme Edition (PSE)");
+ $title->set_use_markup (1);
+
+ $box->pack_start ($title, 0, 1, 0);
+
+ my $vers = Gtk3::Label->new ("@VERSION@");
+ $vers->set_use_markup (1);
+ $box->pack_start ($vers, 0, 1, 0);
+
+ my $tagline = Gtk3::Label->new ("Superior technical demonstration software");
+ $tagline->set_use_markup (1);
+
+ $box->pack_start ($tagline, 0, 1, 0);
+ $box->pack_start (Gtk3::Label->new (""), 0, 1, 0);
+ $box->pack_start (Gtk3::Label->new ("Author: Richard W.M. Jones"), 0, 1, 0);
+
+ my $url = Gtk3::Label->new ("http://people.redhat.com/~rjones/");
+ $url->set_use_markup (1);
+ $box->pack_start ($url, 0, 1, 0);
+ $box->pack_start (Gtk3::Label->new ("GNU General Public License v2 or above"), 0, 1, 0);
+
+ return $box;
+}
+
+# Make the standard button bar across the top of the page.
+sub make_button_bar
+{
+ my $bbox = Gtk3::Toolbar->new ();
+ $bbox->set_style ("GTK_TOOLBAR_TEXT");
+
+ my $i = 0;
+
+ my $bquit = Gtk3::ToolButton->new (undef, "Quit");
+ $bquit->signal_connect (clicked => sub { Gtk3::main_quit });
+ $bbox->insert ($bquit, $i++);
+
+ my $breload = Gtk3::ToolButton->new (undef, "Reload");
+ $breload->signal_connect (clicked => sub { reread_directory () });
+ $bbox->insert ($breload, $i++);
+
+ my $bnext = Gtk3::ToolButton->new (undef, "Next slide");
+ $bnext->signal_connect (clicked => sub { &switch_slide ("NEXT") });
+ $bbox->insert ($bnext, $i++);
+
+ my $bback = Gtk3::ToolButton->new (undef, "Back");
+ $bback->signal_connect (clicked => sub { &switch_slide ("PREV") });
+ $bbox->insert ($bback, $i++);
+
+ $bbox->insert (Gtk3::SeparatorToolItem->new (), $i++);
+
+ my $brestart = Gtk3::ToolButton->new (undef, "Kill & restart");
+ $brestart->signal_connect (clicked =>
+ sub {
+ kill_process ();
+ run_process ();
+ });
+ $bbox->insert ($brestart, $i++);
+
+ my $sep = Gtk3::SeparatorToolItem->new ();
+ $sep->set_expand (TRUE);
+ $sep->set_draw (FALSE);
+ $bbox->insert ($sep, $i++);
+
+ my $optsmenu = Gtk3::Menu->new ();
+
+ my $mfirst = Gtk3::MenuItem->new ("First slide");
+ $mfirst->signal_connect (activate => sub { &switch_slide ("FIRST") });
+ $mfirst->show ();
+ $optsmenu->append ($mfirst);
+
+ my $mlast = Gtk3::MenuItem->new ("Last slide");
+ $mlast->signal_connect (activate => sub { &switch_slide ("LAST") });
+ $mlast->show ();
+ $optsmenu->append ($mlast);
+
+ my $slidesmenu = Gtk3::Menu->new ();
+ foreach (@files) {
+ my $item = Gtk3::MenuItem->new ($_->{name});
+ my $index = $_->{i};
+ $item->signal_connect (activate => sub { &switch_slide ("I_$index") });
+ $item->set_sensitive ($current->{i} != $index);
+ $item->show ();
+ $slidesmenu->append ($item);
}
+
+ my $mslides = Gtk3::MenuItem->new ("Slides");
+ $mslides->set_submenu ($slidesmenu);
+ $mslides->show ();
+ $optsmenu->append ($mslides);
+
+ my $sep2 = Gtk3::SeparatorMenuItem->new ();
+ $sep2->show ();
+ $optsmenu->append ($sep2);
+
+ my $mscreenshot = Gtk3::MenuItem->new ("Take a screenshot");
+ $mscreenshot->signal_connect (activate => sub { screenshot () });
+ $mscreenshot->show ();
+ $optsmenu->append ($mscreenshot);
+
+ my $sep3 = Gtk3::SeparatorMenuItem->new ();
+ $sep3->show ();
+ $optsmenu->append ($sep3);
+
+ my $mquit = Gtk3::MenuItem->new ("Quit");
+ $mquit->signal_connect (activate => sub { Gtk3::main_quit });
+ $mquit->show ();
+ $optsmenu->append ($mquit);
+
+ my $moptions = Gtk3::MenuToolButton->new (undef, "Options");
+ #$boptions->signal_connect (clicked =>
+ # sub { $optsmenu->popup (undef, undef, undef, undef, ?, ?) } );
+ $bbox->insert ($moptions, $i++);
+ $moptions->set_menu ($optsmenu);
+
+ return ($bbox, $bquit, $breload, $bnext, $bback, $brestart);
+}
+
+# Try running the external "gnome-screenshot" program
+sub screenshot
+{
+ system ("gnome-screenshot");
+
+ return FALSE;
}
1;
+__END__
+
=head1 TUTORIAL
+=head2 START WRITING A TALK
+
+[Before you start writing your real talk, I urge you to read
+L below].
+
+To start your talk, all you have to do is to make a new directory
+somewhere:
+
+ mkdir talk
+ cd talk
+
+A tech talk consists of HTML files ("slides") and shell scripts. The
+filenames must start with a number, followed optionally by a
+description, followed by the extension (C<.html>, C<.sh> or C<.term>).
+So to start our talk with two slides:
+
+ echo "This is the introduction" > 0010-introduction.html
+ echo "This is the second slide" > 0020-second.html
+
+To run it, run the command from within the talk directory:
+
+ techtalk-pse
+
+Any other file in the directory is ignored, so if you want to add
+Makefiles, version control files etc, just go ahead.
+
+=head2 TIPS FOR WRITING HTML
+
+You may have your own techniques and tools for writing HTML, so
+this section is just to share my ideas. I start every
+HTML file with a standard stylesheet and Javascript header:
+
+
+
+
+That just ensures that I can put common styling instructions for all
+my slides in a single file (C), and I have one place where
+I can add all Javascript, if I need to use any (C).
+
+=head3 BACKGROUNDS, FONTS AND LOGOS
+
+To add a common background and font size to all slides, put this in
+C:
+
+ body {
+ font-size: 24pt;
+ background: url(background-image.jpg) no-repeat;
+ }
+
+To add a logo in one corner:
+
+ body {
+ background: url(logo.jpg) top right no-repeat;
+ }
+
+=head3 SCALING AND CENTERING
+
+Scaling slide text and images so that they appear at the same
+proportionate size for any screen resolution can be done using
+Javascript. (See
+L).
+
+If you want to center text horizontally, use CSS, eg:
+
+ p.center {
+ text-align: center;
+ }
+
+To center text vertically, CSS3 is supposed to offer a solution some
+time, but while you're waiting for that try
+L.
+
+=head3 PREVIEWING HTML
+
+I find it helpful to have Firefox open to display the HTML files and
+styles as I edit them. Just start firefox in the talk directory:
+
+ firefox file://$(pwd) &
+
+When you edit an HTML file, click the Firefox reload button to
+immediately see your changes.
+
+Tech Talk PSE uses WebKit embedding to display HTML. HTML is
+standardized enough nowadays that what you see in Firefox and other
+browsers should be the same as what Tech Talk PSE displays.
+WebKit-based browsers (Chrome, Safari) should be identical.
+
+=head2 CREATING FIGURES
+
+Use your favorite tool to draw the figure, convert it to an image (in
+any format that the Mozilla engine can display) and include it using
+an CimgE> tag, eg:
+
+
+
+Suitable tools include: Inkscape, XFig, GnuPlot, GraphViz, and many
+TeX tools such as PicTex and in particular TikZ.
+
+=head2 EMBEDDING VIDEOS, ANIMATIONS, ETC.
+
+Using HTML 5, embedding videos in the browser is easy. See:
+L
+
+For animations, you could try L which has a
+Javascript back-end. There are many other possibilities.
+
+If you are B that the venue will have an internet connection,
+why not embed a YouTube video.
+
+=head2 DISPLAYING EXISTING WEB PAGES
+
+Obviously you could just have an HTML file that contains a redirect to
+the public web page:
+
+
+
+However if you want your talk to work offline, then it's better to
+download the web page in advance, eg. using Firefox's "Save Page As
+-E Web Page, complete" feature, into the talk directory, then
+either rename or make a symbolic link to the slide name:
+
+ ln -s "haXe - Welcome to haXe.html" 0010-haxe-homepage.html
+
+=head2 TIPS FOR WRITING SHELL SCRIPTS
+
+Make sure each C<*.sh> or C<*.term> file you write is executable,
+otherwise Tech Talk PSE won't be able to run it. (The program gives a
+warning if you forget this).
+
+The difference between C<*.sh> (shell script) and C<*.term> (a
+terminal script) is that a shell script runs any commands, usually
+graphical commands, whereas a terminal script runs in a full screen
+terminal.
+
+A good idea is to start each script by sourcing some common functions.
+All my scripts start with:
+
+ #!/bin/bash -
+ source functions
+
+where C is another file (ignored by Tech Talk PSE) which
+contains common functions for setting shell history and starting a
+terminal.
+
+In C, I have:
+
+ # -*- shell-script -*-
+
+ # Place any local environment variables required in 'local'.
+ if [ -f local ]; then source local; fi
+
+ export PS1="$ "
+
+ export HISTFILE=$talkdir/history
+
+ rm -f $HISTFILE
+ touch $HISTFILE
+
+ add_history ()
+ {
+ echo "$@" >> $HISTFILE
+ }
+
+ terminal ()
+ {
+ # Make $HISTFILE unwritable so the shell won't update it
+ # when it exits.
+ chmod -w $HISTFILE
+
+ # Execute a shell.
+ bash --norc "$@"
+ }
+
+By initializing the shell history, during your talk you can rapidly
+recall commands to start parts of the demonstration just by hitting
+the Up arrow. A complete terminal script from one of my talks would
+look like this:
+
+ #!/bin/bash -
+ source functions
+ add_history guestfish -i debian.img
+ terminal
+
+This is just a starting point for your own scripts.
+
=head1 REFERENCE
+=head2 ORDER OF FILES
+
+Tech Talk PSE displays the slides in the directory in lexicographic
+order (the same order as C). Only files matching the
+following regexp are considered:
+
+ ^(\d+)(?:-.*)\.(html|sh|term)$
+
+For future compatibility, you should ensure that every slide has a
+unique numeric part (ie. I have C<0010-aaa.html> and
+C<0010-bbb.html>). This is because in future we want to have the
+ability to display multiple files side by side.
+
+Also for future compatibility, I use file names that have an
+uppercase letter immediately after the numeric part. This is because
+in future we want to allow placement hints using filenames like
+C<0010L-on-the-left.html> and C<0010R-on-the-right.html>.
+
+=head2 BASE URL AND CURRENT DIRECTORY
+
+The base URL is set to the be the directory containing the talk files.
+Thus you should use relative paths, eg:
+
+
+
+You can also place assets into subdirectories, because subdirectories
+are ignored by Tech Talk PSE, eg:
+
+
+
+When running shell scripts, the current directory is also set to be
+the directory containing the talk files, so the same rules about using
+relative paths apply there too.
+
+The environment variable C<$talkdir> is exported to scripts and it
+contains the absolute path of the directory containing the talk files.
+When a script is run, the current directory is the same as
+C<$talkdir>, but if your script changes directory (eg. into a
+subdirectory containing supporting files) then it can be useful to use
+C<$talkdir> to refer back to the original directory.
+
=head1 WHAT MAKES A GOOD TALK
+I like what Edward Tufte writes, for example his evisceration of
+PowerPoint use at NASA here:
+L
+
+However it is sometimes hard to translate his ideas into clear
+presentations, and not all of that is the fault of the tools. Here
+are my thoughts and rules on how to deliver a good talk.
+
+B Before you start drawing any slides at
+all, write your talk as a short essay.
+
+This is the number one mistake that presenters make, and it is partly
+a tool fault, because PowerPoint, OpenOffice, even Tech Talk PSE, all
+open up on an initial blank slide, inviting you to write a title and
+some bullet points. If you start that way, you will end up using the
+program as a kind of clumsy outlining tool, and then reading that
+outline to your audience. That's boring and a waste of time for you
+and your audience. (It would be quicker for them just to download the
+talk and read it at home).
+
+B How long do you want to spend preparing the talk? A good
+talk, with a sound essay behind it, well thought out diagrams and
+figures, and interesting demonstrations, takes many hours to prepare.
+How many hours? I would suggest thinking about how many hours of
+effort your audience are putting in. Even just 20 people sitting
+there for half an hour is 10 man-hours of attention, and that is a
+very small talk, and doesn't include all the extra time and hassle
+that it took to get them all in one place.
+
+I don't think you can get away with spending less than two full days
+preparing a talk, if you want to master the topic and draw up accurate
+slides. Steve Jobs was reputed to spend weeks preparing his annual
+sales talk to the Apple faithful.
+
+B Now that you're going to write your talk as an essay, what
+should go in the slides? I would say that you should consider
+delivering the essay, I the slides, to people who don't make the
+talk. An essay can be turned into an article or blog posting, whereas
+even "read-out-the-bullet-point" slides have a low information
+density, large size, and end-user compatibility problems (*.pptx
+anyone?).
+
+What, then, goes on the slides? Anything you cannot just say:
+diagrams, graphs, videos, animations, and of course (only with Tech
+Talk PSE!) demonstrations.
+
+B Once you've got your talk as an essay and slides, practice,
+practice and practice again. Deliver the talk to yourself in the
+mirror, to your colleagues. Practice going backwards and forwards
+through the slides, using your actual laptop and the software so you
+know what to click and what keys to press. Partly memorize what you
+are going to say (but use short notes written on paper if you need
+to).
+
=head1 SEE ALSO
The Cognitive Style of PowerPoint, Tufte, Edward R.
@@ -347,9 +930,11 @@ The Cognitive Style of PowerPoint, Tufte, Edward R.
Richard W.M. Jones L
+Daniel Berrangé L
+
=head1 COPYRIGHT
-Copyright (C) 2010 Red Hat Inc.
+Copyright (C) 2010-2012 Red Hat Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by