#!/usr/bin/perl

# Script:   xdvdshrink.pl
# Author:   Rick Saunders (ozzzy)
# email:    ozzzy1@gmail.com
# Date:     23 Apr, 2005

# xDVDShrink is a perl-Gtk2 application that acts as a front-end to
# two bash scripts. The script dvdshrink is the script that does
# all of the processing of a source DVD to convert a title into some
# intermediate form of AV files, or into a finished single-layer
# DVD. Batchrip.sh is a bash front-end to dvdshrink that allows you
# to take multiple episodes or titles from a source DVD and burn them
# to a single-layer DVD5 blank.

use strict;
use Gtk2;
use Gtk2::Gdk::Keysyms;

my $version     = "2.6.0";
my $build_date  = "Dec 11, 2006";

my $login       =  getlogin || getpwuid($<); # Userid of current user
my $homedir     = "/home/" . $login;         # Home dir of current user
my $app_dir     = "/usr/share/pixmaps";
my $false       = 0;    # A 'false'
my $true        = 1;    # A 'true'
my $srunning    = 0;    # Is the bash script running
my $spid;               # PID of the bash script (either batchrip.pl or dvdshrink)
my @xriplist;           # Holder for the custom riplist (episodes)
my $epval;              # An episode per DVD value
my $epchanged   = 0;    # Has the above changed
my $stitle_val;         # Start title value
my $etitle_val;         # End title value

# Other things we need access to
#-----------------------------------------------------

# These hold some values needed to properly auto-set
# the episode check boxes (I'm lazy).
my $xml_state;
my $dvd_clicked   = 0;
my $dvd_state;
my $burn_clicked  = 0;
my $burn_state;
my $aburn_clicked = 0;
my $eiso_clicked  = 0;

# Single widgets we need
my $pname_entry;        # The single 'project name' entry box
my $tname_entry;        # The single 'title number' entry box
my $aname_entry;        # The single 'audio selection' entry box
my $sname_entry;        # The single 'subtitle selection' entry box
my $kfactor_adjustment; # The single 'shrink factor' slider
my $abcheck;            # The single 'auto-burn checkbox
my $fbcheck;            # The single 'force-burn' checkbox
my $rmcheck;            # The single 'remove files' checkbox
my $aucheck;            # The single 'author DVD' checkbox
my $shcheck;            # The single 'shrink to DVD5' checkbox
my $sicheck;            # The single 'ISO only' checkbox
my $stcheck;            # The single 'streams only' checkbox
my $STcheck;            # The single 'big streams only' checkbox
my $smcheck;            # The single 'MPEG2 only' checkbox
my $SMcheck;            # The single 'big MPEG2 only' checkbox
my $p1button;           # The single 'set name' button
my $a1button;           # The single 'select audio stream' button
my $s1button;           # The single 'select title' button
my $u1button;           # The single 'select sub stream' button
my $ibutton;            # The single 'show title information' button
my $rsbutton;           # The single 'restart' button
my $siso_save_check;    # the single 'save ISO with burn' button
my $sdeletelog_check;   # Delete logs

# Episode widgets we need
my $audiostream_box;    # The episode 'audio selection' entry box
my $xml_check;          # The episode 'build xml files' checkbox
my $burn_check;         # The episode 'burn dvd' checkbox
my $dvd_check;          # The episode 'author dvd' checkbox
my $aburn_check;        # The episode 'force burn' checkbox 
my $eiso_check;         # The episode 'ISO only' checkbox
my $showname_box;       # The episode 'show/project name' entry box
my $subtitlestream_box; # The episode 'subtitle selection' entry box
my $starttitle_box;     # The episode 'start title' entry box
my $endtitle_box;       # The episode 'end title' entry box
my $riplist_box;        # The episode 'custom riplist' entry box
my $episode_box;        # The episode 'episodes per DVD' entry box
my $kfactor_adjust2;    # The value of the episode 'shrink factor' slider   
my $t2button;           # The episode 'set name' button
my $s2button;           # The episode 'select start title' button
my $a2button;           # The episode 'select audio stream' button
my $u2button;           # The episode 'select sub stream' button
my $e2button;           # The episode 'set end title' button
my $r2button;           # The episode 'select custom titles' button
my $eiso_save_check;    # The episode 'save ISO with burn' button
my $edeletelog_check;   # Delete logs
my $erm_check;
my $menu_check;
my $e_restart_button;
   
# Config window checkboxes
my $auto_remove_check;  # The auto delete checkbox
my $multi_drive_check;  # The multidrive checkbox
my $auto_burn_check;    # The auto burn checkbox

# Config window text entry boxes
my $spname_entry;       # Project name entry box
my $bdname_entry;       # Base directory entry box
my $wdname_entry;       # Write device entry box
my $rdname_entry;       # Read device entry box
my $terminal_entry;     # The console to use
my $idname_entry;       # The ISO directory entry box

# Secondary windows
my $restart_window;     # The restart selection window
my $config_window;      # The configuration window
my $tselect_window;     # The title selection window
my $aselect_window;     # The audio stream selection window
my $sselect_window;     # The subtitle stream selection window
my $ppro_window;        # The post-processing window

# Other variables
my $junk;               # A placeholder
my $morejunk;           # another one
my $about_time;         # The timer for the about window
my $ltag;               # The label for the title info 
my $lval;               # The value for the title info 

# This hash holds the main configuration items
#-----------------------------------------------------
my %config = (
   SCOMMAND       => "dvdshrink",
   WDEVICE        => "/dev/dvd",
   RDEVICE        => "/dev/dvd",
   MULTIDRIVE     => 0,
   SPEED          => 1,
   BASEDIR        => "/tmp",
   RMFILES        => 0,
   AUTOBURN       => 0,
   TERMINAL       => "none",
   DELETELOGS     => 0 );

&readconfig;

# Create an identical hash called 'cdefault' to hold
# some values during configuration
#-----------------------------------------------------
my %cdefault;      
while ( my ($key, $value) = each(%config) ) {
   $cdefault{ $key } = $value;
}

# This hash holds some things we need over and over
# while we're maniplating checkboxes
#-----------------------------------------------------
my %single_values = (
   AUTOBURN       => $config{ 'AUTOBURN' },
   FORCEBURN      => 0,
   RMFILES        => $config{ 'RMFILES' },
   AUTHOR_ONLY    => 0,
   STREAM_ONLY    => 0,
   BSTREAM_ONLY   => 0,
   MPEG_ONLY      => 0,
   BMPEG_ONLY     => 0,
   DELETELOGS     => 0,
   ISO_ONLY       => 0,
   SAVEISO        => 0,
   SHRINK         => 1 );

my %episode_values = (
   MAKEXML        => 0,
   AUTOBURN       => $config{ 'AUTOBURN' },
   FORCEBURN      => 0,
   ISO_ONLY       => 0,
   SAVEISO        => 0,
   AUTHOR_ONLY    => 0,
   RMFILES        => $config{ 'RMFILES' },
   DELETELOGS     => 0,
   MAKEMENU       => 1 );

Gtk2->init;

&ShowSplash;

if ( ! -f "$homedir/.dvdshrinkrc" ) { &config; }

# Accelerator keys
#-----------------------------------------------------
my @accels = (
	{ key => 'S', mod => 'control-mask', func => \&buildcmdline },
	{ key => 'C', mod => 'control-mask', func => \&config },
	{ key => 'E', mod => 'control-mask', func => \&restart },
	{ key => 'X', mod => 'control-mask', func => sub{ Gtk2->main_quit(); } },
);

my $accel_group = Gtk2::AccelGroup->new;
foreach my $a (@accels) {
	$accel_group->connect ($Gtk2::Gdk::Keysyms{$a->{key}}, $a->{mod}, 'visible', $a->{func});
}

# Some font/colour descriptions
#-----------------------------------------------------
my $banner_font     = Gtk2::Pango::FontDescription->from_string( 'Helvetica Bold 14' );
my $item_font       = Gtk2::Pango::FontDescription->from_string( 'Helvetica Bold 10' );
my $section_font    = Gtk2::Pango::FontDescription->from_string( 'Helvetica Bold 12' );
my $color_red       = Gtk2::Gdk::Color->parse( 'red' );
my $color_blue      = Gtk2::Gdk::Color->parse( 'blue' );
my $color_green     = Gtk2::Gdk::Color->new( 32000, 45000, 0 );
my $color_lblue     = Gtk2::Gdk::Color->new( 0, 30000, 65535 );

# Put the main program window on the screen
#-----------------------------------------------------
my $window = Gtk2::Window->new( 'toplevel' );
$window->add_accel_group ($accel_group);
$window->set_default_size( 650, 100 );
$window->signal_connect( 'delete_event' => sub { Gtk2->main_quit(); } );
$window->set_title( "xDVDShrink $version" );

my $main_vbox = Gtk2::VBox->new( $false, 0 );
$window->add( $main_vbox );
$main_vbox->show();

# Create some menus

my $menu             = Gtk2::Menu->new();
my $help_menu        = Gtk2::Menu->new();

# Add some menu items for 'file'

my $start_menu_item  = Gtk2::MenuItem->new( "_Start Rip" );
my $kbash_menu_item  = Gtk2::MenuItem->new( "_Kill BASH Session" );
my $config_menu_item = Gtk2::MenuItem->new( "_Configure" );
my $exit_menu        = Gtk2::MenuItem->new( "E_xit" );

# Add some menu items for 'help'

my $ehelp_menu_item  = Gtk2::MenuItem->new( "_Single Title Help" );
my $shelp_menu_item  = Gtk2::MenuItem->new( "_Episode Title Help" );
my $about_menu       = Gtk2::MenuItem->new( "_About DVDShrink" );

# Place the menu items

$menu->append( $start_menu_item );
$menu->append( $kbash_menu_item );
$kbash_menu_item->set_sensitive( $false );
$menu->append( $config_menu_item );
$menu->append( $exit_menu );
$help_menu->append( $ehelp_menu_item );
$help_menu->append( $shelp_menu_item );
$help_menu->append( $about_menu );

# Connect some signals

$start_menu_item->signal_connect( 'activate' => \&buildcmdline, $start_menu_item );
$kbash_menu_item->signal_connect( 'activate' => \&KillBash, $kbash_menu_item );
$config_menu_item->signal_connect( 'activate' => \&config, $config_menu_item );
$exit_menu->signal_connect( 'activate' => sub { Gtk2->main_quit(); }, $exit_menu );
$ehelp_menu_item->signal_connect( 'activate' => sub{ &Help(0); }, $ehelp_menu_item );
$shelp_menu_item->signal_connect( 'activate' => sub{ &Help(1); }, $shelp_menu_item );
$about_menu->signal_connect( 'activate'=> \&about, $about_menu );

# Show the menu items

$start_menu_item->show();
$kbash_menu_item->show();
$config_menu_item->show();
$exit_menu->show();
$ehelp_menu_item->show();
$shelp_menu_item->show();
$about_menu->show();

# Put them all together

my $session_menu = Gtk2::MenuItem->new( "_File" );
$session_menu->show();
$session_menu->set_submenu( $menu );

my $mhelp_menu   = Gtk2::MenuItem->new( "_Help" );
$mhelp_menu->show();
$mhelp_menu->set_submenu( $help_menu );

my $menubar      = Gtk2::MenuBar->new();
$main_vbox->pack_start( $menubar, $false, $false, 0 );
$menubar->show();

$menubar->append( $session_menu );
$menubar->append( $mhelp_menu );

# Add the notebook (tabbed display)

my $notebook     = Gtk2::Notebook->new();
$notebook->set_tab_border( 5 );
   
$main_vbox->pack_start( $notebook, $false, $false, 5 );
$notebook->show();

# Add the 'single title' mode notebook page

my $s_main_vbox = Gtk2::VBox->new( $false, 0 );
&SingleTitle;
my $page1_label  = Gtk2::Label->new( "Single Title" );
$page1_label->show();

$notebook->append_page( $s_main_vbox, $page1_label );
$notebook->set_size_request( 690, 450 );
$s_main_vbox->show();

# Add the 'episode' mode notebook page

my $e_main_vbox = Gtk2::VBox->new( $false, 0 );
&EpisodePage;
my $page2_label  = Gtk2::Label->new( "Multiple Episodes" );
$page2_label->show();
$notebook->append_page( $e_main_vbox, $page2_label );
$e_main_vbox->show();

# The bottom button bar

my $main_buttonbar = Gtk2::Table->new( 3, 2, 0 );
$main_vbox->pack_end( $main_buttonbar, $false, $false, 0 );
$main_buttonbar->show();

# The 'start copy' button

my $rbutton = Gtk2::Button->new();
my $runlabel = Gtk2::Label->new( "Start copy" );
$runlabel->modify_font( $banner_font );
$runlabel->modify_fg( 'normal', $color_green );
$runlabel->show();
$rbutton->add( $runlabel );
$main_buttonbar->attach_defaults( $rbutton, 0, 4, 0, 1 );
$rbutton->signal_connect( 'clicked' => \&buildcmdline, $rbutton );
$rbutton->show();

# The 'configure' button   
         
my $cbutton = Gtk2::Button->new();
$main_buttonbar->attach_defaults( $cbutton, 0, 1, 1, 2 );
$cbutton->signal_connect( 'clicked' => \&config, $cbutton );
my $cb_label = Gtk2::Label->new( "Configure" );
$cb_label->modify_font( $item_font );
$cb_label->modify_fg( 'normal', $color_lblue );
$cbutton->add( $cb_label );
$cb_label->show();
$cbutton->show();

# The 'kill bash' button. Fails the bash script with
# a signal 9

my $kbbutton = Gtk2::Button->new();
my $kill_label = Gtk2::Label->new( "Kill Bash Session" );
$kill_label->modify_font( $item_font );
$kill_label->modify_fg( 'normal', $color_red );
$kbbutton->add( $kill_label );
$kbbutton->signal_connect( 'clicked' => \&KillBash, $kbbutton );
$kbbutton->modify_fg( 'normal', $color_red );
$kill_label->show();
$main_buttonbar->attach_defaults( $kbbutton, 1, 2, 1, 2 );
$kbbutton->set_sensitive( $false );
$kbbutton->show();   

# The 'exit' button. You an issue this while the bash stuff
# is running to 'dismiss' the GUI if you want.

my $quitbutton = Gtk2::Button->new();
my $quitlabel = Gtk2::Label->new_with_mnemonic( "E_xit Program" );
$quitlabel->modify_font( $item_font );
$quitlabel->modify_fg( 'normal', $color_red );
$quitbutton->add( $quitlabel );
$quitlabel->show();
$main_buttonbar->attach_defaults( $quitbutton, 2, 3, 1, 2 );
$quitbutton->signal_connect( 'clicked' => sub { Gtk2->main_quit(); }, $quitbutton );
$quitbutton->show();


$window->show();
Gtk2->main();
exit(0);

# Build the on-screen display for the 'episode' page
#-----------------------------------------------------
sub EpisodePage {

   my $episode_main_hbox = Gtk2::HBox->new( $false, 20 );
   $e_main_vbox->pack_start( $episode_main_hbox, $false, $false, 0 );
   $episode_main_hbox->show();
   
   my $episode_l_vbox = Gtk2::VBox->new( $false, 0 );
   $episode_l_vbox->set_size_request( 400, 400 );
   $episode_main_hbox->pack_start( $episode_l_vbox, $false, $false, 0 );
   $episode_l_vbox->show();
   
   my $episode_r_vbox = Gtk2::VBox->new( $false, 0 );
   $episode_main_hbox->pack_start( $episode_r_vbox, $false, $false, 0 );
   $episode_r_vbox->show();

   my $top_label = Gtk2::Label->new( "Multi-episode (TV show) selection options" );
   $top_label->modify_font( $banner_font );
   $top_label->modify_fg( 'normal', $color_blue );
   $top_label->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $top_label, $false, $false, 5 );
   $top_label->show();

# The TV Show name or project name

   my $showname_label = Gtk2::Label->new( "Set a TV show or project name" );
   $showname_label->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $showname_label, $true, $true, 0 );
   $showname_label->show();
   
   my $p_hbox = Gtk2::HBox->new( $false, 0 );
   $episode_l_vbox->pack_start( $p_hbox, $false, $false, 0 );
   $p_hbox->show();

   $showname_box = Gtk2::Entry->new;
   $showname_box->set_text("");
   $p_hbox->pack_start( $showname_box, $true, $true, 20 );
   $showname_box->show();

   $t2button = Gtk2::Button->new( "  Set from DVD  " );
   $t2button->set_size_request( 150, 30 );
   $t2button->signal_connect( "clicked" => sub {
      $showname_box->set_text( qx/dd if=$config{ 'RDEVICE' } bs=1 skip=32808 count=32 2> \/dev\/null/ );
   }, $t2button );
   $p_hbox->pack_start( $t2button, $false, $false, 0 );
   $t2button->show();

