"Fossies" - the Fresh Open Source Software Archive

Member "dvdisaster-0.79.5/rs03-preferences.c" (25 Oct 2015, 37789 Bytes) of package /linux/misc/dvdisaster-0.79.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rs03-preferences.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.79.3_vs_0.79.5.

    1 /*  dvdisaster: Additional error correction for optical media.
    2  *  Copyright (C) 2004-2015 Carsten Gnoerlich.
    3  *
    4  *  Email: carsten@dvdisaster.org  -or-  cgnoerlich@fsfe.org
    5  *  Project homepage: http://www.dvdisaster.org
    6  *
    7  *  This file is part of dvdisaster.
    8  *
    9  *  dvdisaster is free software: you can redistribute it and/or modify
   10  *  it under the terms of the GNU General Public License as published by
   11  *  the Free Software Foundation, either version 3 of the License, or
   12  *  (at your option) any later version.
   13  *
   14  *  dvdisaster is distributed in the hope that it will be useful,
   15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17  *  GNU General Public License for more details.
   18  *
   19  *  You should have received a copy of the GNU General Public License
   20  *  along with dvdisaster. If not, see <http://www.gnu.org/licenses/>.
   21  */
   22 
   23 #include "dvdisaster.h"
   24 
   25 #include "rs03-includes.h"
   26 
   27 /***
   28  *** Create the preferences page for setting redundancy etc.
   29  ***/
   30 
   31 enum 
   32 {  PREF_NROOTS = 0,
   33    PREF_PRELOAD = 1,
   34    PREF_THREADS = 2
   35 };
   36 
   37 static int prefetch_size[] = { 32, 64, 96, 128, 192, 256, 384, 512, 768, 1024 };
   38 static int threads_count[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,20,24,28,31,32 };
   39 
   40 static void activate_toggle_button(GtkToggleButton *toggle, int state)
   41 {  if(toggle) gtk_toggle_button_set_active(toggle, state);
   42 }
   43 
   44 static void set_range_value(GtkRange *range, int value)
   45 {  if(range) gtk_range_set_value(range, value);
   46 }
   47 
   48 static void set_spin_button_value(GtkSpinButton *spin, int value)
   49 {  if(spin) gtk_spin_button_set_value(spin, value);
   50 }
   51 
   52 static void set_sensitive(GtkWidget *widget, int value)
   53 {
   54   if(widget) gtk_widget_set_sensitive(widget, value);
   55 }
   56 
   57 /*
   58  * Ecc storage method selection 
   59  */
   60 
   61 static void eccmethod_cb(GtkWidget *widget, gpointer data)
   62 {  RS03Widgets *wl = (RS03Widgets*)data;
   63    int state  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
   64 
   65    if(!state)  /* only track changes to activate state */
   66      return;
   67 
   68    if(widget == wl->eccFileA || widget == wl->eccFileB)
   69    {  Closure->eccTarget = ECC_FILE;
   70 
   71       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eccFileA), TRUE); 
   72       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eccFileB), TRUE); 
   73 
   74       set_sensitive(wl->radio1A, TRUE);
   75       set_sensitive(wl->radio1B, TRUE);
   76 
   77       gtk_notebook_set_current_page(GTK_NOTEBOOK(wl->redundancyNotebook), 1);
   78    }
   79 
   80    if(widget == wl->eccImageA || widget == wl->eccImageB)
   81    {  Closure->eccTarget = ECC_IMAGE;
   82 
   83       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eccImageA), TRUE); 
   84       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eccImageB), TRUE); 
   85 
   86       set_sensitive(wl->radio1A, FALSE);
   87       set_sensitive(wl->radio1B, FALSE);
   88 
   89       gtk_notebook_set_current_page(GTK_NOTEBOOK(wl->redundancyNotebook), 0);
   90    }
   91 }
   92 
   93 /*
   94  * Codec type selection 
   95  */
   96 
   97 static void encoding_alg_cb(GtkWidget *widget, gpointer data)
   98 {  RS03Widgets *wl = (RS03Widgets*)data;
   99    int state  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  100 
  101    if(!state)  /* only track changes to activate state */
  102      return;
  103 
  104    if(widget == wl->eaRadio1A || widget == wl->eaRadio1B)
  105    {  Closure->encodingAlgorithm = ENCODING_ALG_32BIT;
  106 
  107       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eaRadio1A), TRUE); 
  108       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eaRadio1B), TRUE); 
  109    }
  110 
  111    if(widget == wl->eaRadio2A || widget == wl->eaRadio2B)
  112    {  Closure->encodingAlgorithm = ENCODING_ALG_64BIT;
  113 
  114       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eaRadio2A), TRUE); 
  115       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eaRadio2B), TRUE); 
  116    }
  117 
  118    if(widget == wl->eaRadio3A || widget == wl->eaRadio3B)
  119    { 
  120 #ifdef HAVE_SSE2 
  121       Closure->encodingAlgorithm = ENCODING_ALG_SSE2;
  122 #endif
  123 #ifdef HAVE_ALTIVEC 
  124       Closure->encodingAlgorithm = ENCODING_ALG_ALTIVEC;
  125 #endif
  126 
  127       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eaRadio3A), TRUE); 
  128       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eaRadio3B), TRUE); 
  129    }
  130 
  131    if(widget == wl->eaRadio4A || widget == wl->eaRadio4B)
  132    {  Closure->encodingAlgorithm = ENCODING_ALG_DEFAULT;
  133 
  134       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eaRadio4A), TRUE); 
  135       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->eaRadio4B), TRUE); 
  136    }
  137 }
  138 
  139 /*
  140  * I/O strategy selection
  141  */
  142 
  143 static void io_strategy_cb(GtkWidget *widget, gpointer data)
  144 {  RS03Widgets *wl = (RS03Widgets*)data;
  145    int state  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  146 
  147    if(!state)  /* only track changes to activate state */
  148      return;
  149 
  150    if(widget == wl->ioRadio1A || widget == wl->ioRadio1B)
  151    {  Closure->encodingIOStrategy = IO_STRATEGY_READWRITE;
  152 
  153       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->ioRadio1A), TRUE); 
  154       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->ioRadio1B), TRUE); 
  155    }
  156 
  157    if(widget == wl->ioRadio2A || widget == wl->ioRadio2B)
  158    {  Closure->encodingIOStrategy = IO_STRATEGY_MMAP;
  159 
  160       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->ioRadio2A), TRUE); 
  161       activate_toggle_button(GTK_TOGGLE_BUTTON(wl->ioRadio2B), TRUE); 
  162    }
  163 }
  164 
  165 /*
  166  * Setting the notebook page does not work at creation time.
  167  */
  168 
  169 static gboolean notebook_idle_func(gpointer data)
  170 {  RS03Widgets *wl = (RS03Widgets*)data;
  171 
  172    switch(Closure->eccTarget)
  173    {  case ECC_FILE:
  174        gtk_notebook_set_current_page(GTK_NOTEBOOK(wl->redundancyNotebook), 1);
  175        break;
  176 
  177      case ECC_IMAGE:
  178        gtk_notebook_set_current_page(GTK_NOTEBOOK(wl->redundancyNotebook), 0);
  179        break;
  180    }
  181 
  182    return FALSE;
  183 }
  184 
  185 
  186 /*
  187  * Redundancy selection for error correction files.
  188  * Cut&Paste from RS01; bad idea; but RS01 will be obsoleted soon.
  189  */
  190 
  191 static void nroots_cb(GtkWidget *widget, gpointer data)
  192 {  RS03Widgets *wl = (RS03Widgets*)data;
  193    int value;
  194 
  195    value = gtk_range_get_value(GTK_RANGE(widget));
  196    if(Closure->redundancy) g_free(Closure->redundancy);
  197    Closure->redundancy = g_strdup_printf("%d", value);
  198 
  199    if(widget == wl->redundancyScaleA)
  200         set_range_value(GTK_RANGE(wl->redundancyScaleB), value);
  201    else set_range_value(GTK_RANGE(wl->redundancyScaleA), value);
  202 
  203    UpdateMethodPreferences();
  204 }
  205 
  206 static void ecc_size_cb(GtkWidget *widget, gpointer data)
  207 {  RS03Widgets *wl = (RS03Widgets*)data;
  208    int value;
  209 
  210    value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
  211    if(Closure->redundancy) g_free(Closure->redundancy);
  212    Closure->redundancy = g_strdup_printf("%dm", value);
  213 
  214    if(widget == wl->redundancySpinA)
  215         gtk_spin_button_set_value(GTK_SPIN_BUTTON(wl->redundancySpinB), atoi(Closure->redundancy));
  216    else gtk_spin_button_set_value(GTK_SPIN_BUTTON(wl->redundancySpinA), atoi(Closure->redundancy));
  217 
  218    UpdateMethodPreferences();
  219 }
  220 
  221 static void toggle_cb(GtkWidget *widget, gpointer data)
  222 {  Method *method = (Method*)data;
  223    RS03Widgets *wl = (RS03Widgets*)method->widgetList;
  224    int state  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  225 
  226    if(state == TRUE)
  227    {  if(widget == wl->radio3A || widget == wl->radio3B)
  228       {  gtk_widget_set_sensitive(wl->redundancyScaleA, TRUE);
  229      gtk_widget_set_sensitive(wl->redundancyScaleB, TRUE);
  230       }
  231       else
  232       {  gtk_widget_set_sensitive(wl->redundancyScaleA, FALSE);
  233      gtk_widget_set_sensitive(wl->redundancyScaleB, FALSE);
  234       }
  235 
  236       if(widget == wl->radio4A || widget == wl->radio4B)
  237       {  gtk_widget_set_sensitive(wl->redundancySpinA, TRUE); 
  238      gtk_widget_set_sensitive(wl->redundancySpinB, TRUE); 
  239      gtk_widget_set_sensitive(wl->radio4LabelA, TRUE); 
  240      gtk_widget_set_sensitive(wl->radio4LabelB, TRUE); 
  241       }
  242       else
  243       {  gtk_widget_set_sensitive(wl->redundancySpinA, FALSE); 
  244      gtk_widget_set_sensitive(wl->redundancySpinB, FALSE); 
  245      gtk_widget_set_sensitive(wl->radio4LabelA, FALSE); 
  246      gtk_widget_set_sensitive(wl->radio4LabelB, FALSE); 
  247       }
  248 
  249       if(   widget == wl->radio1A  /* Normal */
  250      || widget == wl->radio1B)
  251       {  
  252          set_range_value(GTK_RANGE(wl->redundancyScaleA), 32);
  253          set_range_value(GTK_RANGE(wl->redundancyScaleB), 32);
  254 
  255      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio1A), TRUE);
  256      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio1B), TRUE);
  257 
  258      if(Closure->redundancy) g_free(Closure->redundancy);
  259          Closure->redundancy = g_strdup("normal");
  260       }
  261 
  262       if(   widget == wl->radio2A  /* High */
  263      || widget == wl->radio2B)
  264       {  
  265          set_range_value(GTK_RANGE(wl->redundancyScaleA), 64);
  266          set_range_value(GTK_RANGE(wl->redundancyScaleB), 64);
  267 
  268      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio2A), TRUE);
  269      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio2B), TRUE);
  270 
  271      if(Closure->redundancy) g_free(Closure->redundancy);
  272      Closure->redundancy = g_strdup("high");
  273       }
  274 
  275       if(   widget == wl->radio3A  /* number of roots */
  276      || widget == wl->radio3B)
  277       {  int nroots = gtk_range_get_value(GTK_RANGE(wl->redundancyScaleA));
  278 
  279      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio3A), TRUE);
  280      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio3B), TRUE);
  281 
  282      if(Closure->redundancy) g_free(Closure->redundancy);
  283      Closure->redundancy = g_strdup_printf("%d", nroots);
  284       }
  285 
  286       if(   widget == wl->radio4A  /* relative to space usage */
  287      || widget == wl->radio4B)
  288       {  int space = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(wl->redundancySpinA));
  289 
  290      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio4A), TRUE);
  291      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio4B), TRUE);
  292 
  293      if(Closure->redundancy) g_free(Closure->redundancy);
  294      Closure->redundancy = g_strdup_printf("%dm", space);
  295       }
  296 
  297       UpdateMethodPreferences();
  298    }
  299 }
  300 
  301 /*
  302  * Sector prefetch selection
  303  */
  304 
  305 static gchar* format_cb(GtkScale *scale, gdouble value, gpointer data)
  306 {  char *label;
  307 
  308    switch(GPOINTER_TO_INT(data))
  309    {  case PREF_PRELOAD:
  310       case PREF_THREADS:
  311         label = g_strdup(" ");
  312         break;
  313       case PREF_NROOTS:
  314       {  int nroots = value;
  315      int ndata  = GF_FIELDMAX - nroots;
  316    
  317      label = g_strdup_printf(_utf("%4.1f%% redundancy (%d roots)"),
  318                  ((double)nroots*100.0)/(double)ndata,
  319                 nroots);
  320       }
  321     break;
  322       default:
  323        label = g_strdup(" ");
  324        break;
  325    }
  326 #if 0
  327      label = g_strdup_printf(_utf("%4.1f%% redundancy (%d roots)"),
  328                 ((double)nroots*100.0)/(double)ndata,
  329                 nroots);
  330 #endif
  331    FORGET(label);  /* will be g_free()ed by the scale */
  332    return label;
  333 }
  334 
  335 static void prefetch_cb(GtkWidget *widget, gpointer data)
  336 {  RS03Widgets *wl = (RS03Widgets*)data;
  337    LabelWithOnlineHelp *lwoh = wl->prefetchLwoh;
  338    int value;
  339    char *text, *utf;
  340 
  341    value = gtk_range_get_value(GTK_RANGE(widget));
  342    Closure->prefetchSectors = prefetch_size[value];
  343 
  344    text = g_strdup_printf(_("%d sectors"), Closure->prefetchSectors);
  345    utf  = g_locale_to_utf8(text, -1, NULL, NULL, NULL);
  346    gtk_label_set_markup(GTK_LABEL(lwoh->normalLabel), utf);
  347    gtk_label_set_markup(GTK_LABEL(lwoh->linkLabel), utf);
  348    SetOnlineHelpLinkText(lwoh, text);
  349    UpdateMethodPreferences();
  350    g_free(text);
  351    g_free(utf);
  352 }
  353 
  354 static void threads_cb(GtkWidget *widget, gpointer data)
  355 {  RS03Widgets *wl = (RS03Widgets*)data;
  356    LabelWithOnlineHelp *lwoh = wl->threadsLwoh;
  357    int value;
  358    char *text, *utf;
  359 
  360    value = gtk_range_get_value(GTK_RANGE(widget));
  361    Closure->codecThreads = threads_count[value];
  362 
  363    text = g_strdup_printf(_("%d threads"), Closure->codecThreads);
  364    utf  = g_locale_to_utf8(text, -1, NULL, NULL, NULL);
  365    gtk_label_set_markup(GTK_LABEL(lwoh->normalLabel), utf);
  366    gtk_label_set_markup(GTK_LABEL(lwoh->linkLabel), utf);
  367    SetOnlineHelpLinkText(lwoh, text);
  368    UpdateMethodPreferences();
  369    g_free(text);
  370    g_free(utf);
  371 }
  372 
  373 /* 
  374  * Some values may be shared with other codecs.
  375  * If they changed there, update our preferences page.
  376  */
  377 
  378 void ResetRS03PrefsPage(Method *method)
  379 {  RS03Widgets *wl = (RS03Widgets*)method->widgetList;
  380    int index;
  381 
  382    /* Error correction file redundancy */
  383 
  384    if(Closure->redundancy)
  385    {  
  386       if(!strcmp(Closure->redundancy, "normal"))
  387       {  if(wl->radio1A && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wl->radio1A)) == FALSE)
  388      {  activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio1A), TRUE);
  389             activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio1B), TRUE);
  390      }
  391       }
  392       else if(!strcmp(Closure->redundancy, "high"))
  393       {  if(wl->radio2A && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wl->radio2A)) == FALSE)
  394      {  activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio2A), TRUE);
  395         activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio2B), TRUE);
  396      }
  397       }
  398       else
  399       {  int last = strlen(Closure->redundancy)-1;
  400 
  401          if(Closure->redundancy[last] == 'm')
  402      {  if(wl->redundancySpinA)
  403         {  int old = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(wl->redundancySpinA));
  404            int new;
  405 
  406            Closure->redundancy[last] = 0;
  407            new = atoi(Closure->redundancy);
  408            Closure->redundancy[last] = 'm';
  409 
  410            if(new != old)
  411            {  set_spin_button_value(GTK_SPIN_BUTTON(wl->redundancySpinA), new);
  412           set_spin_button_value(GTK_SPIN_BUTTON(wl->redundancySpinB), new);
  413            }
  414 
  415            if(wl->radio4A && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wl->radio4A)) == FALSE)
  416            {  activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio4A), TRUE);
  417           activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio4B), TRUE);
  418            }
  419         }
  420      }
  421      else
  422      {  if(wl->redundancyScaleA)
  423         {  int old = gtk_range_get_value(GTK_RANGE(wl->redundancyScaleA));
  424            int new = atoi(Closure->redundancy);
  425 
  426            if(new != old)
  427            {  set_range_value(GTK_RANGE(wl->redundancyScaleA), new);
  428               set_range_value(GTK_RANGE(wl->redundancyScaleB), new);
  429            }
  430 
  431            if(wl->radio3A && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wl->radio3A)) == FALSE)
  432            {  activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio3A), TRUE);
  433           activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio3B), TRUE);
  434            }
  435         }
  436      }
  437       }
  438    }
  439 
  440    /* Prefetching */
  441 
  442    for(index = 0; index < sizeof(prefetch_size)/sizeof(int); index++)
  443      if(prefetch_size[index] > Closure->prefetchSectors)
  444        break;
  445 
  446    set_range_value(GTK_RANGE(wl->prefetchScaleA), index > 0 ? index-1 : index);
  447    set_range_value(GTK_RANGE(wl->prefetchScaleB), index > 0 ? index-1 : index);
  448 
  449    /* Number of threads */
  450 
  451    for(index = 0; index < sizeof(threads_count)/sizeof(int); index++)
  452      if(threads_count[index] > Closure->codecThreads)
  453        break;
  454 
  455    set_range_value(GTK_RANGE(wl->threadsScaleA), index > 0 ? index-1 : index);
  456    set_range_value(GTK_RANGE(wl->threadsScaleB), index > 0 ? index-1 : index);
  457 }
  458 
  459 /*
  460  * Read values from our preferences page
  461  * to make sure that all changed values from text entries
  462  * are recognized.
  463  */
  464 
  465 void ReadRS03Preferences(Method *method)
  466 {
  467 #if 0
  468    RS03Widgets *wl = (RS03Widgets*)method->widgetList;
  469 #endif
  470 }
  471 
  472 /*
  473  * Create our preferences page
  474  */
  475 
  476 void CreateRS03PrefsPage(Method *method, GtkWidget *parent)
  477 {  RS03Widgets *wl = (RS03Widgets*)method->widgetList;
  478    GtkWidget *frame, *hbox, *vbox, *lab, *scale, *spin, *radio;
  479    LabelWithOnlineHelp *lwoh;
  480    unsigned int index;
  481    char *text;
  482    int i;
  483 
  484    /*** Target for error correction data */
  485 
  486    frame = gtk_frame_new(_utf("Error correction data storage"));
  487    gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
  488 
  489    vbox = gtk_vbox_new(FALSE, 10);
  490    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
  491    gtk_container_add(GTK_CONTAINER(frame), vbox);
  492 
  493    lwoh = CreateLabelWithOnlineHelp(_("Error correction data storage"), 
  494                     _("Store ECC data in: "));
  495    RegisterPreferencesHelpWindow(lwoh);
  496 
  497    for(i=0; i<2; i++)
  498    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  499       GtkWidget *radio1, *radio2;
  500 
  501       gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
  502 
  503       radio1 = gtk_radio_button_new(NULL);
  504       g_signal_connect(G_OBJECT(radio1), "toggled", G_CALLBACK(eccmethod_cb), (gpointer)wl);
  505       gtk_box_pack_start(GTK_BOX(hbox), radio1, FALSE, FALSE, 0);
  506       lab = gtk_label_new(_utf("File"));
  507       gtk_container_add(GTK_CONTAINER(radio1), lab);
  508 
  509       radio2 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio1));
  510       g_signal_connect(G_OBJECT(radio2), "toggled", G_CALLBACK(eccmethod_cb), (gpointer)wl);
  511       gtk_box_pack_start(GTK_BOX(hbox), radio2, FALSE, FALSE, 0);
  512       lab = gtk_label_new(_utf("Image"));
  513       gtk_container_add(GTK_CONTAINER(radio2), lab);
  514 
  515       switch(Closure->eccTarget)
  516       {  case ECC_FILE: activate_toggle_button(GTK_TOGGLE_BUTTON(radio1), TRUE); break;
  517          case ECC_IMAGE: activate_toggle_button(GTK_TOGGLE_BUTTON(radio2), TRUE); break;
  518       }
  519 
  520       if(!i)
  521       {  wl->eccFileA  = radio1;
  522      wl->eccImageA = radio2;
  523      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  524       }
  525       else  
  526       {  wl->eccFileB  = radio1;
  527      wl->eccImageB = radio2;
  528      AddHelpWidget(lwoh, hbox);
  529       }
  530    }
  531 
  532    AddHelpParagraph(lwoh, 
  533             _("<b>Error correction data storage</b>\n\n"
  534               "Select between two ways of storing the "
  535               "error correction information:\n"));
  536 
  537    
  538     AddHelpListItem(lwoh, _("Augmented image (recommended)\n"
  539                "The error correction data will be stored along with the user data on the "
  540                "same medium. This requires the creation of an image file prior to writing the "
  541                "medium. The error correction data will be appended to that image "
  542                "and fill up the remaining space.\n"
  543                "Damaged sectors in the error correction "
  544                "information reduce the data recovery capacity, but do not make recovery "
  545                "impossible - a second medium for keeping or protecting the error correction "
  546                "information is not required.\n"));
  547 
  548   AddHelpListItem(lwoh, _("Error correction file\n"
  549                "Error correction files are the only way of protecting existing media "
  550                "as they can be stored somewhere else. They are kept on a separate "
  551                "medium which must also be protected by dvdisaster. This prevents from losing the "
  552                "error correction files in case of a medium defect.\n"));
  553 
  554       /*** Redundancy selection */
  555 
  556    frame = gtk_frame_new(_utf("Redundancy for new error correction files"));
  557    gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
  558 
  559    /* Notebook for disabling redundancy selection for embedded images */
  560       
  561    wl->redundancyNotebook = gtk_notebook_new();
  562    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(wl->redundancyNotebook), FALSE);
  563    gtk_notebook_set_show_border(GTK_NOTEBOOK(wl->redundancyNotebook), FALSE);
  564    gtk_container_add(GTK_CONTAINER(frame), wl->redundancyNotebook);
  565 
  566    /* dummy page for augmented images */
  567 
  568    lab = gtk_label_new(_utf("no settings for augmented images"));
  569    gtk_notebook_append_page(GTK_NOTEBOOK(wl->redundancyNotebook), lab, 
  570                 gtk_label_new(""));
  571 
  572    g_idle_add(notebook_idle_func, wl); /* defer notebook page activation */
  573 
  574    /* real entry for error correction files */
  575 
  576    vbox = gtk_vbox_new(FALSE, 10);
  577    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
  578    gtk_notebook_append_page(GTK_NOTEBOOK(wl->redundancyNotebook), vbox, 
  579                 gtk_label_new(""));
  580 
  581    /* Normal redundancy */
  582 
  583    lwoh = CreateLabelWithOnlineHelp(_("Normal redundancy"), _("Normal"));
  584    RegisterPreferencesHelpWindow(lwoh);
  585 
  586    for(i=0; i<2; i++)
  587    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  588 
  589       radio = gtk_radio_button_new(NULL);
  590       g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_cb), method);
  591       gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
  592 
  593       if(!i)
  594       {  wl->radio1A = radio;
  595      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  596      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  597       }
  598       else
  599       {  wl->radio1B = radio;
  600          gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  601      AddHelpWidget(lwoh, hbox);
  602       }
  603    }
  604 
  605    AddHelpParagraph(lwoh, _("<b>Normal redundancy</b>\n\n"
  606                 "The preset \"normal\" creates a redundancy of 14.3%%.\n"
  607                 "It invokes optimized program code to speed up the "
  608                 "error correction file creation."));
  609 
  610    /* High redundancy */
  611 
  612    lwoh = CreateLabelWithOnlineHelp(_("High redundancy"), _("High"));
  613    RegisterPreferencesHelpWindow(lwoh);
  614 
  615    for(i=0; i<2; i++)
  616    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  617 
  618       radio = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(i?wl->radio1B:wl->radio1A));
  619       g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_cb), method);
  620       gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
  621 
  622       if(!i)
  623       {  wl->radio2A = radio;
  624      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  625      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  626       }
  627       else
  628       {  wl->radio2B = radio;
  629          gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  630      AddHelpWidget(lwoh, hbox);
  631       }
  632    }
  633 
  634    AddHelpParagraph(lwoh, _("<b>High redundancy</b>\n\n"
  635                 "The preset \"high\" creates a redundancy of 33.5%%.\n"
  636                 "It invokes optimized program code to speed up the "
  637                 "error correction file creation."));
  638 
  639 
  640    /* User-selected redundancy */
  641 
  642    lwoh = CreateLabelWithOnlineHelp(_("Other redundancy"), _("Other"));
  643    RegisterPreferencesHelpWindow(lwoh);
  644 
  645    for(i=0; i<2; i++)
  646    {  hbox = gtk_hbox_new(FALSE, 4);
  647 
  648       radio = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(i?wl->radio1B:wl->radio1A));
  649       g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_cb), method);
  650       gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
  651 
  652       if(!i)
  653       {  wl->radio3A = radio;
  654      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  655       }
  656       else
  657       {  wl->radio3B = radio;
  658          gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  659       }
  660 
  661       scale = gtk_hscale_new_with_range(8,170,1);
  662       gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT);
  663       gtk_range_set_increments(GTK_RANGE(scale), 1, 1);
  664       gtk_range_set_value(GTK_RANGE(scale), 32);
  665       gtk_widget_set_sensitive(scale, FALSE);
  666       g_signal_connect(scale, "format-value", G_CALLBACK(format_cb), (gpointer)PREF_NROOTS);
  667       g_signal_connect(scale, "value-changed", G_CALLBACK(nroots_cb), (gpointer)wl);
  668       gtk_container_add(GTK_CONTAINER(hbox), scale);
  669 
  670       if(!i)
  671       {  wl->redundancyScaleA = scale;
  672      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  673       }
  674       else
  675       {  wl->redundancyScaleB = scale;
  676      AddHelpWidget(lwoh, hbox);
  677       }
  678    }
  679 
  680    AddHelpParagraph(lwoh, _("<b>Other redundancy</b>\n\n"
  681                 "Specifies the redundancy by percent.\n"
  682                 "An error correction file with x%% redundancy "
  683                 "will be approximately x%% of the size of the "
  684                 "corresponding image file."));
  685 
  686    /* Space-delimited redundancy */
  687 
  688    lwoh = CreateLabelWithOnlineHelp(_("Space-delimited redundancy"), _("Use at most"));
  689    RegisterPreferencesHelpWindow(lwoh);
  690 
  691    for(i=0; i<2; i++)
  692    {  hbox = gtk_hbox_new(FALSE, 4);
  693 
  694       radio = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(i?wl->radio1B:wl->radio1A));
  695       g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_cb), method);
  696       gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
  697 
  698       if(!i)
  699       {  wl->radio4A = radio;
  700      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  701       }
  702       else
  703       {  wl->radio4B = radio;
  704          gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  705       }
  706 
  707       spin = gtk_spin_button_new_with_range(0, 100000, 100);
  708       g_signal_connect(spin, "value-changed", G_CALLBACK(ecc_size_cb), (gpointer)wl);
  709       gtk_entry_set_width_chars(GTK_ENTRY(spin), 8);
  710       gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
  711 
  712       lab = gtk_label_new(_utf("MiB for error correction data"));
  713       gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0);
  714       gtk_widget_set_sensitive(spin, FALSE);
  715       gtk_widget_set_sensitive(lab, FALSE);
  716 
  717       if(!i)
  718       {  wl->redundancySpinA = spin;
  719      wl->radio4LabelA = lab;
  720          gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  721       }
  722       else
  723       {  wl->redundancySpinB = spin;
  724      wl->radio4LabelB = lab;
  725      AddHelpWidget(lwoh, hbox);
  726       }
  727    }
  728 
  729    AddHelpParagraph(lwoh, _("<b>Space-delimited redundancy</b>\n\n"
  730                 "Specifies the maximum size of the error correction file in MiB. "
  731                 "dvdisaster will choose a suitable redundancy setting so that "
  732                 "the overall size of the error correction file does not exceed "
  733                 "the given limit.\n\n"
  734                 "<b>Advance notice:</b> When using the same size setting for "
  735                 "images of vastly different size, smaller images receive more "
  736                 "redundancy than larger ones. This is usually not what you want."));
  737 
  738    /* Preset redundancy values
  739       FIXME: replace by ResetRS03Prefs()? */
  740 
  741    if(Closure->redundancy)
  742    {  if(!strcmp(Closure->redundancy, "normal"))
  743       {  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio1A), TRUE);
  744          gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio1B), TRUE);
  745       }
  746       else if(!strcmp(Closure->redundancy, "high"))
  747       {  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio2A), TRUE);
  748          gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio2B), TRUE);
  749       }
  750       else
  751       {  int last = strlen(Closure->redundancy)-1;
  752 
  753          if(Closure->redundancy[last] == 'm')
  754      {  Closure->redundancy[last] = 0;
  755         gtk_spin_button_set_value(GTK_SPIN_BUTTON(wl->redundancySpinA), atoi(Closure->redundancy));
  756         gtk_spin_button_set_value(GTK_SPIN_BUTTON(wl->redundancySpinB), atoi(Closure->redundancy));
  757         Closure->redundancy[last] = 'm';
  758         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio4A), TRUE);
  759         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio4B), TRUE);
  760      }
  761      else
  762      {  gtk_range_set_value(GTK_RANGE(wl->redundancyScaleA), atoi(Closure->redundancy));
  763         gtk_range_set_value(GTK_RANGE(wl->redundancyScaleB), atoi(Closure->redundancy));
  764         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio3A), TRUE);
  765         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio3B), TRUE);
  766      }
  767       }
  768    }
  769 
  770    /*** IO parameters */
  771 
  772    /* Prefetch sectors */
  773 
  774    frame = gtk_frame_new(_utf("I/O parameters"));
  775    gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
  776 
  777    vbox = gtk_vbox_new(FALSE, 10);
  778    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
  779    gtk_container_add(GTK_CONTAINER(frame), vbox);
  780 
  781    text = g_strdup_printf(_("%d sectors"), Closure->prefetchSectors);
  782    lwoh = CreateLabelWithOnlineHelp(_("Sector preloading"), text);
  783    RegisterPreferencesHelpWindow(lwoh);
  784    g_free(text);
  785 
  786    wl->prefetchLwoh = lwoh;
  787    LockLabelSize(GTK_LABEL(lwoh->normalLabel), _utf("%d sectors"), 2222);
  788    LockLabelSize(GTK_LABEL(lwoh->linkLabel), _utf("%d sectors"), 2222);
  789 
  790    for(i=0; i<2; i++)
  791    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  792       int n_entries = sizeof(prefetch_size)/sizeof(int);
  793 
  794       lab = gtk_label_new(_utf("Preload"));
  795       gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0);
  796 
  797       for(index = 0; index < n_entries; index++)
  798     if(prefetch_size[index] > Closure->prefetchSectors)
  799       break;
  800 
  801       scale = gtk_hscale_new_with_range(0,n_entries-1,1);
  802       gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT);
  803       gtk_range_set_increments(GTK_RANGE(scale), 1, 1);
  804       gtk_range_set_value(GTK_RANGE(scale), index > 0 ? index-1 : index);
  805       g_signal_connect(scale, "format-value", G_CALLBACK(format_cb), (gpointer)PREF_PRELOAD);
  806       g_signal_connect(scale, "value-changed", G_CALLBACK(prefetch_cb), (gpointer)wl);
  807       gtk_box_pack_start(GTK_BOX(hbox), scale, TRUE, TRUE, 0);
  808 
  809       if(!i)
  810       {  wl->prefetchScaleA = scale; 
  811      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  812      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  813       }
  814       else
  815       {  wl->prefetchScaleB = scale; 
  816      gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  817      AddHelpWidget(lwoh, hbox);
  818       }
  819    }
  820 
  821    AddHelpParagraph(lwoh, _("<b>Sector preloading</b>\n\n"
  822                 "dvdisaster optimizes access to the image and error correction "
  823                 "data by preloading and caching parts of them.\n\n"
  824                 "The optimal preload value depends on the storage system "
  825                 "used for the image and error correction files.\n"
  826                 "Use small preload values for systems with low latency "
  827                 "and seek time, e.g. SSDs. For magnetic hard disks "
  828                 "performance may be better using larger preload values.\n\n"
  829                 "A preload value of n will used approx. n MiB of RAM."));
  830 
  831    /*** IO strategy */
  832 
  833    lwoh = CreateLabelWithOnlineHelp(_("I/O strategy"), 
  834                     _("I/O strategy: "));
  835    RegisterPreferencesHelpWindow(lwoh);
  836 
  837    for(i=0; i<2; i++)
  838    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  839       GtkWidget *radio1, *radio2;
  840 
  841       gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
  842 
  843       radio1 = gtk_radio_button_new(NULL);
  844       g_signal_connect(G_OBJECT(radio1), "toggled", G_CALLBACK(io_strategy_cb), (gpointer)wl);
  845       gtk_box_pack_start(GTK_BOX(hbox), radio1, FALSE, FALSE, 0);
  846       lab = gtk_label_new(_utf("read/write"));
  847       gtk_container_add(GTK_CONTAINER(radio1), lab);
  848 
  849       radio2 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio1));
  850       g_signal_connect(G_OBJECT(radio2), "toggled", G_CALLBACK(io_strategy_cb), (gpointer)wl);
  851       gtk_box_pack_start(GTK_BOX(hbox), radio2, FALSE, FALSE, 0);
  852       lab = gtk_label_new(_utf("memory mapped"));
  853       gtk_container_add(GTK_CONTAINER(radio2), lab);
  854 
  855       switch(Closure->encodingIOStrategy)
  856       {  case IO_STRATEGY_READWRITE: activate_toggle_button(GTK_TOGGLE_BUTTON(radio1), TRUE); break;
  857          case IO_STRATEGY_MMAP:      activate_toggle_button(GTK_TOGGLE_BUTTON(radio2), TRUE); break;
  858       }
  859 
  860       if(!i)
  861       {  wl->ioRadio1A = radio1;
  862      wl->ioRadio2A = radio2;
  863      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  864       }
  865       else  
  866       {  wl->ioRadio1B = radio1;
  867      wl->ioRadio2B = radio2;
  868      AddHelpWidget(lwoh, hbox);
  869       }
  870    }
  871 
  872    AddHelpParagraph(lwoh, _("<b>I/O strategy</b>\n\n"
  873      "This option controls how dvdisaster performs its disk I/O while creating error "
  874      "correction data. Try both options and see which performs best on your hardware "
  875      "setting.\n\n" 
  876      "The <b>read/write</b> option activates dvdisaster's own I/O scheduler "
  877      "which reads and writes image data using normal file I/O. The advantage of this "
  878      "scheme is that dvdisaster knows exactly which data needs to be cached and preloaded; "
  879      "the disadvantage is that all data needs to be copied between the kernel and "
  880      "dvdisaster's own buffers. Usually, this I/O scheme works best on slow storage "
  881      "with high latency and seek times; e.g. on all storage involving spinning platters.\n\n"
  882      "The <b>memory mapped</b> option uses the kernel's memory mapping scheme for direct access "
  883      "to the image file. This has the advantage of minimal overhead, but may be adversely "
  884      "affected by poor caching and preloading decisions made by the kernel (since the kernel does not "
  885      "know what dvdisaster is going to do with the data). This scheme "
  886      "performs well when encoding in a RAM-based file system (such as /dev/shm on GNU/Linux) "
  887      "and on very fast media with low latency such as SSDs."
  888                 ));
  889 
  890    /*** Number of threads */
  891 
  892    frame = gtk_frame_new(_utf("Multithreading"));
  893    gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
  894 
  895    text = g_strdup_printf(_("%d threads"), Closure->codecThreads);
  896    lwoh = CreateLabelWithOnlineHelp(_("Multithreading"), text);
  897    RegisterPreferencesHelpWindow(lwoh);
  898    g_free(text);
  899 
  900    wl->threadsLwoh = lwoh;
  901    LockLabelSize(GTK_LABEL(lwoh->normalLabel), _utf("%d threads"), 22);
  902    LockLabelSize(GTK_LABEL(lwoh->linkLabel), _utf("%d threads"), 22);
  903 
  904    for(i=0; i<2; i++)
  905    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  906       int n_entries = sizeof(threads_count)/sizeof(int);
  907 
  908       lab = gtk_label_new(_utf("Use"));
  909       gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0);
  910 
  911       for(index = 0; index < n_entries; index++)
  912     if(threads_count[index] > Closure->codecThreads)
  913       break;
  914 
  915       scale = gtk_hscale_new_with_range(0,n_entries-1,1);
  916       gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT);
  917       gtk_range_set_increments(GTK_RANGE(scale), 1, 1);
  918       gtk_range_set_value(GTK_RANGE(scale), index > 0 ? index-1 : index);
  919       g_signal_connect(scale, "format-value", G_CALLBACK(format_cb), (gpointer)PREF_THREADS);
  920       g_signal_connect(scale, "value-changed", G_CALLBACK(threads_cb), (gpointer)wl);
  921       gtk_box_pack_start(GTK_BOX(hbox), scale, TRUE, TRUE, 0);
  922 
  923       if(!i)
  924       {  wl->threadsScaleA = scale; 
  925      gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
  926      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  927      gtk_container_add(GTK_CONTAINER(frame), hbox);
  928       }
  929       else
  930       {  wl->threadsScaleB = scale; 
  931      gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  932      AddHelpWidget(lwoh, hbox);
  933       }
  934    }
  935 
  936    AddHelpParagraph(lwoh, _("<b>Multithreading</b>\n\n"
  937                 "RS03 can use multiple threads (and therefore CPU cores)"
  938                 "for encoding.\n"
  939                 "For systems with 4 cores or less, set the number of "
  940                 "threads to the number of cores. If you have more cores, "
  941                 "leave one unused for doing I/O and graphics updates.\n"
  942                 "E.g. use 7 threads on an 8 core system.\n\n"
  943                 "Performance will not scale linearly "
  944                 "with the number of CPU cores. Hard disk performance "
  945                 "is more limiting than raw CPU power. When using "
  946                 "4 cores or more, memory bandwidth may also affect "
  947                 "performance."));
  948 
  949    /*** Codec type */
  950 
  951    frame = gtk_frame_new(_utf("Encoding algorithm"));
  952    gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
  953 
  954    vbox = gtk_vbox_new(FALSE, 10);
  955    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
  956    gtk_container_add(GTK_CONTAINER(frame), vbox);
  957 
  958    lwoh = CreateLabelWithOnlineHelp(_("Encoding algorithm"), 
  959                     _("Use: "));
  960    RegisterPreferencesHelpWindow(lwoh);
  961 
  962    for(i=0; i<2; i++)
  963    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  964       GtkWidget *radio1, *radio2, *radio3=NULL, *radio4;
  965 
  966       gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
  967 
  968       radio1 = gtk_radio_button_new(NULL);
  969       g_signal_connect(G_OBJECT(radio1), "toggled", G_CALLBACK(encoding_alg_cb), (gpointer)wl);
  970       gtk_box_pack_start(GTK_BOX(hbox), radio1, FALSE, FALSE, 0);
  971       lab = gtk_label_new(_utf("32bit"));
  972       gtk_container_add(GTK_CONTAINER(radio1), lab);
  973 
  974       radio2 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio1));
  975       g_signal_connect(G_OBJECT(radio2), "toggled", G_CALLBACK(encoding_alg_cb), (gpointer)wl);
  976       gtk_box_pack_start(GTK_BOX(hbox), radio2, FALSE, FALSE, 0);
  977       lab = gtk_label_new(_utf("64bit"));
  978       gtk_container_add(GTK_CONTAINER(radio2), lab);
  979 
  980       if(Closure->useSSE2)
  981       {  radio3 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio2));
  982      g_signal_connect(G_OBJECT(radio3), "toggled", G_CALLBACK(encoding_alg_cb), (gpointer)wl);
  983      gtk_box_pack_start(GTK_BOX(hbox), radio3, FALSE, FALSE, 0);
  984      lab = gtk_label_new(_utf("SSE2"));
  985      gtk_container_add(GTK_CONTAINER(radio3), lab);
  986       }
  987       if(Closure->useAltiVec)
  988       {  radio3 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio2));
  989      g_signal_connect(G_OBJECT(radio3), "toggled", G_CALLBACK(encoding_alg_cb), (gpointer)wl);
  990      gtk_box_pack_start(GTK_BOX(hbox), radio3, FALSE, FALSE, 0);
  991      lab = gtk_label_new(_utf("AltiVec"));
  992      gtk_container_add(GTK_CONTAINER(radio3), lab);
  993       }
  994 
  995       radio4 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio2));
  996       g_signal_connect(G_OBJECT(radio4), "toggled", G_CALLBACK(encoding_alg_cb), (gpointer)wl);
  997       gtk_box_pack_start(GTK_BOX(hbox), radio4, FALSE, FALSE, 0);
  998       lab = gtk_label_new(_utf("auto"));
  999       gtk_container_add(GTK_CONTAINER(radio4), lab);
 1000 
 1001       switch(Closure->encodingAlgorithm)
 1002       {  case ENCODING_ALG_DEFAULT: activate_toggle_button(GTK_TOGGLE_BUTTON(radio4), TRUE); break;
 1003          case ENCODING_ALG_32BIT:   activate_toggle_button(GTK_TOGGLE_BUTTON(radio1), TRUE); break;
 1004          case ENCODING_ALG_64BIT:   activate_toggle_button(GTK_TOGGLE_BUTTON(radio2), TRUE); break;
 1005          case ENCODING_ALG_SSE2:    
 1006          case ENCODING_ALG_ALTIVEC: activate_toggle_button(GTK_TOGGLE_BUTTON(radio3), TRUE); break;
 1007       }
 1008 
 1009       if(!i)
 1010       {  wl->eaRadio1A = radio1;
 1011      wl->eaRadio2A = radio2;
 1012      wl->eaRadio3A = radio3;
 1013      wl->eaRadio4A = radio4;
 1014      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 1015       }
 1016       else  
 1017       {  wl->eaRadio1B = radio1;
 1018      wl->eaRadio2B = radio2;
 1019      wl->eaRadio3B = radio3;
 1020      wl->eaRadio4B = radio4;
 1021      AddHelpWidget(lwoh, hbox);
 1022       }
 1023    }
 1024 
 1025    AddHelpParagraph(lwoh, _("<b>Encoding algorithm</b>\n\n"
 1026      "This option affects the speed of generating RS03 error correction data.\n"
 1027      "dvdisaster can either use a generic encoding algorithm using 32bit or 64bit "
 1028      "wide operations running on the integer unit of the processor, or use "
 1029      "processor specific extensions.\n\n"
 1030      "Available extensions are SSE2 for x86 based processors and AltiVec "
 1031      "on PowerPC processors. These extensions encode with 128bit wide operations "
 1032      "and will usually provide the fastest encoding variant. If \"auto\" is selected, the "
 1033      "SSE2/AltiVec algorithms will be selected if the processor supports them; "
 1034      "otherwise the 64bit algorithm will be used."
 1035                 ));
 1036 }