6 # Copyright (C) 2010-2012 Red Hat Inc.
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 use Cwd qw(getcwd abs_path);
30 use Glib qw(TRUE FALSE);
32 use Gtk2::Gdk::Keysyms;
40 techtalk-pse - superior technical demonstration software
44 cd /path/to/talk/; techtalk-pse
46 techtalk-pse /path/to/talk/
50 Tech Talk "Platinum Supreme Edition" (PSE) is Linux Presentation
51 Software designed by technical people to give technical software
52 demonstrations to other technical people. It is designed to be simple
53 to use (for people who know how to use an editor and the command line)
54 and powerful, so that you can create informative, technically accurate
55 and entertaining talks and demonstrations.
57 Tech Talk PSE is good at opening editors at the right place, opening
58 shell prompts with preloaded history, compiling and running things
59 during the demonstration, displaying text, photos, figures and video.
61 Tech Talk PSE is I<bad> at slide effects, chart junk and bullet
64 This manual page covers all the documentation you will need to use
65 Tech Talk PSE. The next section covers running the tool from the
66 command line. After that there is a L</TUTORIAL> section to get you
67 started. Then there is a detailed L</REFERENCE> section. Finally
68 there is a discussion on L<WHAT MAKES A GOOD TALK>.
70 =head1 RUNNING THE TOOL FROM THE COMMAND LINE
72 Tech Talk PSE talks are just directories containing C<*.html>,
73 C<*.sh> (shell script) and C<*.term> (terminal) files:
75 0010-introduction.html
77 0600-command-line.term
80 The filenames that Tech Talk PSE considers to be slides have to match
81 the regular expression:
83 ^(\d+)(?:-.*)\.(html|sh|term)$
85 (any other file or subdirectory is ignored). Shell scripts and
86 terminal files I<must> be executable.
88 =head2 DISPLAYING AN EXISTING TALK
90 To display or run a talk, change into the directory containing all
91 those files and run the C<techtalk-pse> command:
93 cd /path/to/talk/; techtalk-pse
95 You can also run C<techtalk-pse> without changing directory, instead
96 specifying the path to the talk:
98 techtalk-pse /path/to/talk/
110 Display brief help and exit.
118 Start at the last slide.
120 You cannot use this with the B<-n> / B<--start> option.
126 =item B<-n SLIDE> | B<--start SLIDE>
128 Start at the named slide. I<SLIDE> is the shortest unique prefix of
129 the slide name, so to start at a slide named
130 I<00010-introduction.html>, you could use I<-n 00010> or I<-n 00010-intro>,
131 or give the full filename I<-n 00010-introduction.html>.
133 The default is to start at the first slide in the talk.
141 Display verbose messages, useful for debugging or tracing
142 what the program is doing.
150 Display version number and exit.
154 GetOptions ("help|?" => \$help,
157 "start=s" => \$start,
158 "verbose" => \$verbose,
159 "version" => \$version,
166 pod2usage (1) if $help;
168 print "@PACKAGE@ @VERSION@\n";
171 die "techtalk-pse: cannot use --start and --last options together\n"
172 if defined $last && defined $start;
174 die "techtalk-pse: too many arguments\n" if @ARGV >= 2;
176 # Get the true name of the program.
183 chdir $d or die "techtalk-pse: chdir: $d: $!";
185 # XXX In future allow people to specify an archive and unpack
187 die "techtalk-pse: argument is not a directory"
191 # Get the talk directory and set environment variable $talkdir
192 # which is inherited by all the scripts.
193 my $talkdir = getcwd;
194 $ENV{talkdir} = $talkdir;
203 &reread_directory ();
205 print STDERR "read ", 0+@files, " files\n" if $verbose;
207 warn "techtalk-pse: no files found, continuing anyway ...\n"
210 my $w = Gtk2::Window->new ();
211 my $vbox = Gtk2::VBox->new ();
212 my $webkit = Gtk2::WebKit::WebView->new ();
213 my $vte = Gnome2::Vte::Terminal->new ();
214 my $notebook = Gtk2::Notebook->new ();
215 my $splash = make_splash_page ();
216 my $emptylabel = Gtk2::Label->new ();
218 my $webkitscroll = Gtk2::ScrolledWindow->new ();
219 $webkitscroll->add ($webkit);
220 $webkitscroll->set_policy('automatic', 'automatic');
222 my $webkitpage = $notebook->append_page ($webkitscroll);
223 my $shpage = $notebook->append_page ($emptylabel);
224 my $vtepage = $notebook->append_page ($vte);
225 my $splashpage = $notebook->append_page ($splash);
227 my ($bbox, $bquit, $breload, $bnext, $bback, $brestart) = make_button_bar ();
229 $vbox->pack_start($bbox, 0, 0, 0);
230 $vbox->pack_start($notebook, 1, 1, 0);
232 $notebook->set_show_tabs(0);
233 $notebook->set_show_border(0);
235 # Default font size is almost certainly too small
236 # for audience to see.
237 # XXX we should make font size configurable via
239 # XXX any way we can scale WebKit programmatically
240 # to set base size which CSS is relative to ?
241 # NB careful setting it too big, because it will
242 # force a min size on the terminal. Scaling 1.3
243 # is biggest we can do while fitting 1024x768
244 my $font = $vte->get_font;
245 $font->set_size($font->get_size * 1.3);
247 # When an external command exits, automatically
248 # go to the next slide
249 $vte->signal_connect (
250 'child-exited' => sub {
253 &switch_slide("NEXT");
257 # Exit if the window is closed
264 # Handle left/right arrows, page up/down & home/end
265 # as slide navigation commands. But not when there
268 'key-press-event' => sub {
272 # If a shell is running, don't trap keys
277 if ($ev->keyval == $Gtk2::Gdk::Keysyms{Right} ||
278 $ev->keyval == $Gtk2::Gdk::Keysyms{Page_Down}) {
279 &switch_slide("NEXT");
281 } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{Left} ||
282 $ev->keyval == $Gtk2::Gdk::Keysyms{Page_Up}) {
283 &switch_slide("PREV");
285 } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{Home}) {
286 &switch_slide("FIRST");
288 } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{End}) {
289 &switch_slide("LAST");
291 } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{q} ||
292 $ev->keyval == $Gtk2::Gdk::Keysyms{Escape}) {
302 # This allows us to resize the window in window_in_corner().
303 $w->set_geometry_hints ($w, { min_width => 100 }, qw(min-size));
307 window_fullscreen ();
320 foreach (glob ("*")) {
321 if (/^(\d+)(?:-.*)\.(html|sh|term)$/) {
322 print STDERR "reading $_\n" if $verbose;
326 warn "techtalk-pse: $_: command file is not executable (+x)\n"
327 if ($ext eq "sh" || $ext eq "term") && ! -x $_;
329 my $h = { name => $_, seq => $1, ext => $2, i => $i };
334 print STDERR "ignoring $_\n" if $verbose;
339 $files[0]->{first} = 1;
340 $files[$#files]->{last} = 1;
343 # Work out what slide we're starting on.
344 if (@files && !$current) {
346 foreach my $file (@files) {
347 if ($file->{name} =~ /^$start/) {
353 $current = $files[$#files];
356 $current = $files[0];
361 sub window_fullscreen
363 $w->set_decorated (0);
370 $w->set_decorated (1);
373 my $root = Gtk2::Gdk->get_default_root_window ();
374 my ($width, $height) = $root->get_size;
376 $w->resize ($width/2, $height/4);
377 $w->move ($width/2, 64);
382 $pid = $vte->fork_command("./" . $current->{name}, [], [], undef, 0, 0, 0);
387 print STDERR "sending TERM signal to process group $pid\n"
391 # Clears out any current displayed text
393 $vte->set_default_colors();
401 window_fullscreen ();
407 $pipeline->set_state('ready');
410 print STDERR "action = $action\n" if $verbose;
412 my $i = defined $current ? $current->{i} : 0;
414 print STDERR "i = $i\n" if $verbose;
415 if ($action eq "PREV") {
416 if (defined $current) {
421 } elsif ($action eq "NEXT") {
423 } elsif ($action eq "FIRST") {
425 } elsif ($action eq "LAST") {
427 } elsif ($action =~ /^I_(\d+)$/) {
435 $current = $files[$i];
445 # Display an HTML page.
446 if ($current->{ext} eq "html") {
447 $notebook->set_current_page ($webkitpage);
448 my $name = $current->{name};
449 my $url = "file://$talkdir/$name";
451 $webkit->load_uri ($url);
452 $webkit->grab_focus ();
454 # Run a shell command.
455 elsif ($current->{ext} eq "sh") {
458 $notebook->set_current_page ($shpage);
461 # Open a VTE terminal.
462 elsif ($current->{ext} eq "term") {
463 $notebook->set_current_page ($vtepage);
468 $notebook->set_current_page ($splashpage);
477 if (defined $current) {
480 $bnext->set_sensitive (1);
481 $bback->set_sensitive (!exists $current->{first});
489 $bnext->set_sensitive (0);
490 $bback->set_sensitive (int(@files));
495 sub make_splash_page {
496 my $box = Gtk2::VBox->new();
498 my $title = Gtk2::Label->new ("<b><span size='x-large'>Tech Talk Platinum Supreme Edition (PSE)</span></b>");
499 $title->set_use_markup (1);
501 $box->pack_start ($title, 0, 1, 0);
503 my $vers = Gtk2::Label->new ("<b><span size='large'>@VERSION@</span></b>");
504 $vers->set_use_markup (1);
505 $box->pack_start ($vers, 0, 1, 0);
507 my $tagline = Gtk2::Label->new ("<i><span size='large'>Superior technical demonstration software</span></i>");
508 $tagline->set_use_markup (1);
510 $box->pack_start ($tagline, 0, 1, 0);
511 $box->pack_start (Gtk2::Label->new (""), 0, 1, 0);
512 $box->pack_start (Gtk2::Label->new ("Author: Richard W.M. Jones"), 0, 1, 0);
514 my $url = Gtk2::Label->new ("<a href='http://people.redhat.com/~rjones'>http;//people.redhat.com/~rjones/</a>");
515 $url->set_use_markup (1);
516 $box->pack_start ($url, 0, 1, 0);
517 $box->pack_start (Gtk2::Label->new ("GNU General Public License v2 or above"), 0, 1, 0);
522 # Make the standard button bar across the top of the page.
525 my $bbox = Gtk2::Toolbar->new ();
526 $bbox->set_style ("GTK_TOOLBAR_TEXT");
530 my $bquit = Gtk2::ToolButton->new (undef, "Quit");
531 $bquit->signal_connect (clicked => sub { Gtk2->main_quit });
532 $bbox->insert ($bquit, $i++);
534 my $breload = Gtk2::ToolButton->new (undef, "Reload");
535 $breload->signal_connect (clicked => sub { reread_directory () });
536 $bbox->insert ($breload, $i++);
538 my $bnext = Gtk2::ToolButton->new (undef, "Next slide");
539 $bnext->signal_connect (clicked => sub { &switch_slide ("NEXT") });
540 $bbox->insert ($bnext, $i++);
542 my $bback = Gtk2::ToolButton->new (undef, "Back");
543 $bback->signal_connect (clicked => sub { &switch_slide ("PREV") });
544 $bbox->insert ($bback, $i++);
546 $bbox->insert (Gtk2::SeparatorToolItem->new (), $i++);
548 my $brestart = Gtk2::ToolButton->new (undef, "Kill & restart");
549 $brestart->signal_connect (clicked =>
554 $bbox->insert ($brestart, $i++);
556 my $sep = Gtk2::SeparatorToolItem->new ();
557 $sep->set_expand (TRUE);
558 $sep->set_draw (FALSE);
559 $bbox->insert ($sep, $i++);
561 my $optsmenu = Gtk2::Menu->new ();
563 my $mfirst = Gtk2::MenuItem->new ("First slide");
564 $mfirst->signal_connect (activate => sub { &switch_slide ("FIRST") });
566 $optsmenu->append ($mfirst);
568 my $mlast = Gtk2::MenuItem->new ("Last slide");
569 $mlast->signal_connect (activate => sub { &switch_slide ("LAST") });
571 $optsmenu->append ($mlast);
573 my $slidesmenu = Gtk2::Menu->new ();
575 my $item = Gtk2::MenuItem->new ($_->{name});
577 $item->signal_connect (activate => sub { &switch_slide ("I_$index") });
578 $item->set_sensitive ($current->{i} != $index);
580 $slidesmenu->append ($item);
583 my $mslides = Gtk2::MenuItem->new ("Slides");
584 $mslides->set_submenu ($slidesmenu);
586 $optsmenu->append ($mslides);
588 my $sep2 = Gtk2::SeparatorMenuItem->new ();
590 $optsmenu->append ($sep2);
592 my $mscreenshot = Gtk2::MenuItem->new ("Take a screenshot");
593 $mscreenshot->signal_connect (activate => sub { screenshot () });
594 $mscreenshot->show ();
595 $optsmenu->append ($mscreenshot);
597 my $sep3 = Gtk2::SeparatorMenuItem->new ();
599 $optsmenu->append ($sep3);
601 my $mquit = Gtk2::MenuItem->new ("Quit");
602 $mquit->signal_connect (activate => sub { Gtk2->main_quit });
604 $optsmenu->append ($mquit);
606 my $moptions = Gtk2::MenuToolButton->new (undef, "Options");
607 #$boptions->signal_connect (clicked =>
608 # sub { $optsmenu->popup (undef, undef, undef, undef, ?, ?) } );
609 $bbox->insert ($moptions, $i++);
610 $moptions->set_menu ($optsmenu);
612 return ($bbox, $bquit, $breload, $bnext, $bback, $brestart);
615 # Try running the external "gnome-screenshot" program, if it's
616 # available, else take a screenshot using gdk routines.
619 system ("gnome-screenshot");
622 # We are going to save the entire screen.
623 my $root = Gtk2::Gdk->get_default_root_window ();
624 my ($width, $height) = $root->get_size;
626 # Create blank pixbuf to hold the image.
627 my $gdkpixbuf = Gtk2::Gdk::Pixbuf->new ('rgb',
628 0, 8, $width, $height);
630 $gdkpixbuf->get_from_drawable ($root, $root->get_colormap (),
631 0, 0, 0, 0, $width, $height);
634 $i++ while -f "screenshot$i.png";
635 $gdkpixbuf->save ("screenshot$i.png", 'png');
647 =head2 START WRITING A TALK
649 [Before you start writing your real talk, I urge you to read
650 L</WHAT MAKES A GOOD TALK> below].
652 To start your talk, all you have to do is to make a new directory
658 A tech talk consists of HTML files ("slides") and shell scripts. The
659 filenames must start with a number, followed optionally by a
660 description, followed by the extension (C<.html>, C<.sh> or C<.term>).
661 So to start our talk with two slides:
663 echo "This is the introduction" > 0010-introduction.html
664 echo "This is the second slide" > 0020-second.html
666 To run it, run the command from within the talk directory:
670 Any other file in the directory is ignored, so if you want to add
671 Makefiles, version control files etc, just go ahead.
673 =head2 TIPS FOR WRITING HTML
675 You may have your own techniques and tools for writing HTML, so
676 this section is just to share my ideas. I start every
677 HTML file with a standard stylesheet and Javascript header:
679 <link rel="stylesheet" href="style.css" type="text/css"/>
680 <script src="code.js" type="text/javascript"></script>
682 That just ensures that I can put common styling instructions for all
683 my slides in a single file (C<style.css>), and I have one place where
684 I can add all Javascript, if I need to use any (C<code.js>).
686 =head3 BACKGROUNDS, FONTS AND LOGOS
688 To add a common background and font size to all slides, put this in
693 background: url(background-image.jpg) no-repeat;
696 To add a logo in one corner:
699 background: url(logo.jpg) top right no-repeat;
702 =head3 SCALING AND CENTERING
704 Scaling slide text and images so that they appear at the same
705 proportionate size for any screen resolution can be done using
707 L<https://developer.mozilla.org/En/DOM/window.innerHeight>).
709 If you want to center text horizontally, use CSS, eg:
715 To center text vertically, CSS3 is supposed to offer a solution some
716 time, but while you're waiting for that try
717 L<http://www.w3.org/Style/Examples/007/center#vertical>.
719 =head3 PREVIEWING HTML
721 I find it helpful to have Firefox open to display the HTML files and
722 styles as I edit them. Just start firefox in the talk directory:
724 firefox file://$(pwd) &
726 When you edit an HTML file, click the Firefox reload button to
727 immediately see your changes.
729 Tech Talk PSE uses Mozilla embedding to display HTML, which uses the
730 same Mozilla engine as Firefox, so what you should see in Firefox
731 should be identical to what Tech Talk PSE displays.
733 =head2 CREATING FIGURES
735 Use your favorite tool to draw the figure, convert it to an image (in
736 any format that the Mozilla engine can display) and include it using
737 an C<E<lt>imgE<gt>> tag, eg:
741 Suitable tools include: XFig, GnuPlot, GraphViz, and many TeX tools
742 such as PicTex and in particular TikZ.
744 =head2 EMBEDDING VIDEOS, ANIMATIONS, ETC.
746 Using HTML 5, embedding videos in the browser is easy. See:
747 L<https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox>
749 For animations, you could try L<Haxe|http://haxe.org/> which has a
750 Javascript back-end. There are many other possibilities.
752 If you are B<sure> that the venue will have an internet connection,
753 why not embed a YouTube video.
755 =head2 DISPLAYING EXISTING WEB PAGES
757 Obviously you could just have an HTML file that contains a redirect to
760 <meta http-equiv="Refresh" content="0; url=http://www.example.com/">
762 However if you want your talk to work offline, then it's better to
763 download the web page in advance, eg. using Firefox's "Save Page As
764 -E<gt> Web Page, complete" feature, into the talk directory, then
765 either rename or make a symbolic link to the slide name:
767 ln -s "haXe - Welcome to haXe.html" 0010-haxe-homepage.html
769 =head2 TIPS FOR WRITING SHELL SCRIPTS
771 Make sure each C<*.sh> or C<*.term> file you write is executable,
772 otherwise Tech Talk PSE won't be able to run it. (The program gives a
773 warning if you forget this).
775 The difference between C<*.sh> (shell script) and C<*.term> (a
776 terminal script) is that a shell script runs any commands, usually
777 graphical commands, whereas a terminal script runs in a full screen
780 A good idea is to start each script by sourcing some common functions.
781 All my scripts start with:
786 where C<functions> is another file (ignored by Tech Talk PSE) which
787 contains common functions for setting shell history and starting a
790 In C<functions>, I have:
792 # -*- shell-script -*-
794 # Place any local environment variables required in 'local'.
795 if [ -f local ]; then source local; fi
799 export HISTFILE=$talkdir/history
806 echo "$@" >> $HISTFILE
811 # Make $HISTFILE unwritable so the shell won't update it
819 By initializing the shell history, during your talk you can rapidly
820 recall commands to start parts of the demonstration just by hitting
821 the Up arrow. A complete terminal script from one of my talks would
826 add_history guestfish -i debian.img
829 This is just a starting point for your own scripts.
833 =head2 ORDER OF FILES
835 Tech Talk PSE displays the slides in the directory in lexicographic
836 order (the same order as C<LANG=C ls -1>). Only files matching the
837 following regexp are considered:
839 ^(\d+)(?:-.*)\.(html|sh|term)$
841 For future compatibility, you should ensure that every slide has a
842 unique numeric part (ie. I<don't> have C<0010-aaa.html> and
843 C<0010-bbb.html>). This is because in future we want to have the
844 ability to display multiple files side by side.
846 Also for future compatibility, I<don't> use file names that have an
847 uppercase letter immediately after the numeric part. This is because
848 in future we want to allow placement hints using filenames like
849 C<0010L-on-the-left.html> and C<0010R-on-the-right.html>.
851 =head2 BASE URL AND CURRENT DIRECTORY
853 The base URL is set to the be the directory containing the talk files.
854 Thus you should use relative paths, eg:
858 You can also place assets into subdirectories, because subdirectories
859 are ignored by Tech Talk PSE, eg:
861 <img src="images/fig1.gif">
863 When running shell scripts, the current directory is also set to be
864 the directory containing the talk files, so the same rules about using
865 relative paths apply there too.
867 The environment variable C<$talkdir> is exported to scripts and it
868 contains the absolute path of the directory containing the talk files.
869 When a script is run, the current directory is the same as
870 C<$talkdir>, but if your script changes directory (eg. into a
871 subdirectory containing supporting files) then it can be useful to use
872 C<$talkdir> to refer back to the original directory.
874 =head1 WHAT MAKES A GOOD TALK
876 I like what Edward Tufte writes, for example his evisceration of
877 PowerPoint use at NASA here:
878 L<http://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=0001yB>
880 However it is sometimes hard to translate his ideas into clear
881 presentations, and not all of that is the fault of the tools. Here
882 are my thoughts and rules on how to deliver a good talk.
884 B<First, most important rule:> Before you start drawing any slides at
885 all, write your talk as a short essay.
887 This is the number one mistake that presenters make, and it is partly
888 a tool fault, because PowerPoint, OpenOffice, even Tech Talk PSE, all
889 open up on an initial blank slide, inviting you to write a title and
890 some bullet points. If you start that way, you will end up using the
891 program as a kind of clumsy outlining tool, and then reading that
892 outline to your audience. That's boring and a waste of time for you
893 and your audience. (It would be quicker for them just to download the
894 talk and read it at home).
896 B<Secondly:> How long do you want to spend preparing the talk? A good
897 talk, with a sound essay behind it, well thought out diagrams and
898 figures, and interesting demonstrations, takes many hours to prepare.
899 How many hours? I would suggest thinking about how many hours of
900 effort your audience are putting in. Even just 20 people sitting
901 there for half an hour is 10 man-hours of attention, and that is a
902 very small talk, and doesn't include all the extra time and hassle
903 that it took to get them all in one place.
905 I don't think you can get away with spending less than two full days
906 preparing a talk, if you want to master the topic and draw up accurate
907 slides. Steve Jobs is reputed to spend weeks preparing his annual
908 sales talk to the Apple faithful.
910 B<Thirdly:> Now that you're going to write your talk as an essay, what
911 should go in the slides? I would say that you should consider
912 delivering the essay, I<not> the slides, to people who don't make the
913 talk. An essay can be turned into an article or blog posting, whereas
914 even "read-out-the-bullet-point" slides have a low information
915 density, large size, and end-user compatibility problems (*.pptx
918 What, then, goes on the slides? Anything you cannot just say:
919 diagrams, graphs, videos, animations, and of course (only with Tech
920 Talk PSE!) demonstrations.
922 B<Lastly:> Once you've got your talk as an essay and slides, practice,
923 practice and practice again. Deliver the talk to yourself in the
924 mirror, to your colleagues. Practice going backwards and forwards
925 through the slides, using your actual laptop and the software so you
926 know what to click and what keys to press. Partly memorize what you
927 are going to say (but use short notes written on paper if you need
932 The Cognitive Style of PowerPoint, Tufte, Edward R.
936 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
940 Copyright (C) 2010 Red Hat Inc.
942 This program is free software; you can redistribute it and/or modify
943 it under the terms of the GNU General Public License as published by
944 the Free Software Foundation; either version 2 of the License, or
945 (at your option) any later version.
947 This program is distributed in the hope that it will be useful,
948 but WITHOUT ANY WARRANTY; without even the implied warranty of
949 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
950 GNU General Public License for more details.
952 You should have received a copy of the GNU General Public License
953 along with this program; if not, write to the Free Software
954 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.