# The audio stream selection   
         
   my $audiostream_label = Gtk2::Label->new( "Set default audio stream" );
   $audiostream_label->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $audiostream_label, $true, $true, 0 );
   $audiostream_label->show();   

   my $a_hbox = Gtk2::HBox->new( $false, 0 );
   $episode_l_vbox->pack_start( $a_hbox, $false, $false, 0 );
   $a_hbox->show();

   $audiostream_box = Gtk2::Entry->new;
   $audiostream_box->set_text( "0" );
   $audiostream_box->signal_connect( 'changed' => sub {
      if ( ( $audiostream_box->get_text() =~ /\D/ ) &&
           ( $audiostream_box->get_text() ne "" ) )
      {
         $audiostream_box->set_text( "0" );
      }
   }, $audiostream_box );
   $a_hbox->pack_start( $audiostream_box, $true, $true, 20 );
   $audiostream_box->show();

   $a2button = Gtk2::Button->new( "Select from DVD" );
   $a2button->set_size_request( 150, 30 );
   $a2button->signal_connect( 'clicked' => sub{ &showaudiolist(1); }, $a2button );
   $a_hbox->pack_start( $a2button, $false, $false, 0 );
   $a2button->show();   

# The subtitle stream selection   
         
   my $subtitlestream_label = Gtk2::Label->new( "Set default subtitle stream (optional)" );
   $subtitlestream_label->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $subtitlestream_label, $false, $false, 0 );
   $subtitlestream_label->show();

   my $u_hbox = Gtk2::HBox->new( $false, 0 );
   $episode_l_vbox->pack_start( $u_hbox, $false, $false, 0 );
   $u_hbox->show();

   $subtitlestream_box = Gtk2::Entry->new;
   $u_hbox->pack_start( $subtitlestream_box, $true, $true, 20 );
   $subtitlestream_box->signal_connect( 'changed' => sub {
      if ( ( $subtitlestream_box->get_text() ne "" ) &&
           ( $subtitlestream_box->get_text() !~ /disabled/i ) ) {
         if ( $subtitlestream_box->get_text() =~ /\D/ ) {
            $subtitlestream_box->set_text( "" );
         }
      }
   }, $subtitlestream_box );      
   $subtitlestream_box->show();

   $u2button = Gtk2::Button->new( "Select from DVD" );
   $u2button->set_size_request( 150, 30 );
   $u2button->signal_connect( 'clicked' => sub{ &showsublist(1); }, $u2button );
   $u_hbox->pack_start( $u2button, $false, $false, 0 );
   $u2button->show();   

# Test for valid 'subtitle2pgm'. Disable the 'select' etc if the version
# of 'subtitle2pgm' doesn't handle exist, or have the -X switch

   my $subgood = 0;
   qx/which subtitle2pgm > \/dev\/null 2>&1/;
   if ( ! $? ) {
      if ( qx/subtitle2pgm -h 2>&1/ =~ /-X/ ) {
         $subgood++;
      }
   }
   if ( $subgood == 0 ) {
      $subtitlestream_box->set_text( "Disabled" );
      $subtitlestream_box->set_editable( $false );
      $u2button->set_sensitive( $false );
   }

# The first title to rip. Setting this will adjust the end title if needed
# and the number of episodes per DVD. 

   my $starttitle_label = Gtk2::Label->new( "Set the first title to rip" );
   $starttitle_label->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $starttitle_label, $true, $true, 0 );
   $starttitle_label->show();
   
   my $s_hbox = Gtk2::HBox->new( $false, 0 );
   $episode_l_vbox->pack_start( $s_hbox, $false, $false, 0 );
   $s_hbox->show();

   $stitle_val = 1;
   $starttitle_box = Gtk2::Entry->new;
   $starttitle_box->set_size_request( 125, 25 );
   $starttitle_box->set_text( $stitle_val );
   $starttitle_box->signal_connect( 'changed' => \&TestStartTitle, $starttitle_box );
   
   $s_hbox->pack_start( $starttitle_box, $true, $true, 20 );
   $starttitle_box->show();

   $s2button = Gtk2::Button->new( "Select from DVD" );
   $s2button->set_size_request( 150, 30 );
   $s2button->signal_connect( 'clicked' => sub{ &ShowAllTitles( 1 ); }, $s2button );
   $s_hbox->pack_start( $s2button, $false, $false, 0 );
   $s2button->show();   

# The last title to rip. As above this will adjust other things within
# reason

   my $endtitle_label = Gtk2::Label->new( "Set the last title to rip" );
   $endtitle_label->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $endtitle_label, $true, $true, 0 );
   $endtitle_label->show();

   my $e_hbox = Gtk2::HBox->new( $false, 0 );
   $episode_l_vbox->pack_start( $e_hbox, $false, $false, 0 );
   $e_hbox->show();

   $etitle_val = 8;
   $endtitle_box = Gtk2::Entry->new;
   $endtitle_box->set_text( "8" );
   $endtitle_box->signal_connect( 'changed' => \&TestEndTitle, $endtitle_box );
   $e_hbox->pack_start( $endtitle_box, $true, $true, 20 );
   $endtitle_box->show();
   
   $e2button = Gtk2::Button->new( "Select from DVD" );
   $e2button->set_size_request( 150, 30 );
   $e2button->signal_connect( 'clicked' => sub{ ShowAllTitles( 2 ); }, $e2button );
   $e_hbox->pack_start( $e2button, $false, $false, 0 );
   $e2button->show();   

# Specify a custom rip list. This will 'disable' the start and end title
# selection and adjust the number of episodes per DVD

   my $riplist_label = Gtk2::Label->new( "Specify a custom title list (optional)" );
   $riplist_label->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $riplist_label, $true, $true, 0 );
   $riplist_label->show();

   my $r_hbox = Gtk2::HBox->new( $false, 0 );
   $episode_l_vbox->pack_start( $r_hbox, $false, $false, 0 );
   $r_hbox->show();

   $riplist_box = Gtk2::Entry->new;
   $riplist_box->signal_connect( 'changed' => \&toggle_titles, $riplist_box );
   $r_hbox->pack_start( $riplist_box, $true, $true, 20 );
   $riplist_box->show();

   $r2button = Gtk2::Button->new( "Select from DVD" );
   $r2button->set_size_request( 150, 30 );
   $r2button->signal_connect( 'clicked' => sub{ &ShowAllTitles( 3 ); }, $r2button );
   $r_hbox->pack_start( $r2button, $false, $false, 0 );
   $r2button->show();   

# The number of episodes per DVD. While this is adjusted by some of the
# above entries, you can set it to what you want once the titles to rip
# have been selected.

   my $episodes_label = Gtk2::Label->new( "Set the number of titles per each new DVD" );
   $episodes_label->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $episodes_label, $true, $true, 0 );
   $episodes_label->show();

   my $o_hbox = Gtk2::HBox->new( $false, 0 );
   $episode_l_vbox->pack_start( $o_hbox, $false, $false, 0 );
   $o_hbox->show();

   $episode_box = Gtk2::Entry->new;
   $episode_box->set_text( "3" );
   $episode_box->set_size_request( 50, 25 );
   $o_hbox->pack_start( $episode_box, $false, $false, 20 );
   $episode_box->show();

# The 'set shrink factor' slider. As this package was built to shrink
# a dvd (or set) to fit DVD5 let the scripts do their job.

   my $klabel2 = Gtk2::Label->new( "Select a custom shrink factor (optional)" );
   $klabel2->set_alignment( 0, 0 );
   $episode_l_vbox->pack_start( $klabel2, $false, $false, 0 );
   $klabel2->show();

   $kfactor_adjust2 = new Gtk2::Adjustment( 1, 1, 2.1, .01, .1, .1 );
   $kfactor_adjust2->set_value( 1 );

   my $kf_slider2=new Gtk2::HScale( $kfactor_adjustment );
   $episode_l_vbox->pack_start( $kf_slider2, $false, $false, 0 );
   $kf_slider2->show();   
         
# The check boxes on the right side  

   my $sel_label = Gtk2::Label->new( "Session options" );
   $sel_label->modify_font( $banner_font );
   $sel_label->modify_fg( 'normal', $color_blue );
   $sel_label->set_alignment( 0, 0 );
   $episode_r_vbox->pack_start( $sel_label, $false, $false, 5 );
   $sel_label->show();

# The 'build xml' checkbox   
         
   $xml_check = Gtk2::CheckButton->new_with_mnemonic( "Build X_ML file(s)" );
   $xml_check->set_active( $episode_values{ 'MAKEXML' } );
   $xml_check->signal_connect( 'clicked' => sub {
      $episode_values{ 'MAKEXML' } = $xml_check->get_active() ? $true : $false;
   }, $xml_check );
   $episode_r_vbox->pack_start( $xml_check, $false, $false, 0 );
   $xml_check->show();

# The 'author' checkbox. This will automatically set the 'build xml'
# check box if selected

   $dvd_check = Gtk2::CheckButton->new_with_mnemonic( "_Author DVD(s)" );
   $dvd_check->set_active( $episode_values{ 'MAKEDVD' } );
   $dvd_check->signal_connect( 'clicked' => sub {
      $episode_values{ 'MAKEDVD' } = $dvd_check->get_active() ? $true : $false;
      if ( $dvd_clicked % 2 == 0 ) {
         $xml_state = $xml_check->get_active() ? $true : $false;
      }
      if ( $dvd_check->get_active() ) {
         $xml_check->set_active( $true ); 
      } else {
         $xml_check->set_active( $xml_state );
      }
      $dvd_clicked++;
   }, $dvd_check );
   $episode_r_vbox->pack_start( $dvd_check, $false, $false, 0 );
   $dvd_check->show();

# The 'burn dvd' checkbox. If selected it will set the 'build xml' and
# 'author' checkboxes.

   $burn_check = Gtk2::CheckButton->new_with_mnemonic( "_Burn DVD(s)" );
   $burn_check->set_active( $episode_values{ 'AUTOBURN' } );
   $burn_check->signal_connect( 'clicked' => sub {
      $episode_values{ 'AUTOBURN' } = $burn_check->get_active() ? $true : $false;
      if ( $burn_clicked % 2 == 0 ) {
         $dvd_state = $dvd_check->get_active() ? $true : $false;
      }
      if ( $burn_check->get_active() ) {
         $eiso_save_check->set_sensitive( $true );
         $eiso_check->set_sensitive( $false );
         $dvd_check->set_active( $true );
      } else {
         $eiso_save_check->set_sensitive( $false );
         $eiso_check->set_sensitive( $true );
         $dvd_check->set_active( $dvd_state );
      }
      $burn_clicked++;
   }, $burn_check );   
   $episode_r_vbox->pack_start( $burn_check, $false, $false, 0 );
   $burn_check->show();

# The 'force burn' (no prompts) checkbox. Works as the 'burn' checkbox

   $aburn_check = Gtk2::CheckButton->new_with_mnemonic ( "_Force-burn (no prompt)" );
   if ( $config{ 'MULTIDRIVE' } ) {
      $aburn_check->set_active( $episode_values{ 'FORCEBURN' } );
   } else {
      $aburn_check->set_active( $false );
      $aburn_check->set_sensitive( $false );
   }
   $aburn_check->signal_connect( 'clicked' => sub {
      $episode_values{ 'FORCEBURN' } = $aburn_check->get_active() ? $true : $false;
      if ( $aburn_clicked %2 == 0 ) {
         $burn_state = $burn_check->get_active() ? $true : $false;
      }
      if ( $aburn_check->get_active() ) {
         $eiso_save_check->set_sensitive( $true );
         $eiso_check->set_sensitive( $false );
         $burn_check->set_active( $true );
      } else {
         $eiso_save_check->set_sensitive( $false );
         $eiso_check->set_sensitive( $true );
         $burn_check->set_active( $burn_state );
      }
      $aburn_clicked++;
   }, $aburn_check );
   $episode_r_vbox->pack_start( $aburn_check, $false, $false, 0 );
   $aburn_check->show();

# The 'iso only' checkbox. This will disable the burn boxes if
# set.

   $eiso_check = Gtk2::CheckButton->new_with_mnemonic( "_ISO only" );
   $eiso_check->set_active( $episode_values{ 'ISO_ONLY' } );
   $eiso_check->signal_connect( 'clicked' => sub { 
      $episode_values{ 'ISO_ONLY' } = $eiso_check->get_active() ? $true : $false;
      if ( $eiso_clicked % 2 == 0 ) {
         $dvd_state = $dvd_check->get_active() ? $true : $false;
      }
      if ( $eiso_check->get_active() ) {
         $burn_check->set_sensitive( $false );
         $aburn_check->set_sensitive( $false );
         $dvd_check->set_active( $true );
      } else {
         $aburn_check->set_sensitive( $true );
         $burn_check->set_sensitive( $true );
         $dvd_check->set_active( $dvd_state );
      }
      $eiso_clicked++;
   }, $eiso_check ); 
   $episode_r_vbox->pack_start( $eiso_check, $false, $false, 0 );
   $eiso_check->show();   

# The 'save ISO with burn' button

   $eiso_save_check = Gtk2::CheckButton->new_with_mnemonic( "Save ISO with bur_n" );
   $eiso_save_check->set_active( $episode_values{ 'SAVEISO' } );
   $eiso_save_check->signal_connect( 'clicked' => sub {
      $episode_values{ 'SAVEISO' } = $eiso_save_check->get_active() ? $true : $false;
   }, $eiso_save_check );
   $eiso_save_check->set_sensitive( $false );
   $episode_r_vbox->pack_start( $eiso_save_check, $false, $false, 0 );
   $eiso_save_check->show();      

# The 'remove working files' button.

   $erm_check = Gtk2::CheckButton->new_with_mnemonic( "_Remove working files" );
   $erm_check->set_active( $episode_values{ 'RMFILES' } );
   $erm_check->signal_connect( 'clicked' => sub { 
      $episode_values{ 'RMFILES' } = $erm_check->get_active() ? $true : $false;
   }, $erm_check );

   $episode_r_vbox->pack_start( $erm_check, $false, $false, 0 );
   $erm_check->show();


# The 'delete logs' checkbox. This passes the -L switch to 'batchrip.sh'
# which in turn passes the -l switch to 'dvdshrink' <sigh>   
         
   $edeletelog_check = Gtk2::CheckButton->new_with_mnemonic( "_Delete logs" );
   $edeletelog_check->set_active( $episode_values{ 'DELETELOGS' } );
   $edeletelog_check->signal_connect( 'clicked' => sub { 
      $episode_values{ 'DELETELOGS' } = $edeletelog_check->get_active() ? $true : $false;
   }, $edeletelog_check );

   $episode_r_vbox->pack_start( $edeletelog_check, $false, $false, 0 );
   $edeletelog_check->show();

# The 'create dvd menu' checkbox (on by default );

   $menu_check = Gtk2::CheckButton->new_with_mnemonic( "Create DVD M_enu" );
   $menu_check->set_active( $episode_values{ 'MAKEMENU' } );
   $menu_check->signal_connect( 'clicked' => sub { 
      $episode_values{ 'MAKEMENU' } = $menu_check->get_active() ? $true : $false;
   }, $menu_check );
   $episode_r_vbox->pack_start( $menu_check, $false, $false, 0 );
   $menu_check->show();
   
   my $rbuttonbar = Gtk2::HButtonBox->new();
   $rbuttonbar->set_layout_default( 'end' );
   $e_main_vbox->pack_end( $rbuttonbar, $false, $false, 10 );
   $rbuttonbar->show();

   
# The 'restart' button. This, unlike the 'movie' mode restart will try
# to re-rip any missed titles. It turns off the xml, authoring and 
# burning stuff... ISO too. When the failed rips are re-done completely
# all that stuff will be done.   
         
   $e_restart_button = Gtk2::Button->new( "   Restart   " );
   $e_restart_button->signal_connect( 'clicked' => \&restart, $e_restart_button );
   $rbuttonbar->pack_start( $e_restart_button, $false, $false, 0 );
   $e_restart_button->show(); 

   my $e_post_button = Gtk2::Button->new( " Post Process  " );
   $e_post_button->signal_connect( 'clicked' => \&postprocess, $e_post_button );
   $rbuttonbar->pack_start( $e_post_button, $false, $false, 0 );
   $e_post_button->show();   
}

# Manipulate the start and end title values and the episodes per dvd value

sub TestStartTitle {
   my $stext = $starttitle_box->get_text();
   my $etext = $endtitle_box->get_text();
   if ( $stext ne "Custom" ) {
      if ( ( $stext =~ /\D/ ) &&
           ( $stext ne "" ) ) {
         $starttitle_box->set_text( 1 );
         $episode_box->set_text( $etext - $stext );
      } else {
         if ( $etext - $stext <= 0 ) {
            $episode_box->set_text( 3 );
         } else {
            $episode_box->set_text( $etext - $stext );
         }
      }
   }
}

