+ my $pid;
+ # http://docstore.mik.ua/orelly/perl/cookbook/ch10_17.htm
+ local *run_process = sub {
+ $pid = fork ();
+ die "fork: $!" unless defined $pid;
+ unless ($pid) {
+ # Child.
+ POSIX::setsid ();
+ exec ("./".$slide->{name});
+ die "failed to execute command: ", $slide->{name}, ": $!";
+ }
+ # Parent returns.
+ };
+ local *kill_process = sub {
+ print STDERR "sending TERM signal to process group $pid\n"
+ if $verbose;
+ kill "TERM", -$pid;
+ };
+ run_process ();
+
+ my $r = "NEXT";
+
+ my $w = Gtk2::Window->new ();
+
+ my $s = $w->get_screen;
+ $w->set_default_size ($s->get_width, -1);
+ $w->move (0, 0);
+ $w->set_decorated (0);
+
+ my $bbox =
+ make_button_bar ((exists $slide->{first}),
+ (exists $slide->{last}),
+ sub { $r = $_[0]; $w->destroy },
+ restart => sub {
+ kill_process ();
+ run_process ();
+ },
+ );
+
+ $w->add ($bbox);
+
+ $w->signal_connect (destroy => sub {
+ Gtk2->main_quit;
+ return FALSE;
+ });
+ $w->show_all ();
+
+ Gtk2->main;
+
+ kill_process ();
+ print STDERR "returning r=$r\n" if $verbose;
+ return $r;
+ }
+}
+
+# If invoked with the --mozembed parameter then we just display a
+# single page. This is just to prevent crashes in MozEmbed from
+# killing the whole program.
+sub run_mozembed
+{
+ my $w = Gtk2::Window->new ();
+ my $vbox = Gtk2::VBox->new ();
+ my $moz = Gtk2::MozEmbed->new ();
+
+ reread_directory ();
+
+ my $name = $ARGV[1];
+ $current = $files{$name};
+ my $url = "file://$talkdir/$name";
+
+ my $bbox =
+ make_button_bar ($current->{first}, $current->{last},
+ sub { print "RESULT ", $_[0], "\n"; $w->destroy }
+ );
+
+ $vbox->pack_start ($bbox, 0, 0, 0);
+ $vbox->add ($moz);
+ $w->fullscreen ();
+ #$w->set_default_size (640, 480);
+ $w->add ($vbox);
+
+ $w->signal_connect (destroy => sub {
+ Gtk2->main_quit;
+ return FALSE;
+ });
+ $w->show_all ();
+
+ $moz->load_url ($url);
+
+ Gtk2->main;
+
+ exit 0;
+}
+
+# Make the standard button bar across the top of the page.
+sub make_button_bar
+{
+ my $first = shift;
+ my $last = shift;
+ my $cb = shift;
+ my %params = @_;
+
+ my $bbox = Gtk2::Toolbar->new ();
+ $bbox->set_style ("GTK_TOOLBAR_TEXT");
+
+ my $i = 0;
+
+ my $bnext = Gtk2::ToolButton->new (undef, "Next slide");
+ $bnext->signal_connect (clicked => sub { &$cb ("NEXT") });
+ $bnext->set_sensitive (!$last);
+ $bbox->insert ($bnext, $i++);
+
+ my $bback = Gtk2::ToolButton->new (undef, "Back");
+ $bback->signal_connect (clicked => sub { &$cb ("PREV") });
+ $bback->set_sensitive (!$first);
+ $bbox->insert ($bback, $i++);
+
+ if (exists $params{restart}) {
+ $bbox->insert (Gtk2::SeparatorToolItem->new (), $i++);
+
+ my $brestart = Gtk2::ToolButton->new (undef, "Kill & restart");
+ $brestart->signal_connect (clicked => $params{restart});
+ $bbox->insert ($brestart, $i++);
+ }
+
+ my $sep = Gtk2::SeparatorToolItem->new ();
+ $sep->set_expand (TRUE);
+ $sep->set_draw (FALSE);
+ $bbox->insert ($sep, $i++);
+
+ my $optsmenu = Gtk2::Menu->new ();
+
+ my $bfirst = Gtk2::MenuItem->new ("First slide");
+ $bfirst->signal_connect (activate => sub { \&$cb ("FIRST") });
+ $bfirst->show ();
+ $optsmenu->append ($bfirst);
+
+ my $blast = Gtk2::MenuItem->new ("Last slide");
+ $blast->signal_connect (activate => sub { \&$cb ("LAST") });
+ $blast->show ();
+ $optsmenu->append ($blast);
+
+ my $slidesmenu = Gtk2::Menu->new ();
+ foreach (@files) {
+ my $item = Gtk2::MenuItem->new ($_->{name});
+ my $index = $_->{i};
+ $item->signal_connect (activate => sub { \&$cb ("I_$index") });
+ $item->set_sensitive ($current->{i} != $index);
+ $item->show ();
+ $slidesmenu->append ($item);
+ }
+
+ my $bslides = Gtk2::MenuItem->new ("Slides");
+ $bslides->set_submenu ($slidesmenu);
+ $bslides->show ();
+ $optsmenu->append ($bslides);
+
+ my $sep2 = Gtk2::SeparatorMenuItem->new ();
+ $sep2->show ();
+ $optsmenu->append ($sep2);
+
+ my $bscreenshot = Gtk2::MenuItem->new ("Take a screenshot");
+ $bscreenshot->signal_connect (activate => sub { screenshot () });
+ $bscreenshot->show ();
+ $optsmenu->append ($bscreenshot);
+
+ my $sep3 = Gtk2::SeparatorMenuItem->new ();
+ $sep3->show ();
+ $optsmenu->append ($sep3);
+
+ my $bquit = Gtk2::MenuItem->new ("Quit");
+ $bquit->signal_connect (activate => sub { \&$cb ("QUIT") });
+ $bquit->show ();
+ $optsmenu->append ($bquit);
+
+ my $boptions = Gtk2::MenuToolButton->new (undef, "Options");
+ #$boptions->signal_connect (clicked =>
+ # sub { $optsmenu->popup (undef, undef, undef, undef, ?, ?) } );
+ $bbox->insert ($boptions, $i++);
+ $boptions->set_menu ($optsmenu);
+
+ return $bbox;
+}
+
+# Try running the external "gnome-screenshot" program, if it's
+# available, else take a screenshot using gdk routines.
+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');