"Fossies" - the Fresh Open Source Software Archive

Member "dvdisaster-0.79.5/rs01-window.c" (25 Sep 2015, 30016 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 "rs01-window.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes reports: 0.79.3_vs_0.79.5 or 0.72.6_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 "rs01-includes.h"
   26 
   27 /***
   28  *** Forward declarations
   29  ***/
   30 
   31 static void redraw_curve(RS01Widgets*);
   32 static void update_geometry(RS01Widgets*);
   33 
   34 /* Protected widget access */
   35       
   36 static void activate_toggle_button(GtkToggleButton *toggle, int state)
   37 {  if(toggle) gtk_toggle_button_set_active(toggle, state);
   38 }
   39 
   40 static void set_range_value(GtkRange *range, int value)
   41 {  if(range) gtk_range_set_value(range, value);
   42 }
   43 
   44 static void set_spin_button_value(GtkSpinButton *spin, int value)
   45 {  if(spin) gtk_spin_button_set_value(spin, value);
   46 }
   47 
   48 /***
   49  *** Encoding window
   50  ***/
   51 
   52 /*
   53  * Reset the notebook contents for new encoding action
   54  */
   55 
   56 void ResetRS01EncodeWindow(Method *method)
   57 {  RS01Widgets *wl = (RS01Widgets*)method->widgetList;
   58 
   59    SetProgress(wl->encPBar1, 0, 100);
   60    SetProgress(wl->encPBar2, 0, 100);
   61 
   62    gtk_widget_hide(wl->encLabel2);
   63    gtk_widget_hide(wl->encPBar2);
   64    gtk_widget_hide(wl->curveButton);
   65 
   66    gtk_label_set_text(GTK_LABEL(wl->encFootline), "");
   67    gtk_label_set_text(GTK_LABEL(wl->encFootline2), "");
   68 
   69 }
   70 
   71 /* 
   72  * Show the button for switching to the reading curve
   73  */
   74 
   75 static gboolean show_button_idle_func(gpointer data)
   76 {  Method *method = (Method*)data;
   77    RS01Widgets *wl = (RS01Widgets*)method->widgetList;
   78 
   79    gtk_widget_show(wl->curveButton);
   80 
   81    return FALSE;
   82 }
   83 
   84 void RS01ShowCurveButton(Method *method)
   85 {  
   86    g_idle_add(show_button_idle_func, method);
   87    
   88 }
   89 
   90 /* 
   91  * Switch back to the reading curve (read and create mode only)
   92  */
   93 
   94 static gboolean curve_button_cb(GtkWidget *wid, gpointer action)
   95 {  gtk_notebook_set_current_page(GTK_NOTEBOOK(Closure->notebook), 1);
   96   
   97    return FALSE;
   98 }
   99 
  100 /*
  101  * Create the notebook contents for creating an error correction file
  102  */
  103 
  104 void CreateRS01EWindow(Method *method, GtkWidget *parent)
  105 {  RS01Widgets *wl;
  106    GtkWidget *sep,*wid,*pbar,*table,*hbox;
  107 
  108    if(!method->widgetList)
  109    {  wl = g_malloc0(sizeof(RS01Widgets));
  110       method->widgetList = wl;
  111    }
  112    else wl = method->widgetList;
  113 
  114    wl->encHeadline = gtk_label_new(NULL);
  115    gtk_misc_set_alignment(GTK_MISC(wl->encHeadline), 0.0, 0.0); 
  116    gtk_misc_set_padding(GTK_MISC(wl->encHeadline), 5, 0);
  117    gtk_box_pack_start(GTK_BOX(parent), wl->encHeadline, FALSE, FALSE, 3);
  118 
  119    sep = gtk_hseparator_new();
  120    gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
  121 
  122    sep = gtk_hseparator_new();
  123    gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
  124 
  125    table = gtk_table_new(2, 2, FALSE);
  126    gtk_box_pack_start(GTK_BOX(parent), table, FALSE, FALSE, 30);
  127 
  128    wl->encLabel1 = wid = gtk_label_new(NULL);
  129    gtk_label_set_markup(GTK_LABEL(wid),
  130             _utf("<b>1. Calculating image sector checksums:</b>"));
  131    gtk_misc_set_alignment(GTK_MISC(wid), 0.0, 0.0);
  132    gtk_table_attach(GTK_TABLE(table), wid, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 20, 20);
  133 
  134    pbar = wl->encPBar1 = gtk_progress_bar_new();
  135    gtk_table_attach(GTK_TABLE(table), pbar, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 20, 20);
  136 
  137    wl->encLabel2 = wid = gtk_label_new(NULL);
  138    gtk_label_set_markup(GTK_LABEL(wid),
  139             _utf("<b>2. Creating error correction data:</b>"));
  140    gtk_misc_set_alignment(GTK_MISC(wid), 0.0, 0.0);
  141    gtk_table_attach(GTK_TABLE(table), wid, 0, 1, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 20, 20);
  142 
  143    pbar = wl->encPBar2 = gtk_progress_bar_new();
  144    gtk_table_attach(GTK_TABLE(table), pbar, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 20, 20);
  145 
  146    wl->encFootline = gtk_label_new(NULL);
  147    gtk_misc_set_alignment(GTK_MISC(wl->encFootline), 0.0, 0.5); 
  148    gtk_misc_set_padding(GTK_MISC(wl->encFootline), 20, 0);
  149    gtk_box_pack_start(GTK_BOX(parent), wl->encFootline, FALSE, FALSE, 3);
  150 
  151    wl->encFootline2 = gtk_label_new(NULL);
  152    gtk_misc_set_alignment(GTK_MISC(wl->encFootline2), 0.0, 0.5); 
  153    gtk_misc_set_padding(GTK_MISC(wl->encFootline2), 20, 0);
  154    gtk_box_pack_start(GTK_BOX(parent), wl->encFootline2, FALSE, FALSE, 3);
  155 
  156    hbox = gtk_hbox_new(FALSE, 0);
  157    gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
  158 
  159    wid = gtk_label_new(NULL);
  160    gtk_misc_set_padding(GTK_MISC(wid), 10, 0);
  161    gtk_box_pack_start(GTK_BOX(hbox), wid, FALSE, FALSE, 0);
  162 
  163    wl->curveButton = gtk_button_new_with_label(_utf("Show reading speed curve"));
  164    g_signal_connect(G_OBJECT(wl->curveButton), "clicked", G_CALLBACK(curve_button_cb), NULL);
  165    gtk_box_pack_start(GTK_BOX(hbox), wl->curveButton, FALSE, FALSE, 0);
  166 }
  167 
  168 /***
  169  *** "Fix" window
  170  ***/
  171 
  172 /*
  173  * Set the media size and ecc capacity
  174  */
  175 
  176 static gboolean set_max_idle_func(gpointer data)
  177 {  RS01Widgets *wl = (RS01Widgets*)data;
  178 
  179    redraw_curve(wl);
  180 
  181    return FALSE;
  182 }
  183 
  184 void RS01SetFixMaxValues(RS01Widgets *wl, int data_bytes, int ecc_bytes, gint64 sectors)
  185 {
  186    wl->dataBytes = data_bytes;
  187    wl->eccBytes  = ecc_bytes;
  188    wl->nSectors  = sectors;
  189    wl->fixCurve->maxX = 100;
  190    wl->fixCurve->maxY = ecc_bytes - (ecc_bytes % 5) + 5;
  191 
  192    g_idle_add(set_max_idle_func, wl);
  193 }
  194 
  195 /*
  196  * Update the corrected / uncorrected numbers
  197  */
  198 
  199 static gboolean results_idle_func(gpointer data)
  200 {  RS01Widgets *wl = (RS01Widgets*)data;
  201 
  202    SetLabelText(GTK_LABEL(wl->fixCorrected), _("Repaired: %lld"), wl->corrected); 
  203    SetLabelText(GTK_LABEL(wl->fixUncorrected), _("Unrepairable: <span %s>%lld</span>"),Closure->redMarkup, wl->uncorrected); 
  204    SetLabelText(GTK_LABEL(wl->fixProgress), _("Progress: %3d.%1d%%"), wl->percent/10, wl->percent%10);
  205 
  206    return FALSE;
  207 }
  208 
  209 void RS01UpdateFixResults(RS01Widgets *wl, gint64 corrected, gint64 uncorrected)
  210 {
  211    wl->corrected = corrected;
  212    wl->uncorrected = uncorrected;
  213 
  214    g_idle_add(results_idle_func, wl);
  215 }
  216 
  217 /*
  218  * Update the error curve 
  219  */
  220 
  221 static gboolean curve_idle_func(gpointer data)
  222 {  RS01Widgets *wl = (RS01Widgets*)data;
  223    gint x0 = CurveX(wl->fixCurve, (double)wl->lastPercent);
  224    gint x1 = CurveX(wl->fixCurve, (double)wl->percent);
  225    gint y = CurveY(wl->fixCurve, wl->fixCurve->ivalue[wl->percent]);
  226    gint i;
  227 
  228    /*** Mark unused ecc values */
  229 
  230    for(i=wl->lastPercent+1; i<wl->percent; i++)
  231       wl->fixCurve->ivalue[i] = wl->fixCurve->ivalue[wl->percent];
  232 
  233    /*** Resize the Y axes if error values exceeds current maximum */
  234 
  235    if(wl->fixCurve->ivalue[wl->percent] > wl->fixCurve->maxY)
  236    {  wl->fixCurve->maxY = wl->fixCurve->ivalue[wl->percent];
  237       wl->fixCurve->maxY = wl->fixCurve->maxY - (wl->fixCurve->maxY % 5) + 5;
  238 
  239       update_geometry(wl);
  240       gdk_window_clear(wl->fixCurve->widget->window);
  241       redraw_curve(wl);
  242       wl->lastPercent = wl->percent;
  243 
  244       return FALSE;
  245    }
  246 
  247    /*** Draw the error value */
  248 
  249    if(wl->fixCurve->ivalue[wl->percent] > 0)
  250    {  gdk_gc_set_rgb_fg_color(Closure->drawGC, Closure->barColor);
  251       gdk_draw_rectangle(wl->fixCurve->widget->window,
  252              Closure->drawGC, TRUE,
  253              x0, y, x0==x1 ? 1 : x1-x0, wl->fixCurve->bottomY-y);
  254    }
  255    wl->lastPercent = wl->percent;
  256 
  257    /* Redraw the ecc capacity threshold line */
  258 
  259    y = CurveY(wl->fixCurve, wl->eccBytes);  
  260    gdk_gc_set_rgb_fg_color(Closure->drawGC, Closure->greenSector);
  261    gdk_draw_line(wl->fixCurve->widget->window,
  262          Closure->drawGC,
  263          wl->fixCurve->leftX-6, y, wl->fixCurve->rightX+6, y);
  264    return FALSE;
  265 }
  266 
  267 /* 
  268  * Add one new data point 
  269  */
  270 
  271 void RS01AddFixValues(RS01Widgets *wl, int percent, int ecc_max)
  272 {
  273    if(percent < 0 || percent > 1000)
  274      return;
  275 
  276    wl->fixCurve->ivalue[percent] = ecc_max;
  277    wl->percent = percent;
  278    g_idle_add(curve_idle_func, wl);
  279 }
  280   
  281 /*
  282  * Redraw the whole curve
  283  */
  284 
  285 /* Calculate the geometry of the curve and spiral */
  286 
  287 static void update_geometry(RS01Widgets *wl)
  288 {  
  289    /* Curve geometry */ 
  290 
  291    UpdateCurveGeometry(wl->fixCurve, "999", 20);
  292 
  293    /* Label positions in the foot line */
  294 
  295    gtk_box_set_child_packing(GTK_BOX(wl->fixFootlineBox), wl->fixCorrected,
  296                  TRUE, TRUE, wl->fixCurve->leftX, GTK_PACK_START);
  297    gtk_box_set_child_packing(GTK_BOX(wl->fixFootlineBox), wl->fixUncorrected, 
  298                  TRUE, TRUE, wl->fixCurve->leftX, GTK_PACK_START);
  299 }
  300 
  301 static void redraw_curve(RS01Widgets *wl)
  302 {  int y;
  303 
  304    /* Redraw the curve */
  305 
  306    RedrawAxes(wl->fixCurve);
  307    RedrawCurve(wl->fixCurve, wl->percent);
  308 
  309    /* Ecc capacity threshold line */
  310 
  311    y = CurveY(wl->fixCurve, wl->eccBytes);  
  312    gdk_gc_set_rgb_fg_color(Closure->drawGC, Closure->greenSector);
  313    gdk_draw_line(wl->fixCurve->widget->window,
  314          Closure->drawGC,
  315          wl->fixCurve->leftX-6, y, wl->fixCurve->rightX+6, y);
  316 }
  317 
  318 /*
  319  * Expose callback
  320  */
  321 
  322 static gboolean expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data)
  323 {  RS01Widgets *wl = (RS01Widgets*)data; 
  324 
  325    if(event->count) /* Exposure compression */
  326    {  return TRUE;
  327    }
  328 
  329    update_geometry(wl);
  330    redraw_curve(wl);
  331 
  332    return TRUE;
  333 }
  334 
  335 /*
  336  * Reset the notebook contents for new fixing action
  337  */
  338 
  339 void ResetRS01FixWindow(Method *method)
  340 {  RS01Widgets *wl = (RS01Widgets*)method->widgetList;
  341 
  342    gtk_notebook_set_current_page(GTK_NOTEBOOK(wl->fixNotebook), 0);
  343 
  344    ZeroCurve(wl->fixCurve);
  345    RS01UpdateFixResults(wl, 0, 0);
  346 
  347    if(wl->fixCurve && wl->fixCurve->widget)
  348    {  gdk_window_clear(wl->fixCurve->widget->window);
  349       redraw_curve(wl);
  350    }
  351 
  352    wl->percent = 0;
  353    wl->lastPercent = 0;
  354 }
  355 
  356 /*
  357  * Create the notebook contents for fixing an image
  358  */
  359 
  360 void CreateRS01FWindow(Method *method, GtkWidget *parent)
  361 {  RS01Widgets *wl;
  362    GtkWidget *sep,*ignore,*d_area,*notebook,*hbox;
  363 
  364    if(!method->widgetList)
  365    {  wl = g_malloc0(sizeof(RS01Widgets));
  366       method->widgetList = wl;
  367    }
  368    else wl = method->widgetList;
  369 
  370    wl->fixHeadline = gtk_label_new(NULL);
  371    gtk_misc_set_alignment(GTK_MISC(wl->fixHeadline), 0.0, 0.0); 
  372    gtk_misc_set_padding(GTK_MISC(wl->fixHeadline), 5, 0);
  373    gtk_box_pack_start(GTK_BOX(parent), wl->fixHeadline, FALSE, FALSE, 3);
  374 
  375    sep = gtk_hseparator_new();
  376    gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
  377 
  378    sep = gtk_hseparator_new();
  379    gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
  380 
  381    d_area = wl->fixDrawingArea = gtk_drawing_area_new();
  382    gtk_box_pack_start(GTK_BOX(parent), d_area, TRUE, TRUE, 0);
  383    g_signal_connect(G_OBJECT (d_area), "expose_event", G_CALLBACK(expose_cb), (gpointer)wl);
  384    
  385    notebook = wl->fixNotebook = gtk_notebook_new();
  386    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
  387    gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
  388    gtk_box_pack_end(GTK_BOX(parent), notebook, FALSE, FALSE, 0);
  389 
  390    hbox = wl->fixFootlineBox = gtk_hbox_new(TRUE, 0);
  391 
  392    wl->fixCorrected = gtk_label_new(NULL);
  393    gtk_misc_set_alignment(GTK_MISC(wl->fixCorrected), 0.0, 0.0); 
  394    gtk_box_pack_start(GTK_BOX(hbox), wl->fixCorrected, TRUE, TRUE, 0);
  395 
  396    wl->fixProgress = gtk_label_new(NULL);
  397    gtk_misc_set_alignment(GTK_MISC(wl->fixProgress), 0.5, 0.0); 
  398    gtk_box_pack_start(GTK_BOX(hbox), wl->fixProgress, TRUE, TRUE, 0);
  399 
  400    wl->fixUncorrected = gtk_label_new(NULL);
  401    gtk_misc_set_alignment(GTK_MISC(wl->fixUncorrected), 1.0, 0.0); 
  402    gtk_box_pack_start(GTK_BOX(hbox), wl->fixUncorrected, TRUE, TRUE, 0);
  403 
  404    ignore = gtk_label_new("progress_tab");
  405    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, ignore);
  406 
  407    wl->fixFootline = gtk_label_new("Footline");
  408    gtk_misc_set_alignment(GTK_MISC(wl->fixFootline), 0.0, 0.5); 
  409    gtk_misc_set_padding(GTK_MISC(wl->fixFootline), 5, 0);
  410    ignore = gtk_label_new("footer_tab");
  411    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), wl->fixFootline, ignore);
  412 
  413    wl->fixCurve  = CreateCurve(d_area, _("Errors/Ecc block"), "%d", 1000, CURVE_PERCENT);
  414    wl->fixCurve->enable = DRAW_ICURVE;
  415 }
  416 
  417 /***
  418  *** Create the preferences page for setting redundancy etc.
  419  ***/
  420 
  421 #define SYMBOLSIZE 8
  422 #define FIELDSIZE (1<<SYMBOLSIZE)
  423 #define FIELDMAX (FIELDSIZE-1)
  424 
  425 enum 
  426 {  PREF_NROOTS = 0,
  427    PREF_CACHE = 1,
  428    PREF_ECC_SIZE = 2
  429 };
  430 
  431 #ifdef HAVE_32BIT
  432 static int cache_size[] = { 8, 16, 32, 64, 96, 128, 192, 256, 384, 512, 768, 
  433                 1024, 1536 };
  434 #else
  435 static int cache_size[] = { 8, 16, 32, 64, 96, 128, 192, 256, 384, 512, 768, 
  436                 1024, 1536, 2048, 2560, 3072, 4096, 5120, 6144, 7168, 8192 };
  437 #endif
  438 
  439 static gchar* format_cb(GtkScale *scale, gdouble value, gpointer data)
  440 {  int nroots = value;
  441    int ndata  = FIELDMAX - nroots;
  442    char *label;
  443 
  444    if(GPOINTER_TO_INT(data) == PREF_CACHE)
  445    {
  446      label = g_strdup(" ");
  447    }
  448    else
  449      label = g_strdup_printf(_utf("%4.1f%% redundancy (%d roots)"),
  450                 ((double)nroots*100.0)/(double)ndata,
  451                 nroots);
  452 
  453    FORGET(label);  /* will be g_free()ed by the scale */
  454    return label;
  455 }
  456 
  457 static void cache_cb(GtkWidget *widget, gpointer data)
  458 {  RS01Widgets *wl = (RS01Widgets*)data;
  459    LabelWithOnlineHelp *lwoh = wl->cacheLwoh;
  460    int value;
  461    char *text, *utf;
  462 
  463    value = gtk_range_get_value(GTK_RANGE(widget));
  464    Closure->cacheMiB = cache_size[value];
  465     
  466    text = g_strdup_printf(_("%d MiB of file cache"), Closure->cacheMiB);
  467    utf  = g_locale_to_utf8(text, -1, NULL, NULL, NULL);
  468    gtk_label_set_markup(GTK_LABEL(lwoh->normalLabel), utf);
  469    gtk_label_set_markup(GTK_LABEL(lwoh->linkLabel), utf);
  470    SetOnlineHelpLinkText(lwoh, text);
  471    UpdateMethodPreferences();
  472    g_free(text);
  473    g_free(utf);
  474 }
  475 
  476 static void nroots_cb(GtkWidget *widget, gpointer data)
  477 {  RS01Widgets *wl = (RS01Widgets*)data;
  478    int value;
  479 
  480    value = gtk_range_get_value(GTK_RANGE(widget));
  481    if(Closure->redundancy) g_free(Closure->redundancy);
  482    Closure->redundancy = g_strdup_printf("%d", value);
  483 
  484    if(widget == wl->redundancyScaleA)
  485         set_range_value(GTK_RANGE(wl->redundancyScaleB), value);
  486    else set_range_value(GTK_RANGE(wl->redundancyScaleA), value);
  487 
  488    UpdateMethodPreferences();
  489 }
  490 
  491 static void ecc_size_cb(GtkWidget *widget, gpointer data)
  492 {  RS01Widgets *wl = (RS01Widgets*)data;
  493    int value;
  494 
  495    value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
  496    if(Closure->redundancy) g_free(Closure->redundancy);
  497    Closure->redundancy = g_strdup_printf("%dm", value);
  498 
  499    if(widget == wl->redundancySpinA)
  500         gtk_spin_button_set_value(GTK_SPIN_BUTTON(wl->redundancySpinB), atoi(Closure->redundancy));
  501    else gtk_spin_button_set_value(GTK_SPIN_BUTTON(wl->redundancySpinA), atoi(Closure->redundancy));
  502 
  503    UpdateMethodPreferences();
  504 }
  505 
  506 static void toggle_cb(GtkWidget *widget, gpointer data)
  507 {  Method *method = (Method*)data;
  508    RS01Widgets *wl = (RS01Widgets*)method->widgetList;
  509    int state  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  510       
  511    if(state == TRUE)
  512    {  if(widget == wl->radio3A || widget == wl->radio3B)
  513       {  gtk_widget_set_sensitive(wl->redundancyScaleA, TRUE);
  514      gtk_widget_set_sensitive(wl->redundancyScaleB, TRUE);
  515       }
  516       else
  517       {  gtk_widget_set_sensitive(wl->redundancyScaleA, FALSE);
  518      gtk_widget_set_sensitive(wl->redundancyScaleB, FALSE);
  519       }
  520 
  521       if(widget == wl->radio4A || widget == wl->radio4B)
  522       {  gtk_widget_set_sensitive(wl->redundancySpinA, TRUE); 
  523      gtk_widget_set_sensitive(wl->redundancySpinB, TRUE); 
  524      gtk_widget_set_sensitive(wl->radio4LabelA, TRUE); 
  525      gtk_widget_set_sensitive(wl->radio4LabelB, TRUE); 
  526       }
  527       else
  528       {  gtk_widget_set_sensitive(wl->redundancySpinA, FALSE); 
  529      gtk_widget_set_sensitive(wl->redundancySpinB, FALSE); 
  530      gtk_widget_set_sensitive(wl->radio4LabelA, FALSE); 
  531      gtk_widget_set_sensitive(wl->radio4LabelB, FALSE); 
  532       }
  533 
  534       if(   widget == wl->radio1A  /* Normal */
  535      || widget == wl->radio1B)
  536       {  
  537          set_range_value(GTK_RANGE(wl->redundancyScaleA), 32);
  538          set_range_value(GTK_RANGE(wl->redundancyScaleB), 32);
  539 
  540      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio1A), TRUE);
  541      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio1B), TRUE);
  542 
  543      if(Closure->redundancy) g_free(Closure->redundancy);
  544          Closure->redundancy = g_strdup("normal");
  545       }
  546 
  547       if(   widget == wl->radio2A  /* High */
  548      || widget == wl->radio2B)
  549       {  
  550          set_range_value(GTK_RANGE(wl->redundancyScaleA), 64);
  551          set_range_value(GTK_RANGE(wl->redundancyScaleB), 64);
  552 
  553      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio2A), TRUE);
  554      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio2B), TRUE);
  555 
  556      if(Closure->redundancy) g_free(Closure->redundancy);
  557      Closure->redundancy = g_strdup("high");
  558       }
  559 
  560       if(   widget == wl->radio3A  /* number of roots */
  561      || widget == wl->radio3B)
  562       {  int nroots = gtk_range_get_value(GTK_RANGE(wl->redundancyScaleA));
  563 
  564      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio3A), TRUE);
  565      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio3B), TRUE);
  566 
  567      if(Closure->redundancy) g_free(Closure->redundancy);
  568      Closure->redundancy = g_strdup_printf("%d", nroots);
  569       }
  570 
  571       if(   widget == wl->radio4A  /* relative to space usage */
  572      || widget == wl->radio4B)
  573       {  int space = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(wl->redundancySpinA));
  574 
  575      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio4A), TRUE);
  576      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio4B), TRUE);
  577 
  578      if(Closure->redundancy) g_free(Closure->redundancy);
  579      Closure->redundancy = g_strdup_printf("%dm", space);
  580       }
  581 
  582       UpdateMethodPreferences();
  583    }
  584 }
  585 
  586 void ResetRS01PrefsPage(Method *method)
  587 {  RS01Widgets *wl = (RS01Widgets*)method->widgetList;
  588    int index;
  589 
  590    /* Redundancy selection */
  591 
  592    if(Closure->redundancy)
  593    {  
  594       if(!strcmp(Closure->redundancy, "normal"))
  595       {  if(wl->radio1A && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wl->radio1A)) == FALSE)
  596      {  activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio1A), TRUE);
  597         activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio1B), TRUE);
  598      }
  599       }
  600       else if(!strcmp(Closure->redundancy, "high"))
  601       {  if(wl->radio2A && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wl->radio2A)) == FALSE)
  602      {  activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio2A), TRUE);
  603         activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio2B), TRUE);
  604      }
  605       }
  606       else
  607       {  int last = strlen(Closure->redundancy)-1;
  608 
  609          if(Closure->redundancy[last] == 'm')
  610      {  if(wl->redundancySpinA)
  611         {  int old = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(wl->redundancySpinA));
  612            int new;
  613 
  614            Closure->redundancy[last] = 0;
  615            new = atoi(Closure->redundancy);
  616            Closure->redundancy[last] = 'm';
  617 
  618            if(new != old)
  619            {  set_spin_button_value(GTK_SPIN_BUTTON(wl->redundancySpinA), new);
  620           set_spin_button_value(GTK_SPIN_BUTTON(wl->redundancySpinB), new);
  621            }
  622 
  623            if(wl->radio4A && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wl->radio4A)) == FALSE)
  624            {  activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio4A), TRUE);
  625           activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio4B), TRUE);
  626            }
  627         }
  628      }
  629      else
  630      {  if(wl->redundancyScaleA)
  631         {  int old = gtk_range_get_value(GTK_RANGE(wl->redundancyScaleA));
  632            int new = atoi(Closure->redundancy);
  633 
  634            if(new != old)
  635            {  set_range_value(GTK_RANGE(wl->redundancyScaleA), new);
  636               set_range_value(GTK_RANGE(wl->redundancyScaleB), new);
  637            }
  638 
  639            if(wl->radio3A && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(wl->radio3A)) == FALSE)
  640            {  activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio3A), TRUE);
  641           activate_toggle_button(GTK_TOGGLE_BUTTON(wl->radio3B), TRUE);
  642            }
  643         }
  644      }
  645       }
  646    }
  647 
  648    /* Memory caching */
  649 
  650    for(index = 0; index < sizeof(cache_size)/sizeof(int); index++)
  651      if(cache_size[index] > Closure->cacheMiB)
  652        break;
  653 
  654    set_range_value(GTK_RANGE(wl->cacheScaleA), index > 0 ? index-1 : index);
  655    set_range_value(GTK_RANGE(wl->cacheScaleB), index > 0 ? index-1 : index);
  656 }
  657 
  658 void CreateRS01PrefsPage(Method *method, GtkWidget *parent)
  659 {  RS01Widgets *wl = (RS01Widgets*)method->widgetList;
  660    GtkWidget *frame, *hbox, *vbox, *lab, *scale, *spin;
  661    GtkWidget *radio; 
  662    LabelWithOnlineHelp *lwoh;
  663    unsigned int i, index;
  664    char *text;
  665 
  666    /*** Redundancy selection */
  667 
  668    frame = gtk_frame_new(_utf("Redundancy for new error correction files"));
  669    gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
  670 
  671    vbox = gtk_vbox_new(FALSE, 10);
  672    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
  673    gtk_container_add(GTK_CONTAINER(frame), vbox);
  674 
  675    /* Normal redundancy */
  676 
  677    lwoh = CreateLabelWithOnlineHelp(_("Normal redundancy"), _("Normal"));
  678    RegisterPreferencesHelpWindow(lwoh);
  679 
  680    for(i=0; i<2; i++)
  681    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  682 
  683       radio = gtk_radio_button_new(NULL);
  684       g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_cb), method);
  685       gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
  686 
  687       if(!i)
  688       {  wl->radio1A = radio;
  689      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  690      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  691       }
  692       else
  693       {  wl->radio1B = radio;
  694          gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  695      AddHelpWidget(lwoh, hbox);
  696       }
  697    }
  698 
  699    AddHelpParagraph(lwoh, _("<b>Normal redundancy</b>\n\n"
  700                 "The preset \"normal\" creates a redundancy of 14.3%%.\n"
  701                 "It invokes optimized program code to speed up the "
  702                 "error correction file creation."));
  703 
  704    /* High redundancy */
  705 
  706    lwoh = CreateLabelWithOnlineHelp(_("High redundancy"), _("High"));
  707    RegisterPreferencesHelpWindow(lwoh);
  708 
  709    for(i=0; i<2; i++)
  710    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  711 
  712       radio = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(i?wl->radio1B:wl->radio1A));
  713       g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_cb), method);
  714       gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
  715 
  716       if(!i)
  717       {  wl->radio2A = radio;
  718      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  719      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  720       }
  721       else
  722       {  wl->radio2B = radio;
  723          gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  724      AddHelpWidget(lwoh, hbox);
  725       }
  726    }
  727 
  728    AddHelpParagraph(lwoh, _("<b>High redundancy</b>\n\n"
  729                 "The preset \"high\" creates a redundancy of 33.5%%.\n"
  730                 "It invokes optimized program code to speed up the "
  731                 "error correction file creation."));
  732 
  733 
  734    /* User-selected redundancy */
  735 
  736    lwoh = CreateLabelWithOnlineHelp(_("Other redundancy"), _("Other"));
  737    RegisterPreferencesHelpWindow(lwoh);
  738 
  739    for(i=0; i<2; i++)
  740    {  hbox = gtk_hbox_new(FALSE, 4);
  741 
  742       radio = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(i?wl->radio1B:wl->radio1A));
  743       g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_cb), method);
  744       gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
  745 
  746       if(!i)
  747       {  wl->radio3A = radio;
  748      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  749       }
  750       else
  751       {  wl->radio3B = radio;
  752          gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  753       }
  754 
  755       scale = gtk_hscale_new_with_range(8,100,1);
  756       gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT);
  757       gtk_range_set_increments(GTK_RANGE(scale), 1, 1);
  758       gtk_range_set_value(GTK_RANGE(scale), 32);
  759       gtk_widget_set_sensitive(scale, FALSE);
  760       g_signal_connect(scale, "format-value", G_CALLBACK(format_cb), (gpointer)PREF_NROOTS);
  761       g_signal_connect(scale, "value-changed", G_CALLBACK(nroots_cb), (gpointer)wl);
  762       gtk_container_add(GTK_CONTAINER(hbox), scale);
  763 
  764       if(!i)
  765       {  wl->redundancyScaleA = scale;
  766      gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  767       }
  768       else
  769       {  wl->redundancyScaleB = scale;
  770      AddHelpWidget(lwoh, hbox);
  771       }
  772    }
  773 
  774    AddHelpParagraph(lwoh, _("<b>Other redundancy</b>\n\n"
  775                 "Specifies the redundancy by percent.\n"
  776                 "An error correction file with x%% redundancy "
  777                 "will be approximately x%% of the size of the "
  778                 "corresponding image file."));
  779 
  780    /* Space-delimited redundancy */
  781 
  782    lwoh = CreateLabelWithOnlineHelp(_("Space-delimited redundancy"), _("Use at most"));
  783    RegisterPreferencesHelpWindow(lwoh);
  784 
  785    for(i=0; i<2; i++)
  786    {  hbox = gtk_hbox_new(FALSE, 4);
  787 
  788       radio = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(i?wl->radio1B:wl->radio1A));
  789       g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_cb), method);
  790       gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
  791 
  792       if(!i)
  793       {  wl->radio4A = radio;
  794      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  795       }
  796       else
  797       {  wl->radio4B = radio;
  798          gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  799       }
  800 
  801       spin = gtk_spin_button_new_with_range(0, 100000, 100);
  802       g_signal_connect(spin, "value-changed", G_CALLBACK(ecc_size_cb), (gpointer)wl);
  803       gtk_entry_set_width_chars(GTK_ENTRY(spin), 8);
  804       gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
  805 
  806       lab = gtk_label_new(_utf("MiB for error correction data"));
  807       gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0);
  808       gtk_widget_set_sensitive(spin, FALSE);
  809       gtk_widget_set_sensitive(lab, FALSE);
  810 
  811       if(!i)
  812       {  wl->redundancySpinA = spin;
  813      wl->radio4LabelA = lab;
  814          gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  815       }
  816       else
  817       {  wl->redundancySpinB = spin;
  818      wl->radio4LabelB = lab;
  819      AddHelpWidget(lwoh, hbox);
  820       }
  821    }
  822 
  823    AddHelpParagraph(lwoh, _("<b>Space-delimited redundancy</b>\n\n"
  824                 "Specifies the maximum size of the error correction file in MiB. "
  825                 "dvdisaster will choose a suitable redundancy setting so that "
  826                 "the overall size of the error correction file does not exceed "
  827                 "the given limit.\n\n"
  828                 "<b>Advance notice:</b> When using the same size setting for "
  829                 "images of vastly different size, smaller images receive more "
  830                 "redundancy than larger ones. This is usually not what you want."));
  831 
  832    /*** Preset redundancy values */
  833 
  834    if(Closure->redundancy)
  835    {  if(!strcmp(Closure->redundancy, "normal"))
  836       {  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio1A), TRUE);
  837          gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio1B), TRUE);
  838       }
  839       else if(!strcmp(Closure->redundancy, "high"))
  840       {  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio2A), TRUE);
  841          gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio2B), TRUE);
  842       }
  843       else
  844       {  int last = strlen(Closure->redundancy)-1;
  845 
  846          if(Closure->redundancy[last] == 'm')
  847      {  Closure->redundancy[last] = 0;
  848         gtk_spin_button_set_value(GTK_SPIN_BUTTON(wl->redundancySpinA), atoi(Closure->redundancy));
  849         gtk_spin_button_set_value(GTK_SPIN_BUTTON(wl->redundancySpinB), atoi(Closure->redundancy));
  850         Closure->redundancy[last] = 'm';
  851         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio4A), TRUE);
  852         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio4B), TRUE);
  853      }
  854      else
  855      {  gtk_range_set_value(GTK_RANGE(wl->redundancyScaleA), atoi(Closure->redundancy));
  856         gtk_range_set_value(GTK_RANGE(wl->redundancyScaleB), atoi(Closure->redundancy));
  857         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio3A), TRUE);
  858         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wl->radio3B), TRUE);
  859      }
  860       }
  861    }
  862 
  863 
  864    /* Memory utilization */
  865    
  866    frame = gtk_frame_new(_utf("Memory utilization"));
  867    gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
  868 
  869    text = g_strdup_printf(_("%d MiB of file cache"), Closure->cacheMiB);
  870    lwoh = CreateLabelWithOnlineHelp(_("File cache"), text);
  871    RegisterPreferencesHelpWindow(lwoh);
  872    g_free(text);
  873 
  874    wl->cacheLwoh = lwoh;
  875    LockLabelSize(GTK_LABEL(lwoh->normalLabel), _utf("%d MiB of file cache"), 2222);
  876    LockLabelSize(GTK_LABEL(lwoh->linkLabel), _utf("%d MiB of file cache"), 2222);
  877 
  878    for(i=0; i<2; i++)
  879    {  GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
  880       int n_entries = sizeof(cache_size)/sizeof(int);
  881 
  882       lab = gtk_label_new(_utf("Use"));
  883       gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0);
  884 
  885       for(index = 0; index < n_entries; index++)
  886     if(cache_size[index] > Closure->cacheMiB)
  887       break;
  888 
  889       scale = gtk_hscale_new_with_range(0,n_entries-1,1);
  890       gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT);
  891       gtk_range_set_increments(GTK_RANGE(scale), 1, 1);
  892       gtk_range_set_value(GTK_RANGE(scale), index > 0 ? index-1 : index);
  893       g_signal_connect(scale, "format-value", G_CALLBACK(format_cb), (gpointer)PREF_CACHE);
  894       g_signal_connect(scale, "value-changed", G_CALLBACK(cache_cb), (gpointer)wl);
  895       gtk_box_pack_start(GTK_BOX(hbox), scale, TRUE, TRUE, 0);
  896 
  897       if(!i)
  898       {  wl->cacheScaleA = scale; 
  899      gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
  900      gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
  901      gtk_container_add(GTK_CONTAINER(frame), hbox);
  902       }
  903       else
  904       {  wl->cacheScaleB = scale; 
  905      gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
  906      AddHelpWidget(lwoh, hbox);
  907       }
  908    }
  909 
  910    AddHelpParagraph(lwoh, _("<b>File cache</b>\n\n"
  911                 "dvdisaster optimizes access to the image and error correction "
  912                 "files by maintaining its own cache. "
  913                 "The preset of 32MiB is suitable for most systems."));
  914 }