sub TestEndTitle {
   my $stext = $starttitle_box->get_text();
   my $etext = $endtitle_box->get_text();
   if ( $etext ne "Custom" ) {
      if ( ( $etext =~ /\D/ ) &&
           ( $etext ne "" ) ) {
         $endtitle_box->set_text( $stext + 1 );
         $episode_box->set_text( $etext - $stext );
      } else {
         if ( $etext - $stext <= 0 ) {
            $episode_box->set_text( 3 );
         } else {
            $episode_box->set_text( $etext - $stext );
         }
      }
   }
}

# Build the on-screen display for the 'single title' page
#-----------------------------------------------------
sub SingleTitle {

   my $single_main_hbox = Gtk2::HBox->new( $false, 20 );
   $s_main_vbox->pack_start( $single_main_hbox, $false, $false, 0 );
   $single_main_hbox->show();
   
   my $single_l_vbox = Gtk2::VBox->new( $false, 0 );
   $single_main_hbox->pack_start( $single_l_vbox, $false, $false, 0 );
   $single_l_vbox->set_size_request( 400, 400 );
   $single_l_vbox->show();
   
   my $single_r_vbox = Gtk2::VBox->new( $false, 0 );
   $single_main_hbox->pack_start( $single_r_vbox, $false, $false, 0 );
   $single_r_vbox->show();
   
   
   my $top_label = Gtk2::Label->new( "Single title (movie) selection options" );
   $top_label->modify_font( $banner_font );
   $top_label->modify_fg( 'normal', $color_blue );
   $top_label->set_alignment( 0, 0 );
   $single_l_vbox->pack_start( $top_label, $false, $false, 5 );
   $top_label->show();

# The movie or project name

   my $plabel = new Gtk2::Label->new( "Enter a name for the project (optional)" );
   $plabel->set_alignment( 0, 0 );
   $single_l_vbox->pack_start( $plabel, $false, $false, 0 );
   $plabel->show();

   my $p_hbox = Gtk2::HBox->new( $false, 0 );
   $single_l_vbox->pack_start( $p_hbox, $false, $false, 0 );
   $p_hbox->show();

   $pname_entry = Gtk2::Entry->new;
   $pname_entry->set_text( "" );
   $p_hbox->pack_start( $pname_entry, $true, $true, 20 );
   $pname_entry->show();

   $p1button = Gtk2::Button->new( "Set from DVD" );
   $p1button->set_size_request( 150, 30 );
   $p1button->signal_connect( 'clicked' => sub {
      $pname_entry->set_text( qx/dd if=$config{ 'RDEVICE' } bs=1 skip=32808 count=32 2> \/dev\/null/ );
   }, $p1button );
   $p_hbox->pack_start( $p1button, $false, $false, 0 );
   $p1button->show();

# The title to rip. Can't be set to an invalid entry other than
# a title that doesn't exist. Use the 'select from dvd' button
# to get a valid title.

   my $tlabel = Gtk2::Label->new( "Enter the DVD title to rip" );
   $tlabel->set_alignment( 0, 0 );
   $single_l_vbox->pack_start( $tlabel, $false, $false, 0 );
   $tlabel->show();

   my $t_hbox = Gtk2::HBox->new( $false, 0 );
   $single_l_vbox->pack_start( $t_hbox, $false, $false, 0 );
   $t_hbox->show();

   $tname_entry = Gtk2::Entry->new;
   $tname_entry->set_text( "1" );
   $tname_entry->signal_connect( 'changed' => sub {
      if ( ( $tname_entry->get_text() =~ /\D/ ) &&
           ( $tname_entry->get_text() ne "" ) ) {
         $tname_entry->set_text( "1" );
      }
   }, $tname_entry );
   $t_hbox->pack_start( $tname_entry, $true, $true, 20 );
   $tname_entry->show();

   $s1button = Gtk2::Button->new( "  Select from DVD  " );
   $s1button->set_size_request( 150, 30 );
   $s1button->signal_connect( "clicked" => sub{ &ShowAllTitles( 0 ); }, $s1button );
   $t_hbox->pack_start( $s1button, $false, $false, 0 );
   $s1button->show();

# The audio stream to rip. Again, can't be set to an invalid
# entry other than a stream that doesn't exist. Use the 'select from DVD'
# button to set a valid stream.

   my $alabel = Gtk2::Label->new( "Enter the audio channel to rip" );
   $alabel->set_alignment( 0, 0 );
   $single_l_vbox->pack_start( $alabel, $false, $false, 0 );
   $alabel->show();

   my $a_hbox = Gtk2::HBox->new( $false, 0 );
   $single_l_vbox->pack_start( $a_hbox, $false, $false, 0 );
   $a_hbox->show();

   $aname_entry = Gtk2::Entry->new;
   $aname_entry->set_text( "0" );
   $aname_entry->signal_connect( 'changed' => sub {
      if ( ( $aname_entry->get_text() =~ /\D/ ) &&
           ( $aname_entry->get_text() ne "" ) )
      {
         $aname_entry->set_text( "0" );
      }
   }, $aname_entry );   
   $a_hbox->pack_start( $aname_entry, $true, $true, 20 );
   $aname_entry->show();

   $a1button = Gtk2::Button->new( "Select from DVD" );
   $a1button->set_size_request( 150, 30 );
   $a1button->signal_connect( 'clicked' => sub{ &showaudiolist(0); }, $a1button );
   $a_hbox->pack_start( $a1button, $false, $false, 0 );
   $a1button->show();

# The subtitle selection. If your version of 'subtitle2pgm' isn't valid for
# the package, then this is disabled and you're told. You can set it to a
# stream that doesn't exist so use the 'select from DVD' button.

   my $slabel = Gtk2::Label->new( "Enter the subtitle channel to rip (optional)" );
   $slabel->set_alignment( 0, 0 );
   $single_l_vbox->pack_start( $slabel, $false, $false, 0 );
   $slabel->show();

   my $s_hbox = Gtk2::HBox->new( $false, 0 );
   $single_l_vbox->pack_start( $s_hbox, $false, $false, 0 );
   $s_hbox->show();

   $sname_entry = Gtk2::Entry->new;
   $sname_entry->set_text( "" );
   $sname_entry->signal_connect( 'changed' => sub {
      if ( ( $sname_entry->get_text() ne "" ) &&
           ( $sname_entry->get_text() !~ /disabled/i ) ) {
         if ( $sname_entry->get_text() =~ /\D/ ) {
            $sname_entry->set_text( "" );
         }
      }
   }, $sname_entry );   
   $s_hbox->pack_start( $sname_entry, $true, $true, 20 );
   $sname_entry->show();

   $u1button = Gtk2::Button->new( "Select from DVD" );
   $u1button->set_size_request( 150, 30 );
   $u1button->signal_connect( 'clicked' => sub{ &showsublist(0); }, $u1button );
   $s_hbox->pack_start( $u1button, $false, $false, 0 );
   $u1button->show();

   # Test for valid 'subtitle2pgm'. As in the 'episodes' function

   if ( qx/subtitle2pgm -h 2>&1/ !~ /-X/ ) {
      $sname_entry->set_text( "Disabled" );
      $sname_entry->set_editable( $false );
      $u1button->set_sensitive( $false );
   }

   my $sel_label = Gtk2::Label->new( "Session options" );
   $sel_label->modify_font( $banner_font );
   $sel_label->modify_fg( 'normal', $color_blue );
   $sel_label->set_alignment( 0, 0 );
   $single_r_vbox->pack_start( $sel_label, $false, $false, 5 );
   $sel_label->show();

# The shrink factor slider. Rather useless unless a specific application
# is in mind.

   my $klabel = Gtk2::Label->new( "Select a custom shrink factor (optional)" );
   $klabel->set_alignment( 0, 0 );
   $single_l_vbox->pack_start( $klabel, $false, $false, 0 );
   $klabel->show();

   $kfactor_adjustment = new Gtk2::Adjustment( 1, 1, 2.1, .01, .1, .1 );
   $kfactor_adjustment->set_value( 1 );

   my $kf_slider=new Gtk2::HScale( $kfactor_adjustment );
   $single_l_vbox->pack_start( $kf_slider, $false, $false, 0 );
   $kf_slider->show();

# The checkbox widgets

   $siso_save_check = Gtk2::CheckButton->new_with_mnemonic( "Save ISO with bur_n" );
   $rmcheck = Gtk2::CheckButton->new_with_mnemonic( "_Remove working files" );   
   $aucheck = Gtk2::CheckButton->new_with_mnemonic( "_Author DVD on drive only" );   
   $shcheck = Gtk2::CheckButton->new_with_mnemonic( "Shrin_k selected title to fit DVD5" );  
   $sicheck = Gtk2::CheckButton->new_with_mnemonic( "Create _ISO file only" ); 
   $stcheck = Gtk2::CheckButton->new_with_mnemonic( "Rip s_elected streams only" );
   $STcheck = Gtk2::CheckButton->new_with_mnemonic( "Rip selected _unshrunk streams only" );
   $smcheck = Gtk2::CheckButton->new_with_mnemonic( "Create _MPEG file only" );
   $SMcheck = Gtk2::CheckButton->new_with_mnemonic( "Create unshrunk M_PEG file only" );   

# The auto-burn checkbox. All of the checkboxes will disable other boxes
# that may confuse the issue.

   $abcheck = Gtk2::CheckButton->new_with_mnemonic( "Autoburn new _DVD" );
   $abcheck->signal_connect( "clicked" => sub { 
      $single_values{ 'AUTOBURN' } = $abcheck->get_active() ? $true : $false;
      &BurnButtonChk( $abcheck, 1 );
   }, $abcheck );
   $single_r_vbox->pack_start( $abcheck, $false, $false, 0 );
   $abcheck->set_active( $config{ 'AUTOBURN' } );
   $abcheck->show();

# The force burn box (no prompt)

   $fbcheck = Gtk2::CheckButton->new_with_mnemonic( "_Force DVD burn (no-prompt)" );
   if ( $config{ 'MULTIDRIVE' } ) {
      $fbcheck->set_active( $single_values{ 'FORCEBURN' } );
   } else {
      $fbcheck->set_active( $false );
      $fbcheck->set_sensitive( $false );
   }
   $fbcheck->signal_connect( "clicked" => sub { 
      $single_values{ 'FORCEBURN' } = $fbcheck->get_active() ? $true : $false;
      &BurnButtonChk( $fbcheck, 2 ); 
   }, $fbcheck );
   $single_r_vbox->pack_start( $fbcheck, $false, $false, 0 );
   $fbcheck->show();

# The 'save ISO with burn' button

   $siso_save_check->set_active( $single_values{ 'SAVEISO' } );
   $siso_save_check->signal_connect( 'clicked' => sub {
      $single_values{ 'SAVEISO' } = $siso_save_check->get_active() ? $true : $false;
   }, $siso_save_check );
   $siso_save_check->set_sensitive( $false );
   $single_r_vbox->pack_start( $siso_save_check, $false, $false, 0 );
   $siso_save_check->show(); 

# The 'remove working files' checkbox. Dangerous if you want to keep any
# of the files.

   $rmcheck->signal_connect( 'clicked' => sub {
      $single_values{ 'RMFILES' } = $rmcheck->get_active() ? $true : $false;
   }, $rmcheck );
   $single_r_vbox->pack_start( $rmcheck, $false, $false, 0 );
   $rmcheck->set_active( $config{ 'RMFILES' } );
   $rmcheck->show();

# The 'author only' checkbox

   $aucheck->signal_connect( "clicked" => sub { 
      $single_values{ 'AUTHOR_ONLY' } = $aucheck->get_active() ? $true : $false;
      &ButtonChk( $aucheck, 1 );
   }, $aucheck );
   $single_r_vbox->pack_start( $aucheck, $false, $false, 0 );
   $aucheck->set_active( $single_values{ 'AUTHOR_ONLY' } );
   $aucheck->show();

# The 'shrink' checkbox. You can turn this off, but why. Shrinking is the whole
# reason for this package.

   $shcheck->signal_connect( 'clicked' => sub {
      $single_values{ 'SHRINK' } = $shcheck->get_active() ? $true : $false;
   }, $shcheck );
   $single_r_vbox->pack_start( $shcheck, $false, $false, 0 );
   $shcheck->set_active( $single_values{ 'SHRINK' } );
   $shcheck->show();

# The 'create iso only' checkbox

   $sicheck->signal_connect( "clicked" => sub { 
      $single_values{ 'ISO_ONLY' } = $sicheck->get_active() ? $true : $false;
      &ButtonChk( $sicheck, 2 ); 
   }, $sicheck );
   $single_r_vbox->pack_start( $sicheck, $false, $false, 0 );
   $sicheck->set_active( $single_values{ 'ISO_ONLY' } );
   $sicheck->show();

# The 'rip selected streams only' checkbox. This will leave you with a set of
# video, audio and subtitle streams, with the video shrunkf or DVD5.

   $stcheck->signal_connect( "clicked" => sub { 
      $single_values{ 'STREAM_ONLY' } = $stcheck->get_active() ? $true : $false;
      &ButtonChk( $stcheck, 3 ); 
   }, $stcheck );
   $single_r_vbox->pack_start( $stcheck, $false, $false, 0 );
   $stcheck->set_active( $single_values{ 'STREAM_ONLY' } );
   $stcheck->show();

# As above, but no shrink.

   $STcheck->signal_connect( "clicked" => sub { 
      $single_values{ 'BSTREAM_ONLY' } = $STcheck->get_active() ? $true : $false;
      &ButtonChk( $STcheck, 4 );
   }, $STcheck );
   $single_r_vbox->pack_start( $STcheck, $false, $false, 0 );
   $STcheck->set_active( $single_values{ 'BSTREAM_ONLY' } );
   $STcheck->show();

# The 'create mpeg2 only' checkbox. This will leave you with an MPEG file that is
# sized to fit a DVD5
   
   $smcheck->signal_connect( "clicked" => sub { 
      $single_values{ 'MPEG_ONLY' } = $smcheck->get_active() ? $true : $false;
      &ButtonChk( $smcheck, 5 );
   }, $smcheck );
   $single_r_vbox->pack_start( $smcheck, $false, $false, 0 );
   $smcheck->set_active( $single_values{ 'MPEG_ONLY' } );
   $smcheck->show();

# The 'create unshrunk mpeg2' checkbox. As above but no shrinking done

   $SMcheck->signal_connect( "clicked" => sub { 
      $single_values{ 'BMPEG_ONLY' } = $SMcheck->get_active() ? $true : $false;
      &ButtonChk( $SMcheck, 6 );
   }, $SMcheck );
   $single_r_vbox->pack_start( $SMcheck, $false, $false, 0 );
   $SMcheck->set_active( $single_values{ 'BMPEG_ONLY' } );
   $SMcheck->show();

# The delete logs checkbox. Passes the -l option to 'dvdshrink'.

   $sdeletelog_check = Gtk2::CheckButton->new_with_mnemonic( "Delete _logs" );
   $sdeletelog_check->signal_connect( 'clicked' => sub {
      $single_values{ 'DELETELOGS' } = $sdeletelog_check->get_active() ? $true : $false;
   }, $sdeletelog_check );
   $sdeletelog_check->set_active( $single_values{ 'DELETELOGS' } );
   $single_r_vbox->pack_start( $sdeletelog_check, $false, $false, 0 );
   $sdeletelog_check->show();

# The 'mid' button bar

   my $mbutton_bar     = Gtk2::HButtonBox->new();
   $mbutton_bar->set_layout( 'end' );
   $s_main_vbox->pack_end( $mbutton_bar, $false, $false, 10 );
   $mbutton_bar->show();

# The title information button will open a window showing you some
# statistics on the title in the 'select title' entry box

   $ibutton = Gtk2::Button->new( "Title Information" );
   $ibutton->signal_connect( 'clicked' => \&showtinfo, $ibutton );
   $mbutton_bar->pack_start( $ibutton, $false, $false, 0 );
   $ibutton->show();

# Restart 'dvdshrink' after an error

   $rsbutton = Gtk2::Button->new( "Restart" );
   $rsbutton->signal_connect( "clicked" => \&restart, $rsbutton );
   $mbutton_bar->pack_start( $rsbutton, $false, $false, 0 );
   $rsbutton->show();
   
}

