X-Git-Url: http://git.annexia.org/?p=techtalk-pse.git;a=blobdiff_plain;f=techtalk-pse.pl;h=b495911fe6c9deba4f1cd172195a0ff2f3e5b2a6;hp=85104a6136f3b13e7f720f8d6c9be149977a4147;hb=35d7e265d502e203315710725039dfce8bcd6f48;hpb=da52bd4fc08fecea00c82c2c0b8bb44747d85f44 diff --git a/techtalk-pse.pl b/techtalk-pse.pl index 85104a6..b495911 100755 --- a/techtalk-pse.pl +++ b/techtalk-pse.pl @@ -28,10 +28,11 @@ use Pod::Usage; use Getopt::Long; use Cwd qw(getcwd abs_path); use Glib qw(TRUE FALSE); -use Gtk2 -init; -use Gtk2::Gdk::Keysyms; -use Gtk2::WebKit; -use Gnome2::Vte; +use Glib::Object::Introspection; +use Gtk3 -init; +use Gtk3::WebKit; + +Glib::Object::Introspection->setup(basename => "Vte", version => "2.91", package => "Vte"); =encoding utf8 @@ -69,20 +70,21 @@ there is a discussion on L. =head1 RUNNING THE TOOL FROM THE COMMAND LINE -Tech Talk PSE talks are just directories containing C<*.html> and -C<*.sh> (shell script) files: +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)$ + ^(\d+)(?:-.*)\.(html|sh|term)$ -(any other file or subdirectory is ignored). Shell scripts I -be executable. +(any other file or subdirectory is ignored). Shell scripts and +terminal files I be executable. =head2 DISPLAYING AN EXISTING TALK @@ -198,6 +200,9 @@ my %files; my $current; my $pid; my $pipeline; +my $fullscreen = 1; +my $width; +my $height; &reread_directory (); @@ -206,18 +211,20 @@ if (@files == 0) { warn "techtalk-pse: no files found, continuing anyway ...\n" } -my $w = Gtk2::Window->new (); -my $vbox = Gtk2::VBox->new (); -my $webkit = Gtk2::WebKit::WebView->new (); -my $vte = Gnome2::Vte::Terminal->new (); -my $notebook = Gtk2::Notebook->new (); +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 = Gtk2::ScrolledWindow->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); @@ -238,8 +245,7 @@ $notebook->set_show_border(0); # 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 -my $font = $vte->get_font; -$font->set_size($font->get_size * 1.3); +$vte->set_font_scale(1.3); # When an external command exits, automatically # go to the next slide @@ -254,10 +260,20 @@ $vte->signal_connect ( # Exit if the window is closed $w->signal_connect ( destroy => sub { - Gtk2->main_quit; + 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 @@ -271,23 +287,23 @@ $w->signal_connect ( return 0; } - if ($ev->keyval == $Gtk2::Gdk::Keysyms{Right} || - $ev->keyval == $Gtk2::Gdk::Keysyms{Page_Down}) { + if ($ev->keyval == &Gtk3::Gdk::KEY_Right || + $ev->keyval == &Gtk3::Gdk::KEY_Page_Down) { &switch_slide("NEXT"); return 1; - } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{Left} || - $ev->keyval == $Gtk2::Gdk::Keysyms{Page_Up}) { + } elsif ($ev->keyval == &Gtk3::Gdk::KEY_Left || + $ev->keyval == &Gtk3::Gdk::KEY_Page_Up) { &switch_slide("PREV"); return 1; - } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{Home}) { + } elsif ($ev->keyval == &Gtk3::Gdk::KEY_Home) { &switch_slide("FIRST"); return 1; - } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{End}) { + } elsif ($ev->keyval == &Gtk3::Gdk::KEY_End) { &switch_slide("LAST"); return 1; - } elsif ($ev->keyval == $Gtk2::Gdk::Keysyms{q} || - $ev->keyval == $Gtk2::Gdk::Keysyms{Escape}) { - Gtk2->main_quit; + } elsif ($ev->keyval == &Gtk3::Gdk::KEY_q || + $ev->keyval == &Gtk3::Gdk::KEY_Escape) { + Gtk3::main_quit; return 1; } return 0; @@ -295,17 +311,13 @@ $w->signal_connect ( $w->add ($vbox); -$w->show_all (); - -$w->set_decorated (0); -$w->fullscreen (); -$w->move (0,0); -my $scr = $w->get_screen(); +$w->show_all (); +window_fullscreen (); &update_slide(); -Gtk2->main(); +Gtk3::main(); exit 0; @@ -315,13 +327,13 @@ sub reread_directory my $i = 0; foreach (glob ("*")) { - if (/^(\d+)(?:-.*)\.(html|sh)$/) { + if (/^(\d+)(?:-.*)\.(html|sh|term)$/) { print STDERR "reading $_\n" if $verbose; my $seq = $1; 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, ext => $2, i => $i }; push @files, $h; @@ -355,9 +367,31 @@ sub reread_directory } } +sub window_fullscreen +{ + $w->set_decorated (0); + $w->fullscreen (); + $fullscreen = 1; +} + +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; +} + sub run_process { - $pid = $vte->fork_command("./" . $current->{name}, [], [], undef, 0, 0, 0); + my @ret = $vte->spawn_sync('default', ".", ["./" . $current->{name}], [], 'default'); + $pid = $ret[1]; } sub kill_process @@ -376,6 +410,8 @@ sub switch_slide { my $action = shift; + window_fullscreen (); + if ($pid) { kill_process (); } @@ -429,6 +465,13 @@ sub update_slide } # 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 (); @@ -462,28 +505,28 @@ sub update_slide sub make_splash_page { - my $box = Gtk2::VBox->new(); + my $box = Gtk3::VBox->new(); - my $title = Gtk2::Label->new ("Tech Talk Platinum Supreme Edition (PSE)"); + 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 = Gtk2::Label->new ("@VERSION@"); + my $vers = Gtk3::Label->new ("@VERSION@"); $vers->set_use_markup (1); $box->pack_start ($vers, 0, 1, 0); - my $tagline = Gtk2::Label->new ("Superior technical demonstration software"); + my $tagline = Gtk3::Label->new ("Superior technical demonstration software"); $tagline->set_use_markup (1); $box->pack_start ($tagline, 0, 1, 0); - $box->pack_start (Gtk2::Label->new (""), 0, 1, 0); - $box->pack_start (Gtk2::Label->new ("Author: Richard W.M. Jones"), 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 = Gtk2::Label->new ("http;//people.redhat.com/~rjones/"); + 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 (Gtk2::Label->new ("GNU General Public License v2 or above"), 0, 1, 0); + $box->pack_start (Gtk3::Label->new ("GNU General Public License v2 or above"), 0, 1, 0); return $box; } @@ -491,30 +534,30 @@ sub make_splash_page { # Make the standard button bar across the top of the page. sub make_button_bar { - my $bbox = Gtk2::Toolbar->new (); + my $bbox = Gtk3::Toolbar->new (); $bbox->set_style ("GTK_TOOLBAR_TEXT"); my $i = 0; - my $bquit = Gtk2::ToolButton->new (undef, "Quit"); - $bquit->signal_connect (clicked => sub { Gtk2->main_quit }); + my $bquit = Gtk3::ToolButton->new (undef, "Quit"); + $bquit->signal_connect (clicked => sub { Gtk3::main_quit }); $bbox->insert ($bquit, $i++); - my $breload = Gtk2::ToolButton->new (undef, "Reload"); + my $breload = Gtk3::ToolButton->new (undef, "Reload"); $breload->signal_connect (clicked => sub { reread_directory () }); $bbox->insert ($breload, $i++); - my $bnext = Gtk2::ToolButton->new (undef, "Next slide"); + my $bnext = Gtk3::ToolButton->new (undef, "Next slide"); $bnext->signal_connect (clicked => sub { &switch_slide ("NEXT") }); $bbox->insert ($bnext, $i++); - my $bback = Gtk2::ToolButton->new (undef, "Back"); + my $bback = Gtk3::ToolButton->new (undef, "Back"); $bback->signal_connect (clicked => sub { &switch_slide ("PREV") }); $bbox->insert ($bback, $i++); - $bbox->insert (Gtk2::SeparatorToolItem->new (), $i++); + $bbox->insert (Gtk3::SeparatorToolItem->new (), $i++); - my $brestart = Gtk2::ToolButton->new (undef, "Kill & restart"); + my $brestart = Gtk3::ToolButton->new (undef, "Kill & restart"); $brestart->signal_connect (clicked => sub { kill_process (); @@ -522,26 +565,26 @@ sub make_button_bar }); $bbox->insert ($brestart, $i++); - my $sep = Gtk2::SeparatorToolItem->new (); + my $sep = Gtk3::SeparatorToolItem->new (); $sep->set_expand (TRUE); $sep->set_draw (FALSE); $bbox->insert ($sep, $i++); - my $optsmenu = Gtk2::Menu->new (); + my $optsmenu = Gtk3::Menu->new (); - my $mfirst = Gtk2::MenuItem->new ("First slide"); + my $mfirst = Gtk3::MenuItem->new ("First slide"); $mfirst->signal_connect (activate => sub { &switch_slide ("FIRST") }); $mfirst->show (); $optsmenu->append ($mfirst); - my $mlast = Gtk2::MenuItem->new ("Last slide"); + my $mlast = Gtk3::MenuItem->new ("Last slide"); $mlast->signal_connect (activate => sub { &switch_slide ("LAST") }); $mlast->show (); $optsmenu->append ($mlast); - my $slidesmenu = Gtk2::Menu->new (); + my $slidesmenu = Gtk3::Menu->new (); foreach (@files) { - my $item = Gtk2::MenuItem->new ($_->{name}); + my $item = Gtk3::MenuItem->new ($_->{name}); my $index = $_->{i}; $item->signal_connect (activate => sub { &switch_slide ("I_$index") }); $item->set_sensitive ($current->{i} != $index); @@ -549,30 +592,30 @@ sub make_button_bar $slidesmenu->append ($item); } - my $mslides = Gtk2::MenuItem->new ("Slides"); + my $mslides = Gtk3::MenuItem->new ("Slides"); $mslides->set_submenu ($slidesmenu); $mslides->show (); $optsmenu->append ($mslides); - my $sep2 = Gtk2::SeparatorMenuItem->new (); + my $sep2 = Gtk3::SeparatorMenuItem->new (); $sep2->show (); $optsmenu->append ($sep2); - my $mscreenshot = Gtk2::MenuItem->new ("Take a screenshot"); + my $mscreenshot = Gtk3::MenuItem->new ("Take a screenshot"); $mscreenshot->signal_connect (activate => sub { screenshot () }); $mscreenshot->show (); $optsmenu->append ($mscreenshot); - my $sep3 = Gtk2::SeparatorMenuItem->new (); + my $sep3 = Gtk3::SeparatorMenuItem->new (); $sep3->show (); $optsmenu->append ($sep3); - my $mquit = Gtk2::MenuItem->new ("Quit"); - $mquit->signal_connect (activate => sub { Gtk2->main_quit }); + my $mquit = Gtk3::MenuItem->new ("Quit"); + $mquit->signal_connect (activate => sub { Gtk3::main_quit }); $mquit->show (); $optsmenu->append ($mquit); - my $moptions = Gtk2::MenuToolButton->new (undef, "Options"); + my $moptions = Gtk3::MenuToolButton->new (undef, "Options"); #$boptions->signal_connect (clicked => # sub { $optsmenu->popup (undef, undef, undef, undef, ?, ?) } ); $bbox->insert ($moptions, $i++); @@ -581,29 +624,11 @@ sub make_button_bar return ($bbox, $bquit, $breload, $bnext, $bback, $brestart); } -# Try running the external "gnome-screenshot" program, if it's -# available, else take a screenshot using gdk routines. +# Try running the external "gnome-screenshot" program sub screenshot { system ("gnome-screenshot"); - if ($? == -1) { - # We are going to save the entire screen. - my $root = Gtk2::Gdk->get_default_root_window (); - my ($width, $height) = $root->get_size; - - # Create blank pixbuf to hold the image. - my $gdkpixbuf = Gtk2::Gdk::Pixbuf->new ('rgb', - 0, 8, $width, $height); - - $gdkpixbuf->get_from_drawable ($root, $root->get_colormap (), - 0, 0, 0, 0, $width, $height); - - my $i = 0; - $i++ while -f "screenshot$i.png"; - $gdkpixbuf->save ("screenshot$i.png", 'png'); - } - return FALSE; } @@ -626,8 +651,8 @@ somewhere: 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> or C<.sh>). So to -start our talk with two slides: +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 @@ -695,9 +720,10 @@ styles as I edit them. Just start firefox in the talk directory: When you edit an HTML file, click the Firefox reload button to immediately see your changes. -Tech Talk PSE uses Mozilla embedding to display HTML, which uses the -same Mozilla engine as Firefox, so what you should see in Firefox -should be identical to what Tech Talk PSE displays. +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 @@ -707,8 +733,8 @@ an CimgE> tag, eg: -Suitable tools include: XFig, GnuPlot, GraphViz, and many TeX tools -such as PicTex and in particular TikZ. +Suitable tools include: Inkscape, XFig, GnuPlot, GraphViz, and many +TeX tools such as PicTex and in particular TikZ. =head2 EMBEDDING VIDEOS, ANIMATIONS, ETC. @@ -737,9 +763,14 @@ either rename or make a symbolic link to the slide name: =head2 TIPS FOR WRITING SHELL SCRIPTS -Make sure each C<*.sh> 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). +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: @@ -776,30 +807,21 @@ In C, I have: # when it exits. chmod -w $HISTFILE - # Run gnome-terminal. - exec \ - gnome-terminal \ - --window \ - --geometry=+100+100 \ - --hide-menubar \ - --disable-factory \ - -e '/bin/bash --norc' \ - "$@" + # 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 shell script from one of my talks would look -like this: +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 --title="Examining a Debian guest image in guestfish" + terminal -This is just a starting point for your own scripts. You may want to -use a different terminal, such as xterm, and you may want to adjust -terminal fonts. +This is just a starting point for your own scripts. =head1 REFERENCE @@ -809,7 +831,7 @@ 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)$ + ^(\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 @@ -877,7 +899,7 @@ 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 is reputed to spend weeks preparing his annual +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 @@ -908,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