# The configuration window
#-----------------------------------------------------
sub config {
   while ( my ($key, $value) = each(%config) ) {
      $cdefault{ $key } = $value;
   }
   $config_window = Gtk2::Window->new( "toplevel" );
   $config_window->set_default_size( 400, 270 );
   $config_window->set_position( 'center' );
   $config_window->set_title( "DVDShrink Configuration" );
   my $rsignal   = $config_window->signal_connect( 'delete_event' => sub { $config_window->destroy(); } );   

   my $calignment = Gtk2::Alignment->new( .5, .5, .9, .9 );
   $config_window->add( $calignment );
   $calignment->show();
   
   my $c_vbox = Gtk2::VBox->new( $false, 0 );
   $calignment->add( $c_vbox );
   $c_vbox->show();

# Configure the read device

   my $rd_hbox = Gtk2::HBox->new( $false, 0 );
   $c_vbox->pack_start( $rd_hbox, $false, $false, 5 );
   $rd_hbox->show();

   $rdname_entry = Gtk2::Entry->new;
   $rdname_entry->set_text( "$config{ 'RDEVICE' }" );
   $rdname_entry->signal_connect( 'changed' => \&SetMulti, $rdname_entry );
   $rdname_entry->set_size_request( 150, 25 );
   $rd_hbox->pack_end( $rdname_entry, $false, $false, 10 );
   $rdname_entry->show();
                  
   my $rdlabel = new Gtk2::Label->new( "Enter the reader device" );
   $rdlabel->set_alignment( 0, .5 );
   $rd_hbox->pack_end( $rdlabel, $true, $true, 0 );
   $rdlabel->show();

# Configure the write device. If they're the same then the
# MULTIDRIVE value is unset
   
   my $wd_hbox = Gtk2::HBox->new( $false, 0 );
   $c_vbox->pack_start( $wd_hbox, $false, $false, 5 );
   $wd_hbox->show();

   $wdname_entry = Gtk2::Entry->new;
   $wdname_entry->set_size_request( 150, 25 );
   $wdname_entry->set_text( "$config{ 'WDEVICE' }" );
   $wdname_entry->signal_connect( 'changed' => \&SetMulti, $wdname_entry ); 
   $wd_hbox->pack_end( $wdname_entry, $false, $false, 10 );
   $wdname_entry->show();
         
   my $wdlabel = new Gtk2::Label->new( "Enter the writer device" );
   $wdlabel->set_alignment( 0, .5 );
   $wd_hbox->pack_end( $wdlabel, $true, $true, 0 );
   $wdlabel->show();

# Configure the 'base directory' value
         
   my $bd_hbox = Gtk2::HBox->new( $false, 0 );
   $c_vbox->pack_start( $bd_hbox, $false, $false, 5 );
   $bd_hbox->show();   
   
   $bdname_entry = Gtk2::Entry->new;
   $bdname_entry->set_size_request( 150, 25 );
   $bdname_entry->set_text( "$config{ 'BASEDIR' }" );
   $bd_hbox->pack_end( $bdname_entry, $false, $false, 10 );
   $bdname_entry->show();
      
   my $bdlabel = new Gtk2::Label->new( "Enter the base working directory" );
   $bdlabel->set_alignment( 0, .5 );
   $bd_hbox->pack_end( $bdlabel, $true, $true, 0 );
   $bdlabel->show();

# Configure the 'iso storage' directory

   my $id_hbox = Gtk2::HBox->new( $false, 0 );
   $c_vbox->pack_start( $id_hbox, $false, $false, 5 );
   $id_hbox->show();   

   $idname_entry = Gtk2::Entry->new;
   $idname_entry->set_size_request( 150, 25 );
   $idname_entry->set_text( "$config{ 'ISODIR' }" );
   $id_hbox->pack_end( $idname_entry, $false, $false, 10 );
   $idname_entry->show();
      
   my $idlabel = new Gtk2::Label->new( "Enter the ISO directory" );
   $idlabel->set_alignment( 0, .5 );
   $id_hbox->pack_end( $idlabel, $true, $true, 0 );
   $idlabel->show();


# Configure the terminal app to use   
         
   my $terminal_hbox = Gtk2::HBox->new( $false, 0 );
   $c_vbox->pack_start( $terminal_hbox, $false, $false, 5 );
   $terminal_hbox->show();
   
   my @terminals = ( "x-terminal-emulator", "konsole", "gnome-terminal", "eterm", "xterm", "rxvt" );
   $terminal_entry = Gtk2::Combo->new();
   $terminal_entry->set_size_request( 150, 25 );
   $terminal_entry->set_popdown_strings( @terminals );
   $terminal_entry->entry->set_text( $config{ 'TERMINAL' } );
   $terminal_hbox->pack_end( $terminal_entry, $false, $false, 10 );
   $terminal_entry->show();
   
   my $terminal_label = Gtk2::Label->new( "Enter the console to use" );
   $terminal_label->set_alignment( 0, .5 );
   $terminal_hbox->pack_end( $terminal_label, $true, $true, 0 );
   $terminal_label->show();
   
   my $speed_hbox = Gtk2::HBox->new( $false, 0 );
   $c_vbox->pack_start( $speed_hbox, $false, $false, 5 );
   $speed_hbox->show();

# Configure the burn speed

   my @speeds = ( "1", "2", "4", "8", "16" );
   $spname_entry = Gtk2::Combo->new();
   $spname_entry->set_size_request( 100, 25 );
   $spname_entry->set_popdown_strings( @speeds );
   $spname_entry->entry->set_text( $config{ 'SPEED' } );
   $speed_hbox->pack_end( $spname_entry, $false, $false, 10 );
   $spname_entry->show();
         
   my $splabel = Gtk2::Label->new( "Enter the burn speed" );
   $splabel->set_alignment( 0, .5 );
   $speed_hbox->pack_end( $splabel, $true, $true, 0 );
   $splabel->show();

   my $tseparator = new Gtk2::HSeparator();
   $c_vbox->pack_start( $tseparator, $false, $false, 3 );
   $tseparator->show();

# The 'multidrive' checkbox. This will be adjusted as per the values
# of the read and write devices.   
         
   $multi_drive_check = Gtk2::CheckButton->new_with_label( "Seperate reader and burner devices on machine." );
   $c_vbox->pack_start( $multi_drive_check, $false, $false, 0 );
   $multi_drive_check->set_active( $config{ 'MULTIDRIVE' } );
   $multi_drive_check->show();

# The 'auto burn' checkbox

   $auto_burn_check = Gtk2::CheckButton->new_with_label( "Auto-burn new DVD after authoring." );
   $c_vbox->pack_start( $auto_burn_check, $false, $false, 0 );
   $auto_burn_check->set_active( $config{ 'AUTOBURN' } );
   $auto_burn_check->show();

# The 'delete files' checkbox

   $auto_remove_check = Gtk2::CheckButton->new_with_label( "Delete working files as needed to save drive space." );
   $c_vbox->pack_start( $auto_remove_check, $false, $false, 0 );
   $auto_remove_check->set_active( $config{ 'RMFILES' } );
   $auto_remove_check->show();

   my $separator = new Gtk2::HSeparator();
   $c_vbox->pack_start( $separator, $false, $false, 3 );
   $separator->show();

# The buttons... they're pretty much self-explanatory

   my $chbuttonbox = Gtk2::HButtonBox->new();
   $chbuttonbox->set_layout( "end" );
   $c_vbox->add( $chbuttonbox );
   $chbuttonbox->show();

   my $wbutton = Gtk2::Button->new( "Save" );
   $wbutton->signal_connect( "clicked" => \&writeconf, $wbutton );
   $chbuttonbox->pack_start( $wbutton, $true, $true, 0 );
   $wbutton->show();
   my $default_tip = Gtk2::Tooltips->new();
   $default_tip->set_tip( $wbutton, "Write these values as defaults" );
   
   my $ccbutton = Gtk2::Button->new( "Cancel" );
   $ccbutton->signal_connect( 'clicked' => sub { 
      while ( my ($key, $value) = each(%cdefault) ) {
         $config{ $key } = $value;
      }
      $config_window->destroy(); 
   }, $ccbutton );
   $chbuttonbox->pack_start( $ccbutton, $true, $true, 0 );
   $ccbutton->show();
   my $ccancel_tip = Gtk2::Tooltips->new();
   $ccancel_tip->set_tip( $ccbutton, "Don't change values" );
   
   $config_window->show();
}

# Set the 'multi drive' check button as per the values of
# the read and write devices.
#-----------------------------------------------------
sub SetMulti{
   if ( $rdname_entry->get_text() eq $wdname_entry->get_text() ) {
      $config{ 'MULTIDRIVE' } = 0;
      $aburn_check->set_sensitive( $false );
      $fbcheck->set_sensitive( $false );
   } else {
      $config{ 'MULTIDRIVE' } = 1;
      $aburn_check->set_sensitive( $true );
      $fbcheck->set_sensitive( $true );
   }
   $multi_drive_check->set_active( $config{ 'MULTIDRIVE' } );
}

# Write the configuration as set above to the rc file
#-----------------------------------------------------
sub writeconf {
   $config{ 'RDEVICE' }  = $rdname_entry->get_text();
   $config{ 'WDEVICE' }  = $wdname_entry->get_text();
   $config{ 'BASEDIR' }  = $bdname_entry->get_text();
   $config{ 'ISODIR' }   = $idname_entry->get_text();
   $config{ 'SPEED' }    = $spname_entry->entry->get_text();
   $config{ 'TERMINAL' } = $terminal_entry->entry->get_text();

   if ( $multi_drive_check->get_active() == $true ) {
      $config{ 'MULTIDRIVE' } = 1;
   } else {
      $config{ 'MULTIDRIVE' } = 0;
   }
   if ( $auto_burn_check->get_active() == $true ) {
      $config{ 'AUTOBURN' }   = 1;
   } else {
      $config{ 'AUTOBURN' }   = 0;
   }
   if ( $auto_remove_check->get_active() == $true ) {
      $config{ 'RMFILES' }    = 1;
   } else {
      $config{ 'RMFILES' }    = 0;
   }

   open( CONF, "> $homedir/.dvdshrinkrc" );
   print CONF "RDEVICE="    . $config{ 'RDEVICE' }    . "\n";
   print CONF "WDEVICE="    . $config{ 'WDEVICE' }    . "\n";
   print CONF "BASEDIR="    . $config{ 'BASEDIR' }    . "\n";
   print CONF "ISODIR="     . $config{ 'ISODIR' }     . "\n";
   print CONF "SPEED="      . $config{ 'SPEED' }      . "\n";
   print CONF "MULTIDRIVE=" . $config{ 'MULTIDRIVE' } . "\n";
   print CONF "AUTOBURN="   . $config{ 'AUTOBURN' }   . "\n";
   print CONF "RMFILES="    . $config{ 'RMFILES' }    . "\n";
   print CONF "TERMINAL="   . $config{ 'TERMINAL' }   . "\n";
   close CONF;

   $config_window->destroy();
}

# Shows a small dialog box just to ensure that we REALLY do want to
# stop the DVD rip. If you select 'kill' it sends the bash script
# running a -9 signal.
#-----------------------------------------------------
sub KillBash {
   my $kill_dialog = Gtk2::Dialog->new;
   my $kill_text = Gtk2::Label->new( "      Warning!       " );
   $kill_text->modify_font( $banner_font );
   $kill_text->modify_fg( 'normal', $color_red );
   $kill_dialog->vbox->pack_start( $kill_text, $false, $false, 0 );
   my $exp_string = "Do you really want to kill the script?";
   my $kill_explain = Gtk2::Label->new( $exp_string );
   $kill_dialog->vbox->pack_start( $kill_explain, $false, $false, 0 );
   my $kill_close_button = Gtk2::Button->new( "Cancel" );
   $kill_close_button->signal_connect( 'clicked' => sub { 
      $kill_dialog->destroy(); 
   }, $kill_close_button );
   $kill_dialog->action_area->pack_start( $kill_close_button, $false, $false, 0 );
   my $kill_button = Gtk2::Button->new( "Kill" );
   $kill_button->signal_connect( 'clicked' => sub {
      $kill_dialog->destroy();
      kill 9, $spid;
   }, $kill_button );
   $kill_dialog->action_area->pack_start( $kill_button, $false, $false, 0 );
   $kill_text->show();
   $kill_explain->show();
   $kill_close_button->show();
   $kill_button->show();
   $kill_dialog->show();   
} 

sub postprocess {
   $config{ 'SCOMMAND' } = "batchrip.sh --postprocess";
   &startrip;
}

# If there has been an error handle the 'restart' sequence
#-----------------------------------------------------
sub restart {
   if ( $notebook->get_current_page() == 0 ) {
      $restart_window = Gtk2::Window->new( "toplevel" );
      $restart_window->set_default_size( 440, 100 );
      $restart_window->set_position( 'center' );
      $restart_window->set_title( "DVDShrink Restart after error" );
      my $rssignal   = $restart_window->signal_connect( 'delete_event' => sub { $restart_window->destroy(); } );   

      my $rsalignment = Gtk2::Alignment->new( .5, .5, .9, .9 );
      $restart_window->add( $rsalignment );
      $rsalignment->show();

      my $rs_vbox = Gtk2::VBox->new( $false, 0 );
      $rsalignment->add( $rs_vbox );
      $rs_vbox->show();
   
      my $rslabel = Gtk2::Label->new( "Movie (single title) mode" );
      $rslabel->modify_fg( 'normal', $color_red );
      $rslabel->set_alignment( 0, 0 );
      my $tslabel1 = Gtk2::Label->new( "Select 'Last CMD' if you have fixed the reported problem or,\nselect 'Next CMD' if you feel the reported problem was false!" );
      $rs_vbox->pack_start( $rslabel, $false, $false, 3 );
      $rs_vbox->pack_start( $tslabel1, $false, $false, 0 );
      $rslabel->show();
      $tslabel1->show();

      my $rshbuttonbox = Gtk2::HButtonBox->new();
      $rshbuttonbox->set_layout( "end" );
      $rs_vbox->add( $rshbuttonbox );
      $rshbuttonbox->show();

# In 'movie' mode. The restart is a lot smarter than in 'episode' mode. In
# movie mode you have a choice of:
#   1) Trying the failed function again and continuing, or
#   2) assuming the function DID complete enough to carry on and do so   

# Last function is 'try again'
         
      my $bsbutton = Gtk2::Button->new( "Last Func" );
      $bsbutton->signal_connect( "clicked" => sub{ &restartit(0); }, $bsbutton );
      $rshbuttonbox->pack_start( $bsbutton, $true, $true, 0 );
      $bsbutton->show();
      my $last_tip = Gtk2::Tooltips->new();
      $last_tip->set_tip( $bsbutton, "Restart with function that failed" );

# Next function is 'carry on'

      my $bjbutton = Gtk2::Button->new( "Next Func" );
      $bjbutton->signal_connect( "clicked" => sub{ &restartit(1); }, $bjbutton );
      $rshbuttonbox->pack_start( $bjbutton, $true, $true, 0 );
      $bjbutton->show();
      my $next_tip = Gtk2::Tooltips->new();
      $next_tip->set_tip( $bjbutton, "Restart with next function" );

      my $bcbutton = Gtk2::Button->new( "Cancel" );
      $bcbutton->signal_connect( 'clicked' => sub {  $restart_window->destroy(); } );
      $rshbuttonbox->pack_start( $bcbutton, $true, $true, 0 );
      $bcbutton->show();
      my $rc_tip = Gtk2::Tooltips->new();
      $rc_tip->set_tip( $bcbutton, "Don't restart" );

      $restart_window->show();
   }
   
# In 'episode' mode the program will disable all of the xml, authoring, burning
# etc and if 'restart' is selected it will try to redo the failed titles from
# scratch. Of course, you have to fix the problem first.
      
   else {
      $restart_window = Gtk2::Window->new( "toplevel" );
      $restart_window->set_default_size( 440, 100 );
      $restart_window->set_position( 'center' );
      $restart_window->set_title( "BatchRip restart after error" );
      my $rssignal   = $restart_window->signal_connect( 'delete_event' => sub { $restart_window->destroy(); } );   

      my $rsalignment = Gtk2::Alignment->new( .5, .5, .9, .9 );
      $restart_window->add( $rsalignment );
      $rsalignment->show();

      my $rs_vbox = Gtk2::VBox->new( $false, 0 );
      $rsalignment->add( $rs_vbox );
      $rs_vbox->show();
   
      my $rslabel = Gtk2::Label->new( "TV Show (episode) mode" );
      $rslabel->modify_fg( 'normal', $color_red );
      $rslabel->set_alignment( 0, 0 );
      my $tslabel1 = Gtk2::Label->new( "Select 'Re-start' if you have fixed the reported problem(s)" );
      $rs_vbox->pack_start( $rslabel, $false, $false, 3 );
      $rs_vbox->pack_start( $tslabel1, $false, $false, 0 );
      $rslabel->show();
      $tslabel1->show();

      my $rshbuttonbox = Gtk2::HButtonBox->new();
      $rshbuttonbox->set_layout( "end" );
      $rs_vbox->add( $rshbuttonbox );
      $rshbuttonbox->show();
   
      my $bjbutton = Gtk2::Button->new( "Re-start" );
      $bjbutton->signal_connect( "clicked" => \&SetAfterFail, $bjbutton );
      $rshbuttonbox->pack_start( $bjbutton, $true, $true, 0 );
      $bjbutton->show();
      my $next_tip = Gtk2::Tooltips->new();
      $next_tip->set_tip( $bjbutton, "Restart with next function" );

      my $bcbutton = Gtk2::Button->new( "Cancel" );
      $bcbutton->signal_connect( 'clicked' => sub {  $restart_window->destroy(); } );
      $rshbuttonbox->pack_start( $bcbutton, $true, $true, 0 );
      $bcbutton->show();
      my $rc_tip = Gtk2::Tooltips->new();
      $rc_tip->set_tip( $bcbutton, "Don't restart" );

      $restart_window->show();   
   }
}

# Pass the 'restart' command
#-----------------------------------------------------
sub restartit {
   $config{ 'SCOMMAND' } = "dvdshrink";
   my $mode = shift;
   if ( $mode == 0 ) {
      $config{ 'SCOMMAND' } .= " -P --restart";
   } else {
      $config{ 'SCOMMAND' } .= " -P --jumpin";
   }
   &startrip;
   $restart_window->destroy();
}

# Show some information about the title listed in the title entry box
#-----------------------------------------------------
sub showtinfo {
   my $iscrolled_window;
   my $info_text;
   my $title = $tname_entry->get_text();
   my $label;
   my @temparray;
   my $line;
   my $iwindow = Gtk2::Window->new( 'toplevel' );
   $iwindow->set_default_size( 300, 320 );
   $iwindow->set_position( "none" );
   $iwindow->set_title( "DVD Title Information" );
   my $signal = $iwindow->signal_connect( 'delete_event' => sub { Gtk2->main_quit(); } );

   my $info_align = Gtk2::Alignment->new( .5, .5, .8, .8 );
   $iwindow->add( $info_align );
   $info_align->show();
   
   my $info_vbox = Gtk2::VBox->new ( $false, 0 );
   $info_align->add( $info_vbox );

   my $listsbox = Gtk2::HBox->new( $true, 0 );
   $info_vbox->pack_start( $listsbox, $false, $false, 0 );

   my $lvbox = Gtk2::VBox->new;
   $listsbox->pack_start( $lvbox, $false, $false, 0 );
   my $rvbox = Gtk2::VBox->new;
   $listsbox->pack_start( $rvbox, $false, $false, 0 );
   $listsbox->show();
   $lvbox->show();
   $rvbox->show();
   
   my @items = ( "Title Number",
                 "Chapters",
                 "Playing time",
                 "Total frames",
                 "Frame size",
                 "Aspect ratio",
                 "Frame rate",
                 "Audio streams",
                 "Subtitle streams" );
                 
   my $lnum = 0;              
   foreach my $item ( @items ) {
      my $llabel = Gtk2::Label->new( $item );
      $llabel->set_alignment( .1, 0 );
      $llabel->modify_font( $section_font );
      $llabel->modify_fg( 'normal', $color_blue );
      $lvbox->pack_start( $llabel, $false, $false, 0);
      $llabel->show();
   }
   
   my $button_box = Gtk2::HButtonBox->new;
   $info_vbox->add( $button_box );
   
   my $allinfobutton = Gtk2::Button->new( "Show all title info" );
   $allinfobutton->signal_connect( 'clicked' => \&ShowAllInfo, $allinfobutton );
   $button_box->pack_start( $allinfobutton, $true, $true, 0 );
   $allinfobutton->show();
   
   my $close_button = Gtk2::Button->new( "Close" );
   $close_button->signal_connect( 'clicked' => sub { $iwindow->destroy(); } );
   $button_box->pack_start( $close_button, $true, $true, 0 );
   $close_button->show();
   $button_box->show();
   $info_vbox->show();
   $iwindow->show();
   
   my @infoarray = qx/tcprobe -i $config{ 'RDEVICE' } -T $title -H 200 2>&1/;

   $label = Gtk2::Label->new( $title );
   $label->modify_font( $section_font );
   $rvbox->pack_start( $label, $false, $false, 0 );
   $label->show();
   
   foreach $line ( @infoarray ) {
      if ( $line =~ /DVD title/ ) {
         @temparray = split( / /, $line );
         $label = Gtk2::Label->new ( $temparray[4] );
         $label->modify_font( $section_font );
         $rvbox->pack_start( $label, $false, $false, 0 );
         $label->show();
      }
   }
   foreach $line ( @infoarray ) {
      if ( $line =~ /playback time/ ) {
         @temparray = split( / /, $line );
         $label = Gtk2::Label->new ( $temparray[4] );
         $label->modify_font( $section_font );         
         $rvbox->pack_start( $label, $false, $false, 0 );
         $label->show();
      }
   }
   foreach $line ( @infoarray ) {
      if ( $line =~ /\] V:/ ) {
         @temparray = split( / /, $line );
         $label = Gtk2::Label->new ( $temparray[2] );
         $label->modify_font( $section_font );        
         $rvbox->pack_start( $label, $false, $false, 0 );
         $label->show();
      }
   }
   foreach $line ( @infoarray ) {      
      if ( $line =~ /import frame size/ ) {
         @temparray = split( / /, $line );
         $label = Gtk2::Label->new ( $temparray[4] );
         $label->modify_font( $section_font );
         $rvbox->pack_start( $label, $false, $false, 0 );
         $label->show();
      }
   }   
   foreach $line ( @infoarray ) {
      if ( $line =~ /aspect ratio/ ) {
         $line =~ s/^ +//;
         @temparray = split( / /, $line );
         $label = Gtk2::Label->new ( $temparray[$#temparray - 1] );
         $label->modify_font( $section_font );         
         $rvbox->pack_start( $label, $false, $false, 0 );
         $label->show();
      }
   }
   foreach $line ( @infoarray ) {
      if ( $line =~ /frame rate/ ) {
         $line =~ s/^ +//;
         @temparray = split( / /, $line );
         $label = Gtk2::Label->new ( $temparray[3] );
         $label->modify_font( $section_font );         
         $rvbox->pack_start( $label, $false, $false, 0 );
         $label->show();
      }
   }
   
   my $atracks = 0;
   foreach $line ( @infoarray ) {
      if ( $line =~ / drc / ) {
         $atracks++;
      }
   }
   $label = Gtk2::Label->new( $atracks);
   $label->modify_font( $section_font );   
   $rvbox->pack_start( $label, $false, $false, 0 );
   $label->show();
   
   my $stracks = 0;
   foreach $line ( @infoarray ) {
      if ( $line =~ / subtitle / ) {
         $stracks++;
      }
   }
   $label = Gtk2::Label->new( $stracks );
   $rvbox->pack_start( $label, $false, $false, 0 );
   $label->modify_font( $section_font );   
   $label->show();
}

# Read the DVDShrink config file
#-----------------------------------------------------
sub readconfig {
   if ( -f "$homedir/.dvdshrinkrc" ) {
      open( C_DATA, "$homedir/.dvdshrinkrc" );
      my @c_data = <C_DATA>;
      close C_DATA;
      foreach my $line ( @c_data ) {
         chomp $line;
         my ( $key, $val ) = split( /=/, $line );
         $config{ $key } = $val;
      }
   }
}

# Show the audio stream selection window
#-----------------------------------------------------
sub showaudiolist {
   my $mode = shift;
   $aselect_window = new Gtk2::Window( 'toplevel' );
   $aselect_window->set_position( 'center' );
   $aselect_window->signal_connect( 'delete_event' => sub { $aselect_window->destroy(); } );
   my $ttl = $tname_entry->get_text();
   $aselect_window->set_title( "Audio streams in title $ttl" );
   $aselect_window->set_default_size( 500, 250 );
   $aselect_window->show();
  
   my $m_vbox = Gtk2::VBox->new( $false, 0 );
   $aselect_window->add( $m_vbox );
   $m_vbox->show();
   
   my $ascrolled_window = new Gtk2::ScrolledWindow( undef, undef );
   $ascrolled_window->set_policy( "automatic", "always" );
   $m_vbox->add( $ascrolled_window );
   $ascrolled_window->show();

   my $atest_vbox = Gtk2::VBox->new( $false, 0 );
   $ascrolled_window->add_with_viewport( $atest_vbox );
   $atest_vbox->show();

   my $abuttonbox = Gtk2::HButtonBox->new();
   $abuttonbox->set_layout( 'end' );
   $m_vbox->pack_end( $abuttonbox, $false, $false, 0 );
   $abuttonbox->show();

   my $acbutton = new Gtk2::Button( "Close" );
   $acbutton->signal_connect( "clicked" => sub{ $aselect_window->destroy(); } );
   $abuttonbox->pack_start( $acbutton, $false, $false, 0 );
   $acbutton->show();
   
   my $atitle = $tname_entry->get_text();
   my @ainfo = qx/tcprobe -i $config{ 'RDEVICE' } -T $atitle -H 200 2>&1/;
   my @alist = ();
   foreach my $line ( @ainfo ) {
      chomp $line;
      if ( $line =~ /drc/ ) {
         my ( $junk, $audiostream ) = split( /\)/, $line );
         push( @alist, $audiostream );
      }
   }
   
   for my $a ( 0..$#alist ) {
      my $audiostring = sprintf( "Stream %d - %s", $a, $alist[$a] );
      my $buffer = "$audiostring";
      my $button = Gtk2::Button->new( $buffer );
      if ( $audiostring =~ /dts/ ) {
         $button->set_sensitive( $false );
      }
      $button->signal_connect( "clicked" => sub{ \&getanum( $a, $mode ); } );
      $atest_vbox->pack_start( $button, $false, $false, 0 );
      $button->show();
   }
} 

# Set the selected audio stream number
#-----------------------------------------------------
sub getanum {
   my $anum = shift;
   my $mode = shift;
   if ( $mode == 0 ) {
      $aname_entry->set_text( $anum );
   } else {
      $audiostream_box->set_text( $anum );
   }
   $aselect_window->destroy();
}

# Build the command-line arguments that we're going to pass
# to the 'dvdshrink' bash script.
#-----------------------------------------------------
sub buildcmdline {
   &savevalues;
   if ( $srunning == 0 ) {
      if ( $notebook->get_current_page() == 0 ) {
         $config{ 'SCOMMAND' } = "dvdshrink ";
         $config{ 'SCOMMAND' } .= $single_values{ 'AUTOBURN' }     ? "-b " : "-B ";
         $config{ 'SCOMMAND' } .= $single_values{ 'FORCEBURN' }    ? "-F " : "";
         $config{ 'SCOMMAND' } .= $single_values{ 'SAVEISO' }      ? "-O " : "";
         if ( ( $config{ 'SCOMMAND' } =~ /-b/ ) && ( $config{ 'SCOMMAND' } =~ /-F/ ) ) {
            $config{ 'SCOMMAND' } =~ s/-b //i;
         }
         $config{ 'SCOMMAND' } .= $single_values{ 'RMFILES' }      ? "-d " : "-D ";
         $config{ 'SCOMMAND' } .= $single_values{ 'AUTHOR_ONLY' }  ? "-A " : "";
         $config{ 'SCOMMAND' } .= $single_values{ 'STREAM_ONLY' }  ? "-s " : "";
         $config{ 'SCOMMAND' } .= $single_values{ 'BSTREAM_ONLY' } ? "-S " : "";
         if ( ( $config{ 'SCOMMAND' } =~ /-s/ ) && ( $config{ 'SCOMMAND' } =~ /-S/ ) ) {
            $config{ 'SCOMMAND' } =~ s/-s //;
         }
         $config{ 'SCOMMAND' } .= $single_values{ 'SHRINK' }       ? "" : "-K ";
         $config{ 'SCOMMAND' } .= $single_values{ 'DELETELOGS' }   ? "-l " : "";
         $config{ 'SCOMMAND' } .= $single_values{ 'MPEG_ONLY' }    ? "-m " : "";
         $config{ 'SCOMMAND' } .= $single_values{ 'BMPEG_ONLY' }   ? "-M " : "";
         if ( ( $config{ 'SCOMMAND' } =~ /-m/ ) && ( $config{ 'SCOMMAND' } =~ /-M/ ) ) {
            $config{ 'SCOMMAND' } =~ s/-m //;
         }
         $config{ 'SCOMMAND' } .= $single_values{ 'ISO_ONLY' }     ? "-i " : "";
         if ( $pname_entry->get_text() =~ /[a-zA-Z0-9]/ ) {
            my $pname = $pname_entry->get_text();
            $pname =~ s/\s+$//;
            $config{ 'SCOMMAND' } .= "-p " . $pname . " ";
         }
         if ( $tname_entry->get_text() =~ /[0-9]/ ) {
            $config{ 'SCOMMAND' } .= "-t " . lc( $tname_entry->get_text() ) . " ";
         } else {
            $config{ 'SCOMMAND' } .= "-t 1 ";
         }
         if ( $aname_entry->get_text() =~ /[0-9]/ ){
            $config{ 'SCOMMAND' } .= "-a " . lc( $aname_entry->get_text() ) . " ";
         } else {
            $config{ 'SCOMMAND' } .= "-a 0 ";
         }   
         if ( $sname_entry->get_text() =~ /[0-9]/ ) {
            $config{ 'SCOMMAND' } .= "-u " . lc( $sname_entry->get_text() ) . " ";
         }
         my $svalue = $kfactor_adjustment->value;
         if ( $svalue > 1.0 ) {
            $config{ 'SCOMMAND' } .= "-k $svalue";
         }
         &startrip;
      } else {
         $config{ 'SCOMMAND' } = "batchrip.sh ";
         my $start;
         my $end;
         my $isgood = &checkvalues;
         if ( ! $isgood ) {
            my $riplist   = $riplist_box->get_text();
            if ( $riplist != "" ) {
               $riplist   =~ s/\s//g;
               $config{ 'SCOMMAND' }  .= "-r $riplist ";
            } else {
               $start     = $starttitle_box->get_text();
               $end       = $endtitle_box->get_text();
               $config{ 'SCOMMAND' }  .= "-s $start -l $end ";
            }
            if ( $showname_box->get_text() eq "" ) {
               $config{ 'SCOMMAND' }  .= "-n SHOW ";
            } else {
               my $sname = $showname_box->get_text();
               $sname =~ s/\s+$//g;
               $sname =~ s/\s+/_/g;
               $config{ 'SCOMMAND' }  .= "-n $sname ";
            }
            $config{ 'SCOMMAND' }     .= "-e " . $episode_box->get_text() . " ";
            my $svalue = $kfactor_adjust2->value;
            if ( $svalue > 1.0 ) {
                $config{ 'SCOMMAND' } .= " -k $svalue ";
            }
            $config{ 'SCOMMAND' }     .= "-a " . $audiostream_box->get_text() . " ";
            if ( $subtitlestream_box->get_text ne "" ) {
               $config{ 'SCOMMAND' }  .= "-u " . $subtitlestream_box->get_text() . " ";
            }
            $config{ 'SCOMMAND' } .= $episode_values{ 'DELETELOGS' }  ? "-L " : "";
            $config{ 'SCOMMAND' } .= $episode_values{ 'MAKEXML' }     ? "-x " : "";
            $config{ 'SCOMMAND' } .= $episode_values{ 'MAKEDVD' }     ? "-d " : "";
            $config{ 'SCOMMAND' } .= $episode_values{ 'AUTOBURN' }    ? "-B " : "";
            $config{ 'SCOMMAND' } .= $episode_values{ 'FORCEBURN' }   ? "-F " : "";
            $config{ 'SCOMMAND' } .= $episode_values{ 'SAVEISO' }     ? "-O " : "";
            if ( ( $config{ 'SCOMMAND' } =~ /-B/ ) && ( $config{ 'SCOMMAND' } =~ /-F/ ) ) {
               $config{ 'SCOMMAND' } =~ s/-B //;
            }
            $config{ 'SCOMMAND' } .= $episode_values{ 'ISO_ONLY' }    ? "-I " : "";
            $config{ 'SCOMMAND' } .= $episode_values{ 'RMFILES' }     ? "-R " : "-N ";
            $config{ 'SCOMMAND' } .= $episode_values{ 'MAKEMENU' }    ? "-m " : "-M ";
            &startrip;
         } else {
            &showerror( $isgood );
         }
      }
   }   
}               

# Start ripping the DVD. We'll open the script up in a terminal
# window. The front-end supports 'konsole', 'eterm' and 'xterm'
#-----------------------------------------------------
sub startrip {
   my $cmdline = $config{ 'TERMINAL' };
   if ( $cmdline =~ /none/i ) {   
      my @cmds = ("x-terminal-emulator", "konsole", "gnome-terminal", "eterm", "xterm");
      foreach my $cmd ( @cmds ) {
         system ( "which $cmd > /dev/null 2>&1" );
         if ( $? == 0 ) {
           $cmdline = $cmd;
           last
         }
      }
   }
   
   if ( $cmdline eq "konsole" ) {
      $cmdline .= " --name DVDShrink -e $config{ 'SCOMMAND' }"
   } elsif ( $cmdline eq "gnome-terminal" ) {
      $cmdline .= " -t DVDShrink -x $config{ 'SCOMMAND' }";
   } elsif ( $cmdline eq "eterm" ) {
      $cmdline .= " -T DVDShrink -e $config{ 'SCOMMAND' }"
   } elsif ( $cmdline eq "xterm") {
      $cmdline .= " -T DVDShrink -e $config{ 'SCOMMAND' } "
   } elsif ( $cmdline eq "x-terminal-emulator") {
      $cmdline .= " -T DVDShrink -e $config{ 'SCOMMAND' } "
   }

   
   if ( $notebook->get_current_page() == 0 ) {
      if ( -f "$homedir/.dvdshrink.pid" ) {
         qx/rm -f $homedir\/.dvdshrink.pid/;
      }
   } else {
      if ( -f "$homedir/.batchrip.pid" ) {
         qx/rm -f $homedir\/.batchrip.pid/;
      }
   }
   $quitbutton->set_sensitive( $false );
   $exit_menu->set_sensitive( $false );
   system( "$cmdline &" );   
   $srunning = 1;
   my $scriptrun_timer = Glib::Timeout->add( 200, \&CheckStart );
}

# Check for the pid file and if it exists then continue on
#-----------------------------------------------------
sub CheckStart {
   my $pidfile;
   if ( $notebook->get_current_page() == 0 ) {
      $pidfile = "$homedir/.dvdshrink.pid";
   } else {
      $pidfile = "$homedir/.batchrip.pid";
   }
   if ( -f $pidfile ) {      
      $spid = qx/cat $pidfile/;
      $kbash_menu_item->set_sensitive( $true );
      $config_menu_item->set_sensitive( $false );
      $start_menu_item->set_sensitive( $false );
      &toggleButtons;
      $kbbutton->set_sensitive( $true );
      my $checkrun_timer = Glib::Timeout->add( 1000, \&CheckRun );   
      return $false;
   } else {
      return $true;
   }
}

# See if the bash script is running by checking the pid
#-----------------------------------------------------
sub CheckRun {
   qx/ps $spid/;
   if ( $? == 0 ) {
      return $true;
   } else {
      $exit_menu->set_sensitive( $true );
      $quitbutton->set_sensitive( $true );
      &toggleButtons;
      $kbash_menu_item->set_sensitive( $false );
      $config_menu_item->set_sensitive( $true );
      $start_menu_item->set_sensitive( $true );
      $s_main_vbox->show();
      $e_main_vbox->show();
      $srunning = 0;
      &CheckDefaults;
      return $false;
   }
}

# Enable/disable buttons (so we don't do things we shouldn't )
# This just toggles the 'sensitivity' to either true or false
# depending on what state the button is in when called.
#-----------------------------------------------------
sub toggleButtons {
   my $kvalue = abs( $kbbutton->is_sensitive() - 1 );
   my $bvalue;
   if ( $notebook->get_current_page() == 0 ) {
      $bvalue = abs( $a1button->is_sensitive() - 1 );
      $p1button->set_sensitive( $bvalue );
      $cbutton->set_sensitive( $bvalue );
      $a1button->set_sensitive( $bvalue );
      $s1button->set_sensitive( $bvalue );
      $u1button->set_sensitive( $bvalue );
      $ibutton->set_sensitive( $bvalue );
      $rsbutton->set_sensitive( $bvalue );
      $rbutton->set_sensitive( $bvalue );
      $abcheck->set_sensitive( $bvalue );
      $fbcheck->set_sensitive( $bvalue );
      $aucheck->set_sensitive( $bvalue );
      $sicheck->set_sensitive( $bvalue );
      $stcheck->set_sensitive( $bvalue );
      $rmcheck->set_sensitive( $bvalue );
      $STcheck->set_sensitive( $bvalue );
      $smcheck->set_sensitive( $bvalue );
      $SMcheck->set_sensitive( $bvalue );
      $shcheck->set_sensitive( $bvalue );  
      $e_main_vbox->hide();
   } else {
      $bvalue = abs( $a2button->is_sensitive() -1 );
      $a2button->set_sensitive( $bvalue );
      $t2button->set_sensitive( $bvalue );
      $u2button->set_sensitive( $bvalue );
      $s2button->set_sensitive( $bvalue );
      $e2button->set_sensitive( $bvalue );
      $r2button->set_sensitive( $bvalue );
      $dvd_check->set_sensitive( $bvalue );
      $xml_check->set_sensitive( $bvalue );
      $burn_check->set_sensitive( $bvalue );
      $aburn_check->set_sensitive( $bvalue );
      $s_main_vbox->hide();
   }
   $e_restart_button->set_sensitive( $bvalue );
   $rbutton->set_sensitive( $bvalue );          
   $cbutton->set_sensitive( $bvalue );  
   $kbbutton->set_sensitive( $kvalue );  
}

# Get the total number of titles on the DVD
#-----------------------------------------------------
sub gettitlenum {
   my $junk;
   my $titles;
   my @tlist = qx/tcprobe -i $config{ 'RDEVICE' } -T 1 -H 200 2>&1/;
   foreach my $a ( 0..$#tlist ) {
      if ( $tlist[$a] =~ /DVD title/ ) {
         my @tstr = split( / /, $tlist[$a] );
         $titles = $tstr[3];
         $titles =~ s/://;
         ( $junk, $titles ) = split( /\//, $titles );
      }
   }
   return $titles;
}

# Show us a list of titles on the DVD in a button column 
# that we can select from
#-----------------------------------------------------
sub ShowAllTitles {
   my $mode = shift;
   my $runtime;
   my $frames;
   my $chapters;
  
   my $titles = &gettitlenum();

   $epval = $episode_box->get_text();
   $tselect_window = new Gtk2::Window( 'toplevel' );
   $tselect_window->set_position( 'center' );
   $tselect_window->signal_connect( 'delete_event' => sub { 
      $tselect_window->destroy();
      $episode_box->set_text( $epval );
   } );
   $tselect_window->set_title( "Titles on this DVD" );
   $tselect_window->set_default_size( 500, 250 );
   $tselect_window->show();
  
   my $m_vbox = Gtk2::VBox->new( $false, 0 );
   $tselect_window->add( $m_vbox );
   $m_vbox->show();

   my $tscrolled_window = new Gtk2::ScrolledWindow( undef, undef );
   $tscrolled_window->set_policy( "automatic", "always" );
   $m_vbox->add( $tscrolled_window );
   $tscrolled_window->show();

   my $test_vbox = Gtk2::VBox->new( $false, 0 );
   $tscrolled_window->add_with_viewport( $test_vbox );
   $test_vbox->show();
   
   my $tbuttonbox = Gtk2::HButtonBox->new();
   $tbuttonbox->set_layout( 'end' );
   $m_vbox->pack_end( $tbuttonbox, $false, $false, 0 );
   $tbuttonbox->show();
      
   my $tcbutton = new Gtk2::Button( "Close" );
   $tcbutton->signal_connect( "clicked" => sub{ $tselect_window->destroy(); } );
   $tbuttonbox->pack_start( $tcbutton, $false, $false, 0 );
   $tcbutton->show();
   
   for my $a ( 1..$titles ) {
      my @tinfo = qx/tcprobe -i $config{ 'RDEVICE' } -T $a -H 200 2>&1/;
      foreach my $line ( @tinfo ) {
         chomp $line;
         if ( $line =~ /DVD title/ ) {
            ( $junk, $chapters ) = split( /: /, $line );
            ( $chapters, $junk, $morejunk ) = split( /\,/, $chapters );
         }
         if ( $line =~ /playback time/ ) {
            ( $junk, $runtime ) = split( /e: /, $line );
            ( $runtime, $junk ) = split( / /, $runtime );
         }
         if ( $line =~ /\] V:/ ) {
            ( $junk, $frames ) = split( /V: /, $line );
            ( $frames, $junk ) = split( /\,/, $frames );
         }
      }
      my $titlestring = sprintf( "Title %d - %s %s %s", $a, $chapters, $frames, $runtime );
      my $buffer = "$titlestring";
      my $tbutton;
      if ( $mode == 3 ) {
         $tbutton = Gtk2::CheckButton->new_with_label( $titlestring);
         $tbutton->signal_connect( 'clicked' => sub {
            if ( $tbutton->get_active() ) {
               &setlist( $a );
            } else {
               &unsetlist( $a );
            }
         }, $tbutton );
      } else {
         $tbutton = Gtk2::Button->new( $titlestring );
         $tbutton->signal_connect( "clicked" => sub{ \&gettnum( $a, $mode ); } );   
      }   
      $test_vbox->pack_start( $tbutton, $false, $false, 0 );
      $tbutton->show();
   }
}

# Add to the riplist as we select titles
#-----------------------------------------------------
sub setlist {
   my $arg = shift;
   if ( $#xriplist != -1 ) {
      &unsetlist( $arg );
   }
   push( @xriplist, $arg );
   &update_riplist;
}

# Subtract from the riplist as we deselect titles
#-----------------------------------------------------
sub unsetlist {
   my $arg = shift;
   for my $a ( 0..$#xriplist ) {
      if ( $xriplist[$a] == $arg ) {
         $xriplist[$a] = "x";
      }
   }
   &update_riplist;
}

# Update the riplist on the fly as we select/deselect
#-----------------------------------------------------
sub update_riplist {
   my $rlist;
   for my $a ( 0..$#xriplist ) {
      if ( $a < $#xriplist ) {
         $rlist .= $xriplist[$a] . ",";
      } else {
         $rlist .= $xriplist[$a];
      }
   }
   $rlist =~ s/x,//g;
   $rlist =~ s/x//g;
   $rlist =~ s/,,/,/g;
   if ( substr( $rlist, length( $rlist ) - 1, 1 ) eq "," ) {
      $rlist = substr( $rlist, 0, length( $rlist ) - 1 );
   }
   $riplist_box->set_text( $rlist );
}

# Set the selected title number
#-----------------------------------------------------
sub gettnum {
   my $tnum = shift;
   my $mode = shift;
   if ( $mode == 0 ) {
      $tname_entry->set_text( $tnum );
   } elsif ( $mode == 1 ) {
      $starttitle_box->set_text( $tnum );
   } else {
      $endtitle_box->set_text( $tnum );
   }
   $tselect_window->destroy();
}

# Show the subtitle stream selection window
#-----------------------------------------------------
sub showsublist {
   my $mode = shift;
   $sselect_window = new Gtk2::Window( 'toplevel' );
   $sselect_window->set_position( 'center' );
   $sselect_window->signal_connect( 'delete_event' => sub { $sselect_window->destroy(); } );
   my $ttl = $tname_entry->get_text();
   $sselect_window->set_title( "Subtitle streams in title $ttl" );
   $sselect_window->set_default_size( 500, 250 );
   $sselect_window->show();
  
   my $m_vbox = Gtk2::VBox->new( $false, 0 );
   $sselect_window->add( $m_vbox );
   $m_vbox->show();

   my $sscrolled_window = new Gtk2::ScrolledWindow( undef, undef );
   $sscrolled_window->set_policy( "automatic", "always" );
   $m_vbox->add( $sscrolled_window );
   $sscrolled_window->show();

   my $stest_vbox = Gtk2::VBox->new( $false, 0 );
   $sscrolled_window->add_with_viewport( $stest_vbox );
   $stest_vbox->show();

   my $sbuttonbox = Gtk2::HButtonBox->new();
   $sbuttonbox->set_layout( 'end' );
   $m_vbox->pack_end( $sbuttonbox, $false, $false, 0 );
   $sbuttonbox->show();

   my $scbutton = new Gtk2::Button( "Close" );
   $scbutton->signal_connect( "clicked" => sub{ $sselect_window->destroy(); } );
   $sbuttonbox->pack_start( $scbutton, $false, $false, 0 );
   $scbutton->show();
   
   my $stitle = $tname_entry->get_text();
   my @sinfo = qx/tcprobe -i $config{ 'RDEVICE' } -T $stitle -H 200 2>&1/;
   my @slist = ();
   foreach my $line ( @sinfo ) {
      chomp $line;
      if ( $line =~ /\) subtitle/ ) {
         my ( $junk, $substream ) = split( /\) /, $line );
         $substream =~ s/[0-9=<>]//g;
         push( @slist, $substream );
      }
   }
   
   for my $a ( 0..$#slist ) {
      my $substring = sprintf( "Stream %d - %s", $a, $slist[$a] );
      my $buffer = "$substring";
      my $button = Gtk2::Button->new( $buffer );
      $button->signal_connect( "clicked" => sub{ \&getsnum( $a, $mode ); } );
      $stest_vbox->pack_start( $button, $false, $false, 0 );
      $button->show();
   }
}

# Set the selected subtitle stream number
#-----------------------------------------------------
sub getsnum {
   my $snum = shift;
   my $mode = shift;
   if ( $mode == 0 ) {
      $sname_entry->set_text( $snum );
   } else {
      $subtitlestream_box->set_text( $snum );
   }
   $sselect_window->destroy();
}

# Show the 'about' window for a few seconds
#-----------------------------------------------------
sub about {
   my $about_window = Gtk2::Window->new( 'toplevel' );
   $about_window->set_default_size( 400, 410 );
   $about_window->set_position( 'center' );
   $about_window->set_title( "XDVDShrink License" );

   my $about_vbox = Gtk2::VBox->new( $false, 0 );
   $about_window->add( $about_vbox );

   my $about_pLabel = Gtk2::Label->new( "Ozzzy's XDVDShrink" );
   my $about_font = Gtk2::Pango::FontDescription->from_string( "Helvetica Bold 16" );
   my $about_color = Gtk2::Gdk::Color->parse( 'red' );
   $about_pLabel->modify_font( $about_font );
   $about_pLabel->modify_fg( 'normal', $about_color );
   $about_vbox->pack_start( $about_pLabel, $false, $false, 10 );
   $about_pLabel->show();

   my $sText_string = "Version: $version\n" .
                   "Build Date: $build_date\n\n" . 
                   "A Gtk+2 front-end to 'dvdshrink' and \n" .
                   "'batchrip.sh'\n\n" .
                   "Allows you make a 'fair use' archival copy\n" .
                   "of a commercial DVD.\n\n" . 
                   "This software package is released as-is\n" .
                   "under the terms of the GNU General Public\n" .
                   "License with NO WARRANTY WHATSOEVER\n\n" .
                   "(http://www.gnu.org/copyleft/gpl.html)\n\n" .
                   "Copyright (c) 2005, Rick Saunders\n\n" .
                   "Copy and distribute as you see fit as\n" .
                   "long as this copyright notice is included.";

   my $about_license = Gtk2::Label->new( $sText_string );
   $about_vbox->pack_start( $about_license, $false, $false, 0 );
   $about_license->show();

   my $about_url_text = "http://ozzzy.dhis.org";
   my $about_url = Gtk2::Label->new( $about_url_text );
   $about_color= Gtk2::Gdk::Color->parse( 'blue' );
   $about_url->modify_font( $banner_font );
   $about_url->modify_fg( 'normal', $about_color );
   $about_vbox->pack_start( $about_url, $false, $false, 10 );
   $about_url->show();
   $about_vbox->show();

   my $about_hbox = Gtk2::HButtonBox->new;
   $about_hbox->set_layout( 'end' );
   my $about_close_button = Gtk2::Button->new( "Close" );
   $about_close_button->signal_connect( 'clicked' => sub{ $about_window->destroy(); } );
   $about_hbox->pack_end( $about_close_button, $false, $false, 0 );
   $about_close_button->show();
   $about_hbox->show();
   $about_vbox->add( $about_hbox );
   $about_time = time;
   my $about_timer = Glib::Timeout->add( 1000, \&AboutTimer, $about_window );

   $about_window->show();
}

# The timer for the about box
#-----------------------------------------------------
sub AboutTimer {
   my ( $widget ) = @_;
   my $new_val;
   my $newtime    = time;
   $new_val       = $newtime - $about_time;
   if ( $new_val <= 10 ) {
      return( $true )
   } else {
      $widget->destroy();
      return ( $false );
   }
}

# The timer for the splash window
#-----------------------------------------------------
sub SplashTimer {
   my $timeout = shift;
   my $widget = shift;
   my $new_val;
   my $newtime    = time;
   $new_val       = $newtime - $about_time;
   if ( $new_val <= $timeout ) {
      return( $true )
   } else {
      $widget->destroy();
      return ( $false );
   }
}

# The main 'help' window with buttons for each sub-topic
#-----------------------------------------------------
sub Help {
   my $mode = shift;
   my $mHelp_window = Gtk2::Window->new( 'toplevel' );
   $mHelp_window->set_default_size( 250,100 );
   $mHelp_window->set_title( "DVDShrink Help" );
   my $mHelp_vbox = Gtk2::VBox->new( $false, 0 );
   $mHelp_window->add( $mHelp_vbox );
   $mHelp_vbox->show();
         
   if ( $mode == 0 ) {
      my $pname_button = Gtk2::Button->new( "Project Name" );
      $pname_button->set_relief( 'none' );
      $mHelp_vbox->pack_start( $pname_button, $true, $false, 0 );
      $pname_button->signal_connect( 'clicked' => sub{ &ShowHelp( 1 ); }, $pname_button );
      $pname_button->show();
      
      my $audio_button = Gtk2::Button->new( "Audio Streams" );
      $audio_button->set_relief( 'none' );
      $mHelp_vbox->pack_start( $audio_button, $false, $false, 0 );
      $audio_button->signal_connect( 'clicked' => sub{ &ShowHelp( 2 ); }, $audio_button );
      $audio_button->show();

      my $sub_button = Gtk2::Button->new( "Subtitle Streams" );
      $sub_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $sub_button, $false, $false, 0 );
      $sub_button->signal_connect( 'clicked' => sub{ &ShowHelp( 3 ); }, $sub_button );
      $sub_button->show();
      
      my $title_button = Gtk2::Button->new( "Title Selection" );
      $title_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $title_button, $false, $false, 0 );
      $title_button->signal_connect( 'clicked' => sub{ &ShowHelp( 4 ); }, $title_button );
      $title_button->show();

      my $iso_button = Gtk2::Button->new( "ISO Creation" );
      $iso_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $iso_button, $false, $false, 0 );
      $iso_button->signal_connect( 'clicked' => sub{ &ShowHelp( 5 ); }, $iso_button );
      $iso_button->show();

      my $requant_button = Gtk2::Button->new( "TCRequant Factors" );
      $requant_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $requant_button, $false, $false, 0 );
      $requant_button->signal_connect( 'clicked' => sub{ &ShowHelp( 6 ); }, $requant_button );
      $requant_button->show();

      my $streams_button = Gtk2::Button->new( "Streams Only" );
      $streams_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $streams_button, $false, $false, 0 );
      $streams_button->signal_connect( 'clicked' => sub{ &ShowHelp( 7 ); }, $streams_button );
      $streams_button->show();

      my $author_button = Gtk2::Button->new( "Authoring and burning" );
      $author_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $author_button, $false, $false, 0 );
      $author_button->signal_connect( 'clicked' => sub{ &ShowHelp( 8 ); }, $author_button );
      $author_button->show();

      my $remove_button = Gtk2::Button->new( "Removing working files" );
      $remove_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $remove_button, $false, $false, 0 );
      $remove_button->signal_connect( 'clicked' => sub{ &ShowHelp( 9 ); }, $remove_button );
      $remove_button->show();

      my $mpeg_button = Gtk2::Button->new( "MPEG Creation" );
      $mpeg_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $mpeg_button, $false, $false, 0 );
      $mpeg_button->signal_connect( 'clicked' => sub{ &ShowHelp( 10 ); }, $mpeg_button );
      $mpeg_button->show();

       my $restart_button = Gtk2::Button->new( "Restarting" );
      $restart_button->set_relief( 'none' );       
      $mHelp_vbox->pack_start( $restart_button, $false, $false, 0 );
      $restart_button->signal_connect( 'clicked' => sub{ &ShowHelp( 11 ); }, $restart_button );
      $restart_button->show();
      
      my $bind_button = Gtk2::Button->new( "Key bindings" );
      $bind_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $bind_button, $false, $false, 0 );
      $bind_button->signal_connect( 'clicked' => sub{ &ShowHelp( 15 ); }, $bind_button );
      $bind_button->show();

   } else {
      my $tname_button = Gtk2::Button->new( "TV Show Name" );
      $tname_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $tname_button, $false, $false, 0 );
      $tname_button->signal_connect( 'clicked' => sub{ &ShowHelp( 1 ); }, $tname_button );
      $tname_button->show();
      
      my $audio_button = Gtk2::Button->new( "Audio Streams" );
      $audio_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $audio_button, $false, $false, 0 );
      $audio_button->signal_connect( 'clicked' => sub{ &ShowHelp( 2 ); }, $audio_button );
      $audio_button->show();

      my $sub_button = Gtk2::Button->new( "Subtitle Streams" );
      $sub_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $sub_button, $false, $false, 0 );
      $sub_button->signal_connect( 'clicked' => sub{ &ShowHelp( 3 ); }, $sub_button );
      $sub_button->show();
      
      my $title_button = Gtk2::Button->new( "Title Selection" );
      $title_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $title_button, $false, $false, 0 );
      $title_button->signal_connect( 'clicked' => sub{ &ShowHelp( 4 ); }, $title_button );
      $title_button->show();

      my $riplist_button = Gtk2::Button->new( "Custom Rip List" );
      $riplist_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $riplist_button, $false, $false, 0 );
      $riplist_button->signal_connect( 'clicked' => sub{ &ShowHelp( 13 ); }, $riplist_button );
      $riplist_button->show();

      my $requant_button = Gtk2::Button->new( "TCRequant Factors" );
      $requant_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $requant_button, $false, $false, 0 );
      $requant_button->signal_connect( 'clicked' => sub{ &ShowHelp( 6 ); }, $requant_button );
      $requant_button->show();

      my $episodes_button = Gtk2::Button->new( "Episodes per DVD" );
      $episodes_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $episodes_button, $false, $false, 0 );
      $episodes_button->signal_connect( 'clicked' => sub{ &ShowHelp( 14 ); }, $episodes_button );
      $episodes_button->show();

      my $author_button = Gtk2::Button->new( "Authoring and burning" );
      $author_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $author_button, $false, $false, 0 );
      $author_button->signal_connect( 'clicked' => sub{ &ShowHelp( 8 ); }, $author_button );
      $author_button->show();
      
      my $er_button = Gtk2::Button->new( "Restarting" );
      $er_button->set_relief( 'none' );
      $mHelp_vbox->pack_start( $er_button, $false, $false, 0 );
      $er_button->signal_connect( 'clicked' => sub{ &ShowHelp( 11 ); }, $er_button );
      $er_button->show();
      
      my $bind_button = Gtk2::Button->new( "Key bindings" );
      $bind_button->set_relief( 'none' );      
      $mHelp_vbox->pack_start( $bind_button, $false, $false, 0 );
      $bind_button->signal_connect( 'clicked' => sub{ &ShowHelp( 15 ); }, $bind_button );
      $bind_button->show();
   }

   my $seperator = Gtk2::HSeparator->new();
   $mHelp_vbox->pack_start( $seperator, $false, $false, 0 );
   $seperator->show();

   my $buttonbar = Gtk2::HButtonBox->new();
   $buttonbar->set_layout( 'end' );
   $mHelp_vbox->pack_start( $buttonbar, $false, $false, 0 );
   $buttonbar->can_focus( $true );
   $buttonbar->grab_focus();
   $buttonbar->show();
   
   my $quitbutton = Gtk2::Button->new( "Close" );
   $buttonbar->pack_start( $quitbutton, $false, $false, 0 );
   $quitbutton->signal_connect( 'clicked' => sub{ $mHelp_window->destroy(); }, $quitbutton );
   $quitbutton->can_default( $true );
   $quitbutton->grab_default();
   $quitbutton->show();
      
   $mHelp_window->show();   
}   

# The help stuff
#-----------------------------------------------------
sub ShowHelp {
   my $help = shift;
   my $help_message;
   my $help_title;
   if ( $help ==1 ) {
      $help_message = "The project name should be something that is simple\n" .
                      "to remember. You can put anything you wish in here\n" .
                      "with a limit of 32 characters; or use the Volume ID of\n" .
                      "the DVD by clicking the 'Set from DVD' button next to\n" .
                      "the entry box. If you leave this blank then the script\n" .
                      "will automatically set the project name to the Volume ID.\n\n" .
                      "In 'episode mode' the project name changes for each\n" .
                      "episode ripped. This is done by adding a time based\n" .
                      "field in the project name string. This is to enable the\n" .
                      "script to build an XML file for the project which is used\n" .
                      "in the author function.";
      $help_title = "Project Name";
   } elsif ( $help == 2 ) {
      $help_message = "Normally the first audio stream in English is stream\n" .
                      "'0' which is the script default. To select a dif-\n" .
                      "ferent stream enter the stream number or click the\n" .
                      "'Select from DVD' button next to the entry box.\n\n" .
                      "Any non-digit value will cause the program to error\n" .
                      "giving you the opportunity to amend the value.";
      $help_title = "Audio streams";
   } elsif ( $help == 3 ) {
      $help_message = "Most times you won't be ripping subtitle streams. \n" .
                      "If you do indeed need a subtitle on your new\n" .
                      "DVD then enter the corresponding number in the sub-\n" .
                      "title selection entry box, or click the 'Select from\n" .
                      "DVD' button next to the entry box.\n\n" .
                      "Any non-digit value will cause the program to error\n" .
                      "giving you the opportunity to amend the value.";
      $help_title = "Subtitle streams";
   } elsif ( $help == 4 ) {
      $help_message = "Generally on a DVD the title with the most chapters\n" .
                      "is the main feature. Again, generally this is title 1.\n" .
                      "Some DVD authors, for whatever perverse reason, put a\n" .
                      "title with many chapters but no time on their disks.\n" .
                      "This may thwart some copiers, but is really a waste of\n" .
                      "time. Look at the run-time of the movie and select the\n" .
                      "title that corresponds if there is any question as to\n" .
                      "which title is the main feature.\n\n" .
                      "On multi-episode DVDs the titles that correspond to the\n" .
                      "episodes will all show the same run-time.";
      $help_title = "Title Selection";
   } elsif ( $help == 5 ) {
      $help_message = "By clicking the 'Create ISO only' checkbox you have asked\n" .
                      "the script to NOT burn a DVD but only create an ISO image\n" .
                      "that you can burn later. (Movie mode only)";
      $help_title = "ISO Creation";
   } elsif ( $help == 6 ) {
      $help_message = "The 'shrink-factor' is a value issued to the utility\n" .
                      "'M2VRequantiser' that tells it how much or how little\n" .
                      "to re-quantize the MPEG2 video stream. You'll have\n" .
                      "to play with this a bit, but a good starting point\n" .
                      "is 1.5. The script will correctly calculate the nec-\n" .
                      "cessary shrink factor to fit your title onto a DVD5\n" .
                      "so unless you have a special need for a different\n" .
                      "factor you should leave this at 1.0.\n\n" .
                      "In 'episode' mode the script will correctly calculate\n" .
                      "a shrink factor that will allow each title to fit into\n" .
                      "a space of 4.7G / number of episodes per DVD.";
      $help_title = "TCRequant shrink factor";
   } elsif ( $help == 7 ) {
      $help_message = "Checking the 'Rip selected streams only' box will cause\n" .
                      "the script to exit after ripping the video and audio\n" .
                      "streams and re-sizing the video to fit DVD5\n\n" .
                      "Checking the 'Rip selecte unshrunk streams only' box will\n" .
                      "cause the script to exit after ripping the streams. No\n" .
                      "resizing will be performed. (Movie mode only)";
      $help_title = "Ripping Streams Only";
   } elsif ( $help == 8 ) {
      $help_message = "The authoring and burning check boxes function exactly\n" .
                      "as they say. They tell the script to author the new DVD\n" .
                      "on the hard drive under the project directory and\n" .
                      "then, when the DVD is authored to burn it to a new blank\n" .
                      "DVD if selected. Checking the 'Forceburn' box will cause\n" .
                      "the script to start the burn without a prompt and is only\n" .
                      "activated if you have two devices configured.";
      $help_title = "Authoring and Burning";
   } elsif ( $help == 10 ) {
      $help_message = "Checking the 'Create MPEG file only' box will cause the\n" .
                      "script to exit after creating an MPEG2 file of your rip\n" .
                      "re-sized to fit on a DVD5\n\n" .
                      "Checking the 'Create unshrunk MPEG file only' box will\n" .
                      "cause the script to exit after creating an MPEG2 file that\n" .
                      "is the original size as that on the source DVD for that\n" .
                      "title. (Movie mode only)";
      $help_title = "MPEG Files Only";
   } elsif ( $help == 9 ) {
      $help_message = "Selecting the 'Remove working files' box causes the script\n" .
                      "to remove it's working files as soon as they are no longer\n" .
                      "needed. This is solely to save disk space. If you may wish\n" .
                      "to re-use your working files at a later date uncheck this\n" .
                      "box. (Movie mode only)";
      $help_title = "Remove Working Files";
   } elsif ( $help == 11 ) {
      $help_message = "Should the main bash script fail you will be notified and\n" .
                      "given the opportunity to read the script log (in your home\n" .
                      "directory) and the error log (in the project directory).\n\n" .
                      "If the error is correctable you can fix the problem and\n" .
                      "'restart' the main script either at the same point that\n" .
                      "it failed, or if you feel the problem isn't fatal you may\n" .
                      "restart with the next function in the main script to con-\n" .
                      "tinue the rip.\n\n" .
                      "In 'episode' mode the restart functions a bit differently.\n" .
                      "Should a single episode fail then the DVD functions such\n" .
                      "as 'Create XML', 'Author...' and 'Burn...' are disabled and\n" .
                      "the program will attempt to re-rip the failed episodes from\n" .
                      "scratch. This is a neccessary evil of the function of the\n" .
                      "episode mode.\n\n" .
                      "Clicking the 'Restart' button in 'episode' mode will re-set\n" .
                      "the DVD functions selected when the title failed.";
      $help_title = "Restarting";
   } elsif ( $help == 13 ) {
      $help_message = "If you have determined that you don't want all of\n" .
                      "the titles in sequence from a DVD you may enter a\n" .
                      "'rip-list'. This is a comma-delimited string that\n" .
                      "tells the script which titles to rip. Enter any\n" .
                      "string of numbers such as 4,7,2,1,5. If there are\n" .
                      "any whitespaces they will be removed, but if you\n" .
                      "enter anything other than numbers and commas the\n" .
                      "script will error out and tell you to amend your\n" .
                      "ways. Entering a non-valid title number will cause\n" .
                      "the 'dvdshrink' script to error. (Episode mode only)";
      $help_title = "Custom rip list";
   } elsif ( $help == 14 ) {
      $help_message = "The 'episodes-per-DVD' value is just how many\n" .
                      "episodes that you want the script to put into your\n" .
                      "XML files (if you create them). So, if you enter\n" .
                      "4 in this field, you will have XML description files\n" .
                      "with 4 or less titles per DVD.\n\n" .
                      "You must enter a numeric value greater than 0. If you\n" .
                      "enter any other character the script will error and\n" .
                      "ask you to amend your entry. (Episode mode only)";
      $help_title = "Episodes per DVD";
   } elsif ( $help == 15 ) {
      $help_message = "There are only four key bindings. They are\n\n" .
                      "   Ctrl-S       Start the rip\n" .
                      "   Ctrl-E       Re-start the rip (only in movie mode)\n" .
                      "   Ctrl-C       Configure\n" .
                      "   Ctrl-X       Exit the program";
      $help_title = "Key bindings";
   }
   my $help_window = Gtk2::Window->new( 'toplevel' );
   $help_window->set_default_size( 400, 200 );
   $help_window->signal_connect( 'delete_event' => sub { $help_window->destroy(); } );   
   
   my $help_align = Gtk2::Alignment->new( .5, .5, .8, .8 );
   $help_window->add( $help_align );
   $help_align->show();
   
   my $help_vbox = Gtk2::VBox->new( $false, 0 );
   $help_align->add( $help_vbox );
   $help_vbox->show();
   
   my $help_label = Gtk2::Label->new();
   $help_label->modify_font( $banner_font );
   $help_label->modify_fg( 'normal', $color_red );
   $help_label->set_text( "xBatchRip Help" );
   $help_vbox->pack_start( $help_label, $false, $false, 5 );
   $help_label->show();
   
   my $help_title_label = Gtk2::Label->new();
   $help_title_label->modify_font( $banner_font );
   $help_title_label->modify_fg( 'normal', $color_blue );
   $help_title_label->set_text( $help_title );
   $help_vbox->pack_start( $help_title_label, $false, $false, 5 );
   $help_title_label->show();
   
   my $help_msg_label = Gtk2::Label->new();
   $help_msg_label->set_text( $help_message );
   $help_vbox->pack_start( $help_msg_label, $false, $false, 0 );
   $help_msg_label->show();
   
   my $help_buttonbar = Gtk2::HButtonBox->new();
   $help_buttonbar->set_layout( 'end' );
   $help_vbox->pack_start( $help_buttonbar, $false, $false, 0 );
   $help_buttonbar->show();
   
   my $help_quit_button = Gtk2::Button->new_with_label( "Close" );
   $help_quit_button->signal_connect( 'clicked' => sub{ $help_window->destroy(); }, $help_quit_button );
   $help_buttonbar->pack_start( $help_quit_button, $false, $false, 0 );
   $help_quit_button->show();
   
   $help_window->show();
}

   
# A simple error trap. It only looks for simple errors but may catch some
# typing mystakes.
#-----------------------------------------------------
sub checkvalues {
   my $startval = $starttitle_box->get_text();
   chomp $startval;
   $startval =~ s/\D//g;
   my $endval   = $endtitle_box->get_text();
   chomp $endval;
   $endval =~ s/\D//g;
   my $shrinkval = $kfactor_adjust2->value;
   chomp $shrinkval;
   $shrinkval =~ s/[a-zA-Z_\-\,\|\"\'\(\)\*\&\^\%\$\#\@\!\?\/\>\<\[\]\{\}]//;
   my $episodeval = $episode_box->get_text();
   chomp $episodeval;
   $episodeval =~ s/\D//g;
   if ( $riplist_box->get_text() eq "" ) {
      if ( ( $startval < 1 ) || ( $startval eq "" ) ) { 
         return 1; 
      }
      if ( ( $endval < $startval ) || ( $endval eq "" ) ) { 
         return 2;
      }
   }
   if ( $shrinkval > 1.0 ) {   
      if ( ( $shrinkval != "" ) && ( ( $shrinkval <= 1 ) || ( $shrinkval > 2 ) ) ) {
         return 3;
      }
   }
   if ( ( $episodeval == 0 ) || ( $episodeval eq "" ) ) { 
      return 4; 
   }
}

# Shows the error found above
#-----------------------------------------------------
sub showerror {
   my $error = shift;
   my $message1 = "The start title must be greater than 0 and not\n" .
                  "contain any non-digit characters. The end title\n" .
                  "must be greater or equal to the start title and\n" .
                  "not contain any non-digit characters. Neither\n" .
                  "may be empty strings unles a rip-list value is\n." .
                  "specified correctly.";
   my $message2 = "The rip-list string may contain only digits and\n" .
                   "commas. Whitespaces are removed. The rip-list may\n" .
                   "be blank as long as the start and end title values\n" .
                   "are correct.\n\n" . 
                   "An acceptible value would be something like 1,4,8,7";
   my $message3 = "The episodes-per-DVD value may not be 0 and may not\n" .
                   "contain any non-digit characters and may not be a\n" .
                   "blank string.";
   my $message4 = "The shrink factor must be a value between 1.01 and \n" .
                   "2.0. While values outside this range are perfectly\n" .
                   "acceptible to the utilities, anything 1.0 or below\n" .
                   "are ignored by the underlying bash script and values\n" .
                   "above 2.0 may give odd results. Therefore they are\n" .
                   "banned by xBatchRip.";
                                      
   my $error_window = Gtk2::Window->new( 'toplevel' );
   my $error_message = Gtk2::Label->new();
   $error_window->set_default_size( 400, 90 );
   my $signal = $error_window->signal_connect( 'delete_event' => sub { $error_window->destroy(); } );
   my $error_align = Gtk2::Alignment->new( .5, .5, .8, .8 );
   $error_align->show();
   $error_window->add( $error_align );
   my $error_vbox = Gtk2::VBox->new( $true, 0 );
   $error_align->add( $error_vbox );
   $error_vbox->show();
   my $error_label = Gtk2::Label->new();
   $error_label->modify_font( $item_font );
   $error_label->modify_fg( 'normal', $color_red );
   if ( $error == 1 ) { 
      $error_label->set_text( "Invalid start title value" ); 
      $error_message->set_text( $message1 );
   }
   elsif ( $error == 2 ) { 
      $error_label->set_text( "Invalid end title value" );
      $error_message->set_text( $message1 );
   }
   elsif ( $error == 3 ) { 
      $error_label->set_text( "Invalid shrink factor value" );
      $error_message->set_text( $message4 );
   }
   elsif ( $error == 4 ) { 
      $error_label->set_text( "Invalid 'episodes per DVD' value" );
      $error_message->set_text( $message3 );
   }

   $error_vbox->pack_start( $error_label, $false, $false, 0 );
   $error_vbox->pack_start( $error_message, $false, $false, 0 );
   $error_label->show();
   $error_message->show();
   my $error_buttonbar = Gtk2::HButtonBox->new();
   $error_buttonbar->set_layout( 'end' );
   $error_vbox->pack_start( $error_buttonbar, $false, $false, 0 );
   $error_buttonbar->show();
   my $error_close_button = Gtk2::Button->new( "Close" );
   $error_close_button->signal_connect( 'clicked' => sub{ $error_window->destroy(); } );
   $error_buttonbar->pack_start( $error_close_button, $false, $false, 0 );
   $error_close_button->show();
   $error_window->show();
}    

# Adjust the episode value when the start/end title boxes change
#-----------------------------------------------------
sub AdjustEpisodes {
   my $starttitle = $starttitle_box->get_text();
   my $endtitle   = $endtitle_box->get_text();
   if ( $endtitle >= $starttitle ) {
      if ( $endtitle >= $starttitle ) {
         my $episodes = $endtitle - $starttitle;
         if ( $episodes == 0 ) {
            $episode_box->set_text( "1" );
         } else {
            $episode_box->set_text( $episodes + 1);
         }
      }
   }
} 

# Toggle the titles boxes if we're putting in a custom
# riplist. Also, store the value we had in the episodes
# box, amend the episodes box as per the riplist and
# return the original value if we clear the riplist.
#-----------------------------------------------------
sub toggle_titles {
   if ( $epchanged == 0 ) {
      $epval = $episode_box->get_text();
      $epchanged++;
   }
   if ( $riplist_box->get_text() ne "" ) {
      $starttitle_box->set_text( "Custom" );
      $starttitle_box->set_editable( $false );
      $endtitle_box->set_text( "Custom" );
      $endtitle_box->set_editable( $false );
   } else {
      $starttitle_box->set_editable( $true );      
      $starttitle_box->set_text( $stitle_val );
      $endtitle_box->set_editable( $true );      
      $endtitle_box->set_text( $etitle_val );
      
   }
   my $riplistval = $riplist_box->get_text();
   if ( $riplistval =~ /\,\D/ ) {
      $riplistval =~ s/\,\D//;
      $riplist_box->set_text( $riplistval );
   }
   my @eps = split( /\,/, $riplistval );      
   if ( $#eps + 1 < 1 ) {
      $episode_box->set_text( $epval );
      $epchanged = 0;
   } else {
      $episode_box->set_text( $#eps + 1 );
   }
}      

# Reset the sensitivity of everything
#-----------------------------------------------------
sub CheckDefaults {
   if ( $notebook->get_current_page() == 0 ) {
      $abcheck->set_sensitive( $true );
      if ( $config{ 'MULTIDRIVE' } ) {
         $fbcheck->set_sensitive( $true );
      }
      $aucheck->set_sensitive( $true );
      $rmcheck->set_sensitive( $true );
      $sicheck->set_sensitive( $true );
      $stcheck->set_sensitive( $true );
      $STcheck->set_sensitive( $true );
      $smcheck->set_sensitive( $true );
      $SMcheck->set_sensitive( $true );
      $shcheck->set_sensitive( $true );
   } else {
      $xml_check->set_sensitive( $true );
      $dvd_check->set_sensitive( $true );
      $burn_check->set_sensitive( $true );
      if ( $config{ 'MULTIDRIVE' } ) {
         $aburn_check->set_sensitive( $true );
      }
   }
 
}   

# Save checkbox values to the hash
#-----------------------------------------------------
sub savevalues {
   if ( $notebook->get_current_page() == 0 ) {
      $single_values{ 'AUTOBURN' }     = $abcheck->get_active() ? $true : $false;
      $single_values{ 'FORCEBURN' }    = $fbcheck->get_active() ? $true : $false;
      $single_values{ 'RMFILES' }      = $rmcheck->get_active() ? $true : $false;
      $single_values{ 'AUTHOR_ONLY' }  = $aucheck->get_active() ? $true : $false;
      $single_values{ 'STREAM_ONLY' }  = $stcheck->get_active() ? $true : $false;
      $single_values{ 'BSTREAM_ONLY' } = $STcheck->get_active() ? $true : $false;
      $single_values{ 'MPEG_ONLY' }    = $smcheck->get_active() ? $true : $false;
      $single_values{ 'BMPEG_ONLY' }   = $SMcheck->get_active() ? $true : $false;
      $single_values{ 'ISO_ONLY' }     = $sicheck->get_active() ? $true : $false;
      $single_values{ 'SHRINK' }       = $shcheck->get_active() ? $true : $false;
      $single_values{ 'SAVEISO' }      = $siso_save_check->get_active() ? $true : $false;
      $single_values{ 'DELETELOGS' }   = $sdeletelog_check->get_active() ? $true : $false;
   } else {
      $episode_values{ 'MAKEXML' }      = $xml_check->get_active() ? $true : $false;
      $episode_values{ 'AUTHOR_ONLY' }  = $dvd_check->get_active() ? $true : $false;
      $episode_values{ 'AUTOBURN' }     = $burn_check->get_active() ? $true : $false;
      $episode_values{ 'FORCEBURN' }    = $aburn_check->get_active() ? $true : $false;
      $episode_values{ 'SAVEISO' }      = $eiso_save_check->get_active() ? $true: $false;
      $episode_values{ 'DELETELOGS' }   = $edeletelog_check->get_active() ? $true : $false;
      $episode_values{ 'ISO_ONLY' }     = $eiso_check->get_active() ? $true : $false;
      $episode_values{ 'MAKEMENU' }     = $menu_check->get_active() ? $true : $false;
      $episode_values{ 'RMFILES' }      = $erm_check->get_active() ? $true : $false;
  }      
}

# Enable/disable the autoburn or force burn buttons depending
# on the button selected. This function and then ButtonChk
# functions give 'radio button' functionality to standard
# checkboxes. We could use radio buttons, but that would mar
# the look of the application window.
#-----------------------------------------------------
sub BurnButtonChk {
   my ( $widget, $wvalue ) = @_;
   my $bvalue = abs( $widget->get_active() - 1 );
   if ( $wvalue != 1 ) { $widget->set_sensitive( $bvalue ); }
   if ( $config{ 'MULTIDRIVE' } ) {
      if ( $wvalue != 2 ) { $widget->set_sensitive( $bvalue ); }
   }
   $siso_save_check->set_sensitive( abs( $bvalue ) - 1 );
   $aucheck->set_sensitive( $bvalue );
   $sicheck->set_sensitive( $bvalue );
   $stcheck->set_sensitive( $bvalue );
   $STcheck->set_sensitive( $bvalue );
   $smcheck->set_sensitive( $bvalue );
   $SMcheck->set_sensitive( $bvalue );
}

# Enable/disable buttons as needed depending on button selection
#-----------------------------------------------------
sub ButtonChk {
   my ( $widget, $wvalue ) = @_;
   my $bvalue = abs( $widget->get_active() - 1 );
   $abcheck->set_sensitive( $bvalue );
   if ( $config{ 'MULTIDRIVE' } ) {
      $fbcheck->set_sensitive( $bvalue );    
   }
   if ( $wvalue != 1 ) { $aucheck->set_sensitive( $bvalue ); }   
   if ( $wvalue != 2 ) { $sicheck->set_sensitive( $bvalue ); }
   if ( $wvalue != 3 ) { $stcheck->set_sensitive( $bvalue ); }
   if ( $wvalue != 4 ) { $STcheck->set_sensitive( $bvalue ); }   
   if ( $wvalue != 5 ) { $smcheck->set_sensitive( $bvalue ); }
   if ( $wvalue != 6 ) { $SMcheck->set_sensitive( $bvalue ); }
   if ( ( $wvalue == 4 ) || ( $wvalue == 6 ) ) {   
      $shcheck->set_sensitive( $bvalue );
   }
}   

# Open a textview window with the full output from libdvdread
# in it.... just some more information.
#-----------------------------------------------------
sub ShowAllInfo {
   my $title = $tname_entry->get_text();
   my $infostring = "";
   
   my $rwindow = Gtk2::Window->new( 'toplevel' );
   $rwindow->set_default_size( 600, 480 );
   $rwindow->set_position( "none" );
   $rwindow->set_title( "Title Information" );
   $window->signal_connect( 'delete_event' => sub { $rwindow->destroy(); } );

   my $wx_text_align = Gtk2::Alignment->new( .5, .5, .8, .8 );
   $rwindow->add( $wx_text_align );
   $wx_text_align->show();
   
   my $wx_vbox = Gtk2::VBox->new;
   $wx_text_align->add( $wx_vbox );

   my $app_label = Gtk2::Label->new( "libdvdread Output" );
   my $app_label_font = Gtk2::Pango::FontDescription->from_string( "Helvetica Bold 16" );
   my $app_label_color = Gtk2::Gdk::Color->parse( 'red' );
   $app_label->modify_font( $app_label_font );
   $app_label->modify_fg( 'normal', $app_label_color );
   $app_label->show();
   $wx_vbox->pack_start( $app_label, $false, $false, 0 );

   my $scrolled_window = Gtk2::ScrolledWindow->new(undef, undef);
   $scrolled_window->set_policy('automatic', 'automatic');

   my $wx_text = new Gtk2::TextView->new;
   $wx_text->set_editable( $true );
   $wx_text->set_wrap_mode( 'word' );
   $wx_text->set_size_request( 500, 370 );
   my $wxbuffer = Gtk2::TextBuffer->new;
   $wxbuffer->set_text( "" );
   $wx_text->set_buffer( $wxbuffer );
   $wxbuffer->create_mark ('end', $wxbuffer->get_end_iter, $false);
   $wxbuffer->signal_connect ('insert_text' => sub {
      $wx_text->scroll_to_mark ( $wxbuffer->get_mark ('start'), 0.0, $true, 0, 0.5);
   }, $wxbuffer);
   $scrolled_window->add( $wx_text );
   $scrolled_window->show();
   $wx_text->show();
   $wx_vbox->add( $scrolled_window );

   $scrolled_window->set_size_request( 500, 370 );

   my $button_box = Gtk2::HButtonBox->new;
   $button_box->set_layout( 'end' );
   $wx_vbox->add( $button_box );
   my @infoarray = qx/tcprobe -i $config{ 'RDEVICE' } -T $title -H 200 2>&1/;
   for my $entry ( @infoarray ) {
      $infostring .= "$entry";
   }
   $wxbuffer->set_text( $infostring );
   
   my $close_button = Gtk2::Button->new( "Close" );
   $close_button->signal_connect( 'clicked' => sub { $rwindow->destroy(); } );
   $button_box->pack_start( $close_button, $false, $false, 0 );
   $close_button->show();
   $button_box->show();
   $wx_vbox->show();

   $rwindow->show();
}

# Show the Splash Screen
#---------------------------------------------------
sub ShowSplash {
   $about_time = time;
   my $splash_window = Gtk2::Window->new( 'popup' );
   $splash_window->set_position( 'center' );
   my $image = Gtk2::Image->new_from_file( "$app_dir/xdvdshrink_logo.png" );
   $splash_window->add( $image );
   $image->show();
   $splash_window->show();
   my $about_timer = Glib::Timeout->add( 1000, sub{ &SplashTimer( 4, $splash_window ) } );
}

# Return the system to the state needed for a restart after
# failure. Reads the /tmp/batchrip.fail file to set the 
# needed variables.
#---------------------------------------------------
sub SetAfterFail {
   if ( -f "/tmp/batchrip.fail" ) {
      open( FDATA, "/tmp/batchrip.fail" );
      my @fdata = <FDATA>;
      close( FDATA );
      for my $line ( @fdata ) {
         chomp $line;
         my ( $key, $val ) = split( /=/, $line );
         if   ( $key eq "TVNAME" )      { $showname_box->set_text( $val ); }
         if   ( $key eq "AUDIOSTREAM" ) { $audiostream_box->set_text( $val ); }
         if   ( $key eq "SUBSTREAM" )   { $subtitlestream_box->set_text( $val ); }
         if   ( $key eq "RIPLIST" )     { $riplist_box->set_text( $val ); }
         if   ( $key eq "EPISODES" )    { $episode_box->set_text( $val ); }
         if ( ( $key eq "SHRINKFAC" ) && ( $val ne "" ) ) { $kfactor_adjust2->set_value( $val ); }
         if ( ( $key eq "AUTHORDVD" ) && ( $val == 1 ) )  { $dvd_check->set_active( $true ); }
         if ( ( $key eq "BURNDVDS" ) && ( $val == 1 ) )   { $burn_check->set_active( $true ); }
         if ( ( $key eq "FORCEBURN" ) && ( $val == 1 ) )  { $aburn_check->set_active( $true ); }
         if ( ( $key eq "ISO_ONLY" ) && ( $val == 1 ) )    { $eiso_check->set_active( $true ); }
         if ( ( $key eq "DELETELOGS" ) && ( $val == 1 ) ) { $edeletelog_check->set_active( $true ); }
      }
      &buildcmdline;
   }
}
