Files
dvdisaster/preferences.c
Stéphane Lesimple 38defdf7aa Apply (most) debian patches
Apply debian patch 02-encryption
Apply debian patch 03-dvdrom
Apply a modified version of patch 05-help-dialog
Apply debian patch 08-fix-gnu-make-detection
Apply debian patch 10-use-non-size-specific-icon-and-add-keywords-to-desktop-file
Apply debian patch 12-fix-spelling-of-up-to
Apply debian patch 13-fix-missing-language-field-in-po-files
Apply a modified version of debian patch 14-make-builds-reproducible
Apply debian patch 17-fix-all-but-deprecated-api-warnings
Apply a modified version of debian patch 18-update-copyright-in-about-dialog
Apply debian patch 19-show-text-files-with-abs-path
Apply debian patch 22-fix-hurd-i386-ftbfs
Apply debian patch 23-add-bdrom-support
Apply debian patch 25-fix-man-pages
Apply debian patch 27-allow-opening-in-browser-again
Apply debian patch 28-pdftex-reproducibility
Apply debian patch 29-fix-more-typos
Apply debian patch 30-hurd-kfreebsd-ftbfs
Apply debian patch 31-improve-hurd-and-kfreebsd-support
Apply debian patch 33-honour-LDFLAGS
Apply debian patch 34-gcc8-format-security.patch
Apply debian patch 35-archived-homepage
Apply debian patch 36-fix-parallelism
2020-08-20 14:17:35 +02:00

3213 lines
111 KiB
C

/* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2017 Carsten Gnoerlich.
*
* Email: carsten@dvdisaster.org -or- cgnoerlich@fsfe.org
* Project homepage: http://www.dvdisaster.org
*
* This file is part of dvdisaster.
*
* dvdisaster is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dvdisaster is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dvdisaster. If not, see <http://www.gnu.org/licenses/>.
*/
// DVDISASTER_GUI_FILE
#include "dvdisaster.h"
extern gint64 CurrentMediumSize(int); /* from scsi-layer.h */
/***
*** debugging workaround
***/
#if 0
#define gtk_widget_set_sensitive(widget, state) { printf("%s, line %d - gtk_widget_set_sensitive()\n", __FILE__, __LINE__); gtk_widget_set_sensitive(widget, state); }
#endif
/***
*** Protected widget mutators
***
* We might have some race conditions where a callback tries to change
* a not yet initialized widget.
*/
static void activate_toggle_button(GtkToggleButton *toggle, int state)
{ if(toggle)
gtk_toggle_button_set_active(toggle, state);
}
static void set_widget_sensitive(GtkWidget *widget, int state)
{ if(widget)
gtk_widget_set_sensitive(widget, state);
}
static void set_entry_text(GtkEntry *entry, char *text)
{ if(entry)
gtk_entry_set_text(entry, text);
}
/***
*** Local data structs
***/
/* non linear scale housekeeping */
typedef struct
{ GtkWidget *label; /* for help system linkage */
LabelWithOnlineHelp *lwoh;
int action;
int *values;
char *format;
struct _prefs_context *pc;
} non_linear_info;
/* color button housekeeping */
typedef struct
{ GtkWidget *button;
GtkWidget *dialog;
GtkWidget *frame;
GtkWidget *image;
GdkColor *color;
GdkPixmap *pixmap;
GdkGC *gc;
int userData;
} color_button_info;
/***
*** Preferences window housekeeping
***/
typedef struct _prefs_context
{ char *formatLinear;
char *formatAdaptive;
GPtrArray *helpPages; /* The online help frame structures */
/* Widgets for changing preferences settings. The are two copies (A and B)
of each; one for the standard dialog and one embedded in the online help. */
GtkWidget *suffixA, *suffixB;
GtkWidget *radioLinearA, *radioLinearB;
GtkWidget *radioAdaptiveA, *radioAdaptiveB;
GtkWidget *minAttemptsScaleA, *minAttemptsScaleB;
GtkWidget *maxAttemptsScaleA, *maxAttemptsScaleB;
GtkWidget *readMediumA, *readMediumB;
GtkWidget *cacheDefectiveA, *cacheDefectiveB;
GtkWidget *cacheDefectiveDirA, *cacheDefectiveDirB;
GtkWidget *cacheDefectiveChooser;
GtkWidget *cacheDefectivePrefixA, *cacheDefectivePrefixB;
GtkWidget *rangeToggleA, *rangeToggleB;
GtkWidget *rangeSpin1A, *rangeSpin1B;
GtkWidget *rangeSpin2A, *rangeSpin2B;
GtkWidget *rawButtonA, *rawButtonB;
GtkWidget *jumpScaleA, *jumpScaleB;
GtkWidget *daoButtonA, *daoButtonB;
GtkWidget *ignoreISOSizeA, *ignoreISOSizeB;
GtkWidget *dsmButtonA, *dsmButtonB;
GtkWidget *recogRS02A, *recogRS02B;
GtkWidget *recogRS03A, *recogRS03B;
GtkWidget *byteEntryA, *byteEntryB;
GtkWidget *byteCheckA, *byteCheckB;
GtkWidget *spinUpA, *spinUpB;
GtkWidget *internalAttemptsA, *internalAttemptsB;
GtkWidget *radioRawMode20A, *radioRawMode20B;
GtkWidget *radioRawMode21A, *radioRawMode21B;
GtkWidget *radioRawModeOtherA, *radioRawModeOtherB;
GtkWidget *rawModeValueA, *rawModeValueB;
GtkWidget *fatalSenseA, *fatalSenseB;
GtkWidget *ejectA, *ejectB;
GtkWidget *readAndCreateButtonA, *readAndCreateButtonB;
GtkWidget *unlinkImageButtonA, *unlinkImageButtonB;
GtkWidget *confirmDeletionA, *confirmDeletionB;
GtkWidget *mainNotebook;
GtkWidget *methodChooserA,*methodChooserB;
GtkWidget *methodNotebook;
GtkWidget *cancelOKA, *cancelOKB;
GtkWidget *verboseA, *verboseB;
GtkWidget *logFileA, *logFileB;
GtkWidget *logFilePathA, *logFilePathB;
GtkWidget *logFileChooser;
color_button_info *redA, *redB;
color_button_info *yellowA, *yellowB;
color_button_info *greenA, *greenB;
color_button_info *blueA, *blueB;
color_button_info *whiteA, *whiteB;
color_button_info *darkA, *darkB;
color_button_info *redTextA, *redTextB;
color_button_info *greenTextA, *greenTextB;
color_button_info *barColorA, *barColorB;
color_button_info *logColorA, *logColorB;
color_button_info *curveColorA, *curveColorB;
non_linear_info *jumpScaleInfoA, *jumpScaleInfoB;
LabelWithOnlineHelp *jumpScaleLwoh;
non_linear_info *minAttemptsScaleInfoA, *minAttemptsScaleInfoB;
non_linear_info *maxAttemptsScaleInfoA, *maxAttemptsScaleInfoB;
LabelWithOnlineHelp *minAttemptsScaleLwoh, *maxAttemptsScaleLwoh;
} prefs_context;
void FreePreferences(void *context)
{ prefs_context *pc = (prefs_context*)context;
int i;
for(i=0; i<pc->helpPages->len; i++)
{ LabelWithOnlineHelp *lwoh = g_ptr_array_index(pc->helpPages,i);
FreeLabelWithOnlineHelp(lwoh);
}
g_ptr_array_free(pc->helpPages, FALSE);
if(pc->formatLinear) g_free(pc->formatLinear);
if(pc->formatAdaptive) g_free(pc->formatAdaptive);
if(pc->jumpScaleInfoA) g_free(pc->jumpScaleInfoA);
if(pc->jumpScaleInfoB) g_free(pc->jumpScaleInfoB);
if(pc->minAttemptsScaleInfoA->format) g_free(pc->minAttemptsScaleInfoA->format);
if(pc->minAttemptsScaleInfoB->format) g_free(pc->minAttemptsScaleInfoB->format);
if(pc->minAttemptsScaleInfoA) g_free(pc->minAttemptsScaleInfoA);
if(pc->minAttemptsScaleInfoB) g_free(pc->minAttemptsScaleInfoB);
if(pc->maxAttemptsScaleInfoA->format) g_free(pc->maxAttemptsScaleInfoA->format);
if(pc->maxAttemptsScaleInfoB->format) g_free(pc->maxAttemptsScaleInfoB->format);
if(pc->maxAttemptsScaleInfoA) g_free(pc->maxAttemptsScaleInfoA);
if(pc->maxAttemptsScaleInfoB) g_free(pc->maxAttemptsScaleInfoB);
if(pc->redA) g_free(pc->redA);
if(pc->redB) g_free(pc->redB);
if(pc->yellowA) g_free(pc->yellowA);
if(pc->yellowB) g_free(pc->yellowB);
if(pc->greenA) g_free(pc->greenA);
if(pc->greenB) g_free(pc->greenB);
if(pc->blueA) g_free(pc->blueA);
if(pc->blueB) g_free(pc->blueB);
if(pc->whiteA) g_free(pc->whiteA);
if(pc->whiteB) g_free(pc->whiteB);
if(pc->darkA) g_free(pc->darkA);
if(pc->darkB) g_free(pc->darkB);
if(pc->redTextA) g_free(pc->redTextA);
if(pc->redTextB) g_free(pc->redTextB);
if(pc->greenTextA) g_free(pc->greenTextA);
if(pc->greenTextB) g_free(pc->greenTextB);
if(pc->barColorA) g_free(pc->barColorA);
if(pc->barColorB) g_free(pc->barColorB);
if(pc->logColorA) g_free(pc->logColorA);
if(pc->logColorB) g_free(pc->logColorB);
if(pc->curveColorA) g_free(pc->curveColorA);
if(pc->curveColorB) g_free(pc->curveColorB);
g_free(pc);
}
static gboolean delete_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
{
FreePreferences(Closure->prefsContext);
Closure->prefsWindow = NULL;
Closure->prefsContext = NULL;
return FALSE;
}
void HidePreferences(void)
{ prefs_context *pc = (prefs_context*)Closure->prefsContext;
Method *method;
const char *value1, *value2;
int method_index;
int i;
/* Get reading range values */
if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pc->rangeToggleA))
|| gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pc->rangeToggleB)))
{
Closure->readStart = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pc->rangeSpin1A));
Closure->readEnd = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pc->rangeSpin2A));
}
else Closure->readStart = Closure->readEnd = 0;
/* Get fill byte and recalculate the dead sector marker */
if(pc->byteCheckA && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pc->byteCheckA)))
{ const char *value1 = gtk_entry_get_text(GTK_ENTRY(pc->byteEntryA));
const char *value2 = gtk_entry_get_text(GTK_ENTRY(pc->byteEntryB));
int v1 = strtol(value1, NULL, 0);
int v2 = strtol(value2, NULL, 0);
/* both fields may contain different values */
if(Closure->fillUnreadable != v2)
{ Closure->fillUnreadable = v2;
gtk_entry_set_text(GTK_ENTRY(pc->byteEntryA), value2);
}
else
if(Closure->fillUnreadable != v1)
{ Closure->fillUnreadable = v1;
gtk_entry_set_text(GTK_ENTRY(pc->byteEntryB), value1);
}
if(Closure->fillUnreadable < 0)
Closure->fillUnreadable = 1;
if(Closure->fillUnreadable > 255)
Closure->fillUnreadable = 255;
}
/* Get raw reading mode */
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pc->radioRawModeOtherA)))
{ const char *value1 = gtk_entry_get_text(GTK_ENTRY(pc->rawModeValueA));
const char *value2 = gtk_entry_get_text(GTK_ENTRY(pc->rawModeValueB));
int v1 = strtol(value1, NULL, 0);
int v2 = strtol(value2, NULL, 0);
/* both fields may contain different values */
if(Closure->rawMode != v2)
{ Closure->rawMode = v2;
gtk_entry_set_text(GTK_ENTRY(pc->rawModeValueA), value2);
}
else
if(Closure->rawMode != v1)
{ Closure->rawMode = v1;
gtk_entry_set_text(GTK_ENTRY(pc->rawModeValueB), value1);
}
if(Closure->rawMode < 0)
Closure->rawMode = 0;
if(Closure->rawMode > 255)
Closure->rawMode = 255;
}
/* Get defective sector cache prefix.
Both entries might contain different input. */
value1 = gtk_entry_get_text(GTK_ENTRY(pc->cacheDefectivePrefixA));
value2 = gtk_entry_get_text(GTK_ENTRY(pc->cacheDefectivePrefixB));
if(strcmp(Closure->dDumpPrefix, value1))
{ g_free(Closure->dDumpPrefix);
Closure->dDumpPrefix = g_strdup(value1);
gtk_entry_set_text(GTK_ENTRY(pc->cacheDefectivePrefixB), value1);
}
else if(strcmp(Closure->dDumpPrefix, value2))
{ g_free(Closure->dDumpPrefix);
Closure->dDumpPrefix = g_strdup(value2);
gtk_entry_set_text(GTK_ENTRY(pc->cacheDefectivePrefixA), value2);
}
/* Ask currently selected method to update its settings
from the preferences */
method_index = gtk_notebook_get_current_page(GTK_NOTEBOOK(pc->methodNotebook));
method = g_ptr_array_index(Closure->methodList, method_index);
if(method->readPreferences)
method->readPreferences(method);
/* hide preferences and finish */
gtk_widget_hide(GTK_WIDGET(Closure->prefsWindow));
for(i=0; i<pc->helpPages->len; i++)
{ LabelWithOnlineHelp *lwoh = g_ptr_array_index(pc->helpPages,i);
gtk_widget_hide(lwoh->helpWindow);
}
}
static void close_cb(GtkWidget *widget, gpointer data)
{
HidePreferences();
}
/***
*** Setting preferences from external functions
***/
void UpdatePrefsExhaustiveSearch(void)
{ prefs_context *pc = (prefs_context*)Closure->prefsContext;
if(Closure->prefsContext)
{ activate_toggle_button(GTK_TOGGLE_BUTTON(pc->recogRS02A), Closure->examineRS02);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->recogRS02B), Closure->examineRS02);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->recogRS03A), Closure->examineRS03);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->recogRS03B), Closure->examineRS03);
}
}
void UpdatePrefsConfirmDeletion(void)
{ prefs_context *pc = (prefs_context*)Closure->prefsContext;
if(Closure->prefsContext)
{ activate_toggle_button(GTK_TOGGLE_BUTTON(pc->confirmDeletionA), Closure->confirmDeletion);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->confirmDeletionB), Closure->confirmDeletion);
}
}
/*
* Register a preferences help window
*/
void RegisterPreferencesHelpWindow(LabelWithOnlineHelp *lwoh)
{ prefs_context *pc = (prefs_context*)Closure->prefsContext;
g_ptr_array_add(pc->helpPages, lwoh);
}
/*
* Actions used in the preferences
*/
enum
{ TOGGLE_READ_CREATE,
TOGGLE_UNLINK,
TOGGLE_SUFFIX,
TOGGLE_RECOG_RS02,
TOGGLE_RECOG_RS03,
TOGGLE_SIZEDRIVE,
TOGGLE_DAO,
TOGGLE_DSM,
TOGGLE_RANGE,
TOGGLE_RAW,
TOGGLE_RAW_20H,
TOGGLE_RAW_21H,
TOGGLE_RAW_OTHER,
TOGGLE_CACHE_DEFECTIVE,
TOGGLE_CANCEL_OK,
TOGGLE_FATAL_SENSE,
TOGGLE_EJECT,
TOGGLE_VERBOSE,
TOGGLE_LOGFILE,
TOGGLE_CONFIRM_DELETION,
SPIN_DELAY,
SPIN_INTERNAL_ATTEMPTS,
SPIN_READ_MEDIUM,
SLIDER_JUMP,
SLIDER_MIN_READ_ATTEMPTS,
SLIDER_MAX_READ_ATTEMPTS,
COLOR_RED,
COLOR_YELLOW,
COLOR_GREEN,
COLOR_BLUE,
COLOR_WHITE,
COLOR_DARK,
COLOR_RED_TEXT,
COLOR_GREEN_TEXT,
COLOR_BAR,
COLOR_LOG,
COLOR_CURVE
};
/*
* Create a new notebook page
*/
static GtkWidget *create_page(GtkWidget *notebook, char *label)
{ GtkWidget *vbox,*tab_label;
tab_label = gtk_label_new(label);
vbox = gtk_vbox_new(FALSE, 5);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, tab_label);
return vbox;
}
/***
*** Toggle button actions
***/
static void toggle_cb(GtkWidget *widget, gpointer data)
{ int state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
int action = GPOINTER_TO_INT(data);
prefs_context *pc = (prefs_context*)Closure->prefsContext;
switch(action)
{ case TOGGLE_READ_CREATE:
Closure->readAndCreate = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->readAndCreateButtonA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->readAndCreateButtonB), state);
if(state && Closure->adaptiveRead) /* set reading strategy to linear */
{ prefs_context *pc = Closure->prefsContext;
Closure->adaptiveRead = FALSE;
pc->jumpScaleInfoA->format = pc->formatLinear;
pc->jumpScaleInfoB->format = pc->formatLinear;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioLinearA), TRUE);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioLinearB), TRUE);
ShowMessage(Closure->prefsWindow,
_("Switched to the linear reading strategy."),
GTK_MESSAGE_INFO);
}
break;
case TOGGLE_UNLINK:
Closure->unlinkImage = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->unlinkImageButtonA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->unlinkImageButtonB), state);
break;
case TOGGLE_CONFIRM_DELETION:
Closure->confirmDeletion = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->confirmDeletionA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->confirmDeletionB), state);
break;
case TOGGLE_SUFFIX:
Closure->autoSuffix = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->suffixA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->suffixB), state);
break;
case TOGGLE_CACHE_DEFECTIVE:
Closure->defectiveDump = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->cacheDefectiveA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->cacheDefectiveB), state);
break;
case TOGGLE_LOGFILE:
Closure->logFileEnabled = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->logFileA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->logFileB), state);
break;
case TOGGLE_CANCEL_OK:
Closure->reverseCancelOK = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->cancelOKA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->cancelOKB), state);
break;
case TOGGLE_SIZEDRIVE:
Closure->ignoreIsoSize = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->ignoreISOSizeA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->ignoreISOSizeB), state);
break;
case TOGGLE_DAO:
Closure->noTruncate = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->daoButtonA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->daoButtonB), state);
break;
case TOGGLE_RECOG_RS02:
Closure->examineRS02 = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->recogRS02A), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->recogRS02B), state);
break;
case TOGGLE_RECOG_RS03:
Closure->examineRS03 = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->recogRS03A), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->recogRS03B), state);
break;
case TOGGLE_DSM:
Closure->dsmVersion = !state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->dsmButtonA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->dsmButtonB), state);
if(state)
{ if(pc->byteCheckA)
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->byteCheckA), FALSE);
if(pc->byteCheckB)
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->byteCheckB), FALSE);
}
break;
case TOGGLE_RAW:
Closure->readRaw = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->rawButtonA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->rawButtonB), state);
break;
case TOGGLE_FATAL_SENSE:
Closure->ignoreFatalSense = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->fatalSenseA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->fatalSenseB), state);
break;
case TOGGLE_EJECT:
Closure->eject = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->ejectA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->ejectB), state);
break;
case TOGGLE_RAW_20H:
if(state)
{ Closure->rawMode = 0x20;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioRawMode20A), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioRawMode20B), state);
set_widget_sensitive(pc->rawModeValueA, FALSE);
set_widget_sensitive(pc->rawModeValueB, FALSE);
set_entry_text(GTK_ENTRY(pc->rawModeValueA), "0x20");
set_entry_text(GTK_ENTRY(pc->rawModeValueB), "0x20");
}
break;
case TOGGLE_RAW_21H:
if(state)
{ Closure->rawMode = 0x21;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioRawMode21A), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioRawMode21B), state);
set_widget_sensitive(pc->rawModeValueA, FALSE);
set_widget_sensitive(pc->rawModeValueB, FALSE);
set_entry_text(GTK_ENTRY(pc->rawModeValueA), "0x21");
set_entry_text(GTK_ENTRY(pc->rawModeValueB), "0x21");
}
break;
case TOGGLE_RAW_OTHER:
if(state)
{ activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioRawModeOtherA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioRawModeOtherB), state);
set_widget_sensitive(pc->rawModeValueA, TRUE);
set_widget_sensitive(pc->rawModeValueB, TRUE);
}
break;
case TOGGLE_VERBOSE:
Closure->verbose = state;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->verboseA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->verboseB), state);
break;
case TOGGLE_RANGE:
{ int image_size = CurrentMediumSize(FALSE) - 1;
set_widget_sensitive(pc->rangeSpin1A, state);
set_widget_sensitive(pc->rangeSpin1B, state);
set_widget_sensitive(pc->rangeSpin2A, state);
set_widget_sensitive(pc->rangeSpin2B, state);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin1A), 0.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin1B), 0.0);
if(state)
{ gtk_spin_button_set_range(GTK_SPIN_BUTTON(pc->rangeSpin2A), 0.0, image_size);
gtk_spin_button_set_range(GTK_SPIN_BUTTON(pc->rangeSpin2B), 0.0, image_size);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2A), image_size);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2B), image_size);
}
else
{ gtk_spin_button_set_range(GTK_SPIN_BUTTON(pc->rangeSpin2A), 0.0, 1.0);
gtk_spin_button_set_range(GTK_SPIN_BUTTON(pc->rangeSpin2B), 0.0, 1.0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2A), 0.1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2B), 0.1);
}
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->rangeToggleA), state);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->rangeToggleB), state);
}
break;
}
}
/***
*** Spin button actions
***/
static void spin_cb(GtkWidget *widget, gpointer data)
{ int which = GPOINTER_TO_INT(data);
int value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
prefs_context *pc = (prefs_context*)Closure->prefsContext;
switch(which)
{ case SPIN_DELAY:
Closure->spinupDelay = value;
if(widget == pc->spinUpA)
{ if(pc->spinUpB)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->spinUpB), value);
}
if(widget == pc->spinUpB)
{ if(pc->spinUpA)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->spinUpA), value);
}
break;
case SPIN_INTERNAL_ATTEMPTS:
Closure->internalAttempts = value;
if(widget == pc->internalAttemptsA)
{ if(pc->internalAttemptsB)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->internalAttemptsB), value);
}
if(widget == pc->internalAttemptsB)
{ if(pc->internalAttemptsA)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->internalAttemptsA), value);
}
break;
case SPIN_READ_MEDIUM:
Closure->readingPasses = value;
if(widget == pc->readMediumA)
{ if(pc->readMediumB)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->readMediumB), value);
}
if(widget == pc->readMediumB)
{ if(pc->readMediumA)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->readMediumA), value);
}
break;
}
}
/*
* Make sure the reading range is a valid interval
*/
static void read_range_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)data;
if(pc->rangeSpin1A == widget || pc->rangeSpin2A == widget)
{ int from = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pc->rangeSpin1A));
int to = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pc->rangeSpin2A));
if(from > to)
{ if(widget == pc->rangeSpin1A)
{ gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin1A), to);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin1B), to);
}
else
{ gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2A), from);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2B), from);
}
}
else
{ gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin1B), from);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2B), to);
}
}
else
{ int from = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pc->rangeSpin1B));
int to = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(pc->rangeSpin2B));
if(from > to)
{ if(widget == pc->rangeSpin1B)
{ gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin1A), to);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin1B), to);
}
else
{ gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2A), from);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2B), from);
}
}
else
{ gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin1A), from);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(pc->rangeSpin2A), to);
}
}
}
/***
*** Color buttons
***/
/*
* Create a color button. We need to do this manually as the GTK color button
* won't let us manipulate the button order.
*/
#define COLOR_BUTTON_WIDTH 32
#define COLOR_BUTTON_HEIGHT 12
static gboolean color_delete_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
{ color_button_info *cbi = (color_button_info*)data;
cbi->dialog = NULL;
return FALSE;
}
static void update_color_buttons(color_button_info *a, color_button_info *b, int redraw)
{ GdkRectangle rect;
GdkWindow *window;
gint ignore;
/* Note that a->color and b->color point to the same object. */
gdk_colormap_alloc_color(gdk_colormap_get_system(), a->color, FALSE, TRUE);
gdk_gc_set_rgb_fg_color(a->gc, a->color);
gdk_gc_set_rgb_bg_color(a->gc, a->color);
gdk_gc_set_rgb_fg_color(b->gc, b->color);
gdk_gc_set_rgb_bg_color(b->gc, b->color);
gdk_draw_rectangle(a->pixmap, a->gc, TRUE, 0, 0, COLOR_BUTTON_WIDTH, COLOR_BUTTON_HEIGHT);
gdk_draw_rectangle(b->pixmap, b->gc, TRUE, 0, 0, COLOR_BUTTON_WIDTH, COLOR_BUTTON_HEIGHT);
/* Trigger an expose event for the button. Since the button has no own window
this will actually redraw the whole dialog box. */
if(redraw) /* Useful when all buttons are reset to default at once */
{ window = gtk_widget_get_parent_window(a->button);
if(window)
{ gdk_window_get_geometry(window, &rect.x, &rect.y, &rect.width, &rect.height, &ignore);
gdk_window_invalidate_rect(a->button->window, &rect, TRUE);
}
}
window = gtk_widget_get_parent_window(b->button);
if(window)
{ gdk_window_get_geometry(window, &rect.x, &rect.y, &rect.width, &rect.height, &ignore);
gdk_window_invalidate_rect(window, &rect, TRUE);
}
}
static void color_ok_cb(GtkWidget *widget, gpointer data)
{ color_button_info *cbi = (color_button_info*)data;
prefs_context *pc = (prefs_context*)Closure->prefsContext;
gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(((GtkColorSelectionDialog*)cbi->dialog)->colorsel), cbi->color);
switch(cbi->userData)
{ case COLOR_RED:
update_color_buttons(pc->redA, pc->redB, TRUE);
break;
case COLOR_YELLOW:
update_color_buttons(pc->yellowA, pc->yellowB, TRUE);
break;
case COLOR_GREEN:
update_color_buttons(pc->greenA, pc->greenB, TRUE);
break;
case COLOR_BLUE:
update_color_buttons(pc->blueA, pc->blueB, TRUE);
break;
case COLOR_WHITE:
update_color_buttons(pc->whiteA, pc->whiteB, TRUE);
break;
case COLOR_DARK:
update_color_buttons(pc->darkA, pc->darkB, TRUE);
break;
case COLOR_RED_TEXT:
update_color_buttons(pc->redTextA, pc->redTextB, TRUE);
UpdateMarkup(&Closure->redMarkup, Closure->redText);
break;
case COLOR_GREEN_TEXT:
update_color_buttons(pc->greenTextA, pc->greenTextB, TRUE);
UpdateMarkup(&Closure->greenMarkup, Closure->greenText);
break;
case COLOR_BAR:
update_color_buttons(pc->barColorA, pc->barColorB, TRUE);
break;
case COLOR_LOG:
update_color_buttons(pc->logColorA, pc->logColorB, TRUE);
break;
case COLOR_CURVE:
update_color_buttons(pc->curveColorA, pc->curveColorB, TRUE);
break;
}
gtk_widget_hide(cbi->dialog);
}
static void color_cancel_cb(GtkWidget *widget, gpointer data)
{ color_button_info *cbi = (color_button_info*)data;
gtk_widget_hide(cbi->dialog);
}
static void color_choose_cb(GtkWidget *widget, gpointer data)
{ color_button_info *cbi = (color_button_info*)data;
if(!cbi->dialog)
{ GtkColorSelectionDialog *csd;
cbi->dialog = gtk_color_selection_dialog_new(_utf("Color selection"));
g_signal_connect(cbi->dialog, "delete_event", G_CALLBACK(color_delete_cb), cbi);
csd = (GtkColorSelectionDialog*)cbi->dialog;
g_signal_connect(G_OBJECT(csd->cancel_button), "clicked", G_CALLBACK(color_cancel_cb), cbi);
g_signal_connect(G_OBJECT(csd->ok_button), "clicked", G_CALLBACK(color_ok_cb), cbi);
ReverseCancelOK(GTK_DIALOG(cbi->dialog));
}
gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(((GtkColorSelectionDialog*)cbi->dialog)->colorsel), cbi->color);
gtk_widget_show(cbi->dialog);
}
static void default_color_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)Closure->prefsContext;
DefaultColors();
update_color_buttons(pc->redA, pc->redB, FALSE);
update_color_buttons(pc->yellowA, pc->yellowB, FALSE);
update_color_buttons(pc->greenA, pc->greenB, FALSE);
update_color_buttons(pc->blueA, pc->blueB, FALSE);
update_color_buttons(pc->whiteA, pc->whiteB, FALSE);
update_color_buttons(pc->darkA, pc->darkB, FALSE);
update_color_buttons(pc->redTextA, pc->redTextB, FALSE);
update_color_buttons(pc->greenTextA, pc->greenTextB, FALSE);
update_color_buttons(pc->barColorA, pc->barColorB, FALSE);
update_color_buttons(pc->logColorA, pc->logColorB, FALSE);
update_color_buttons(pc->curveColorA, pc->curveColorB, TRUE);
}
static color_button_info *create_color_button(GdkColor *color, int user_data)
{ color_button_info *cbi = g_malloc0(sizeof(color_button_info));
cbi->button = gtk_button_new();
cbi->frame = gtk_frame_new(NULL);
gtk_container_set_border_width(GTK_CONTAINER(cbi->frame), 1);
gtk_frame_set_shadow_type(GTK_FRAME(cbi->frame), GTK_SHADOW_ETCHED_OUT);
gtk_container_add(GTK_CONTAINER(cbi->button), cbi->frame);
cbi->pixmap = gdk_pixmap_new(gdk_get_default_root_window(), COLOR_BUTTON_WIDTH, COLOR_BUTTON_HEIGHT, -1);
cbi->image = gtk_image_new_from_pixmap(cbi->pixmap, NULL);
gtk_container_add(GTK_CONTAINER(cbi->frame), cbi->image);
cbi->gc = gdk_gc_new(cbi->pixmap);
gdk_gc_set_foreground(cbi->gc, color);
gdk_gc_set_background(cbi->gc, color);
gdk_draw_rectangle(cbi->pixmap, cbi->gc, TRUE, 0, 0, COLOR_BUTTON_WIDTH, COLOR_BUTTON_HEIGHT);
cbi->color = color;
cbi->userData = user_data;
g_signal_connect(G_OBJECT(cbi->button), "clicked", G_CALLBACK(color_choose_cb), cbi);
return cbi;
// gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, color);
}
/***
*** Non-linear scales
***/
static int jump_values[] = { 0, 16, 32, 64, 128, 256, 384, 512, 768,
1024, 2048, 4096, 10240, 20480 };
#define JUMP_VALUE_LENGTH 14
static int min_attempts_values[] = { 1, 2, 3, 4, 5, 7, 9, 11, 15, 20, 25, 30, 40, 50};
static int max_attempts_values[] = { 1, 2, 3, 4, 5, 7, 9, 11, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100};
#define MIN_ATTEMPTS_VALUE_LENGTH 14
#define MAX_ATTEMPTS_VALUE_LENGTH 19
static void non_linear_cb(GtkWidget *widget, gpointer data)
{ non_linear_info *nli = (non_linear_info*)data;
int index = gtk_range_get_value(GTK_RANGE(widget));
char *text,*utf;
text = g_strdup_printf(nli->format, nli->values[index]);
utf = g_locale_to_utf8(text, -1, NULL, NULL, NULL);
switch(nli->action)
{ case SLIDER_JUMP:
Closure->sectorSkip = nli->values[index];
gtk_range_set_value(GTK_RANGE(nli->pc->jumpScaleB), index);
gtk_label_set_markup(GTK_LABEL(nli->pc->jumpScaleInfoB->label), utf);
gtk_range_set_value(GTK_RANGE(nli->pc->jumpScaleA), index);
gtk_label_set_markup(GTK_LABEL(nli->pc->jumpScaleInfoA->label), utf);
SetOnlineHelpLinkText(nli->pc->jumpScaleLwoh, text);
break;
case SLIDER_MIN_READ_ATTEMPTS:
{ int max = gtk_range_get_value(GTK_RANGE(nli->pc->maxAttemptsScaleA));
Closure->minReadAttempts = nli->values[index];
gtk_range_set_value(GTK_RANGE(nli->pc->minAttemptsScaleB), index);
gtk_label_set_markup(GTK_LABEL(nli->pc->minAttemptsScaleInfoB->label), utf);
gtk_range_set_value(GTK_RANGE(nli->pc->minAttemptsScaleA), index);
gtk_label_set_markup(GTK_LABEL(nli->pc->minAttemptsScaleInfoA->label), utf);
SetOnlineHelpLinkText(nli->pc->minAttemptsScaleLwoh, text);
if(index > max)
{
gtk_range_set_value(GTK_RANGE(nli->pc->maxAttemptsScaleA), index);
gtk_range_set_value(GTK_RANGE(nli->pc->maxAttemptsScaleB), index);
}
}
break;
case SLIDER_MAX_READ_ATTEMPTS:
{ int min = gtk_range_get_value(GTK_RANGE(nli->pc->minAttemptsScaleA));
Closure->maxReadAttempts = nli->values[index];
gtk_range_set_value(GTK_RANGE(nli->pc->maxAttemptsScaleB), index);
gtk_label_set_markup(GTK_LABEL(nli->pc->maxAttemptsScaleInfoB->label), utf);
gtk_range_set_value(GTK_RANGE(nli->pc->maxAttemptsScaleA), index);
gtk_label_set_markup(GTK_LABEL(nli->pc->maxAttemptsScaleInfoA->label), utf);
SetOnlineHelpLinkText(nli->pc->maxAttemptsScaleLwoh, text);
if(index < min)
{
gtk_range_set_value(GTK_RANGE(nli->pc->minAttemptsScaleA), index);
gtk_range_set_value(GTK_RANGE(nli->pc->minAttemptsScaleB), index);
}
}
break;
}
g_free(utf);
g_free(text);
}
static gchar* non_linear_format_cb(GtkScale *scale, gdouble value, gpointer data)
{ char *text;
text = g_strdup(" ");
FORGET(text); /* The scale will free the old string by itself. Weird. */
return text;
}
static GtkWidget* non_linear_scale(GtkWidget **hbox_out, non_linear_info *nli,
GtkWidget *label, prefs_context *pc,
int action, int *values, int n, int value)
{ GtkWidget *scale;
GtkWidget *hbox;
char *text,*utf;
int index;
for(index = 0; index < n; index++)
if(values[index] > value)
break;
nli->action = action;
nli->values = values;
nli->pc = pc;
hbox = gtk_hbox_new(FALSE, 0);
scale = gtk_hscale_new_with_range(0,n-1,1);
gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT);
gtk_range_set_increments(GTK_RANGE(scale), 1, 1);
gtk_range_set_value(GTK_RANGE(scale), index > 0 ? index-1 : index);
g_signal_connect(scale, "format-value", G_CALLBACK(non_linear_format_cb), nli);
g_signal_connect(scale, "value-changed", G_CALLBACK(non_linear_cb), nli);
gtk_box_pack_start(GTK_BOX(hbox), scale, TRUE, TRUE, 0);
text = g_strdup_printf(nli->format, nli->values[index > 0 ? index-1 : index]);
utf = g_locale_to_utf8(text, -1, NULL, NULL, NULL);
nli->label = label;
gtk_label_set_markup(GTK_LABEL(label), utf);
if(nli->lwoh)
{ SetOnlineHelpLinkText(nli->lwoh, text);
gtk_box_pack_start(GTK_BOX(hbox), nli->lwoh->linkBox, FALSE, FALSE, 0);
}
else gtk_box_pack_start(GTK_BOX(hbox), nli->label, FALSE, FALSE, 0);
g_free(utf);
g_free(text);
*hbox_out = hbox;
return scale;
}
/*
* Read strategy selection
*/
static void strategy_cb(GtkWidget *widget, gpointer data)
{ int state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
prefs_context *pc = (prefs_context*)data;
if(pc->jumpScaleA && pc->jumpScaleB && state == TRUE)
{ double tmp;
if(pc->radioLinearA == widget || pc->radioLinearB == widget)
{ Closure->adaptiveRead = FALSE;
pc->jumpScaleInfoA->format = pc->formatLinear;
pc->jumpScaleInfoB->format = pc->formatLinear;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioLinearA), TRUE);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioLinearB), TRUE);
}
if(pc->radioAdaptiveA == widget || pc->radioAdaptiveB == widget)
{ Closure->adaptiveRead = TRUE;
pc->jumpScaleInfoA->format = pc->formatAdaptive;
pc->jumpScaleInfoB->format = pc->formatAdaptive;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioAdaptiveA), TRUE);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->radioAdaptiveB), TRUE);
if(Closure->readAndCreate)
{ Closure->readAndCreate = FALSE;
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->readAndCreateButtonA), FALSE);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->readAndCreateButtonB), FALSE);
ShowMessage(Closure->prefsWindow,
_("Disabled automatic error correction file generation."),
GTK_MESSAGE_INFO);
}
}
/* poor hack to make the range widgets redraw */
tmp = gtk_range_get_value(GTK_RANGE(pc->jumpScaleA));
gtk_range_set_value(GTK_RANGE(pc->jumpScaleA), tmp+1.0);
gtk_range_set_value(GTK_RANGE(pc->jumpScaleA), tmp);
gtk_range_set_value(GTK_RANGE(pc->jumpScaleB), tmp+1.0);
gtk_range_set_value(GTK_RANGE(pc->jumpScaleB), tmp);
}
}
/*
* Select the mode page value for raw reading
*/
static void rawvalue_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)data;
const char *value = gtk_entry_get_text(GTK_ENTRY(widget));
char new_value[11];
Closure->rawMode = strtol(value, NULL, 0);
if(Closure->rawMode < 0)
{ Closure->rawMode = 0;
set_entry_text(GTK_ENTRY(pc->rawModeValueA), "0");
set_entry_text(GTK_ENTRY(pc->rawModeValueB), "0");
return;
}
if(Closure->rawMode > 255)
{ Closure->rawMode = 255;
}
g_snprintf(new_value, 10, "0x%02x", Closure->rawMode);
set_entry_text(GTK_ENTRY(pc->rawModeValueA), new_value);
set_entry_text(GTK_ENTRY(pc->rawModeValueB), new_value);
}
/*
* Select the value for filling unreadable sectors
*/
static void bytefill_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)data;
const char *value = gtk_entry_get_text(GTK_ENTRY(widget));
char byte[11];
Closure->fillUnreadable = strtol(value, NULL, 0);
if(Closure->fillUnreadable < 0)
{ Closure->fillUnreadable = 1;
set_entry_text(GTK_ENTRY(pc->byteEntryA), "1");
set_entry_text(GTK_ENTRY(pc->byteEntryB), "1");
return;
}
if(Closure->fillUnreadable > 255)
{ Closure->fillUnreadable = 255;
}
g_snprintf(byte, 10, "0x%02x", Closure->fillUnreadable);
set_entry_text(GTK_ENTRY(pc->byteEntryA), byte);
set_entry_text(GTK_ENTRY(pc->byteEntryB), byte);
}
static void bytefill_check_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)data;
int state = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
if(pc->byteCheckA)
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->byteCheckA), state);
if(pc->byteCheckB)
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->byteCheckB), state);
if(state)
{ char byte[11];
set_widget_sensitive(pc->byteEntryA, TRUE);
set_widget_sensitive(pc->byteEntryB, TRUE);
if(Closure->fillUnreadable < 0 || Closure->fillUnreadable > 255)
Closure->fillUnreadable = 0xb0;
g_snprintf(byte, 10, "0x%02x", Closure->fillUnreadable);
set_entry_text(GTK_ENTRY(pc->byteEntryA), byte);
set_entry_text(GTK_ENTRY(pc->byteEntryB), byte);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->dsmButtonA), FALSE);
activate_toggle_button(GTK_TOGGLE_BUTTON(pc->dsmButtonB), FALSE);
}
else
{ Closure->fillUnreadable = -1;
set_widget_sensitive(pc->byteEntryA, FALSE);
set_widget_sensitive(pc->byteEntryB, FALSE);
}
}
/*
* Enter the prefix for raw sector files
*/
static void defective_prefix_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)data;
char *value = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
if(!value || !*value)
{ set_entry_text(GTK_ENTRY(pc->cacheDefectivePrefixA), "sector-");
set_entry_text(GTK_ENTRY(pc->cacheDefectivePrefixB), "sector-");
return;
}
if(widget == pc->cacheDefectivePrefixA)
set_entry_text(GTK_ENTRY(pc->cacheDefectivePrefixB), value);
if(widget == pc->cacheDefectivePrefixB)
set_entry_text(GTK_ENTRY(pc->cacheDefectivePrefixA), value);
}
/*
* Run the file chooser for the raw sector files directory
*/
static void cache_defective_select_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)Closure->prefsContext;
int action = GPOINTER_TO_INT(data);
switch(action)
{ case 0: /* destroy */
pc->cacheDefectiveChooser = NULL;
break;
case 1: /* OK */
if(Closure->dDumpDir)
g_free(Closure->dDumpDir);
Closure->dDumpDir = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(pc->cacheDefectiveChooser)));
if(pc->cacheDefectiveDirA)
gtk_label_set_text(GTK_LABEL(pc->cacheDefectiveDirA), Closure->dDumpDir);
if(pc->cacheDefectiveDirB)
gtk_label_set_text(GTK_LABEL(pc->cacheDefectiveDirB), Closure->dDumpDir);
gtk_widget_hide(pc->cacheDefectiveChooser);
break;
case 2: /* Cancel */
gtk_widget_hide(pc->cacheDefectiveChooser);
break;
}
}
static void cache_defective_dir_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)data;
GtkWidget *file_list;
if(!pc->cacheDefectiveChooser)
{ char filename[strlen(Closure->dDumpDir)+10];
pc->cacheDefectiveChooser = gtk_file_selection_new(_utf("Raw sector caching"));
ReverseCancelOK(GTK_DIALOG(pc->cacheDefectiveChooser));
g_signal_connect(G_OBJECT(pc->cacheDefectiveChooser), "destroy",
G_CALLBACK(cache_defective_select_cb),
GINT_TO_POINTER(0));
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(pc->cacheDefectiveChooser)->ok_button),
"clicked", G_CALLBACK(cache_defective_select_cb), GINT_TO_POINTER(1));
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(pc->cacheDefectiveChooser)->cancel_button),
"clicked", G_CALLBACK(cache_defective_select_cb), GINT_TO_POINTER(2));
sprintf(filename, "%s/", Closure->dDumpDir);
gtk_file_selection_set_filename(GTK_FILE_SELECTION(pc->cacheDefectiveChooser),
filename);
gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(pc->cacheDefectiveChooser));
/* Hide the file selection parts */
file_list = GTK_FILE_SELECTION(pc->cacheDefectiveChooser)->file_list;
set_widget_sensitive(file_list, FALSE);
gtk_widget_hide(GTK_FILE_SELECTION(pc->cacheDefectiveChooser)->selection_entry);
set_entry_text(GTK_ENTRY(GTK_FILE_SELECTION(pc->cacheDefectiveChooser)->selection_entry), "");
#if 0
gtk_widget_hide(file_list->parent);
#endif
}
gtk_widget_show(pc->cacheDefectiveChooser);
}
/*
* Run the file chooser for the log file
*/
static void logfile_select_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)Closure->prefsContext;
int action = GPOINTER_TO_INT(data);
switch(action)
{ case 0: /* destroy */
pc->logFileChooser = NULL;
break;
case 1: /* OK */
g_free(Closure->logFile);
Closure->logFile = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(pc->logFileChooser)));
Closure->logFileStamped = FALSE;
if(pc->logFilePathA)
gtk_label_set_text(GTK_LABEL(pc->logFilePathA), Closure->logFile);
if(pc->logFilePathB)
gtk_label_set_text(GTK_LABEL(pc->logFilePathB), Closure->logFile);
gtk_widget_hide(pc->logFileChooser);
break;
case 2: /* Cancel */
gtk_widget_hide(pc->logFileChooser);
break;
}
}
#define LOGFILE_SELECT 1
#define LOGFILE_DELETE 2
static void logfile_cb(GtkWidget *widget, gpointer data)
{ prefs_context *pc = (prefs_context*)Closure->prefsContext;
int action = GPOINTER_TO_INT(data);
switch(action)
{ case LOGFILE_SELECT:
if(!pc->logFileChooser)
{
pc->logFileChooser = gtk_file_selection_new(_utf("Log file"));
ReverseCancelOK(GTK_DIALOG(pc->logFileChooser));
g_signal_connect(G_OBJECT(pc->logFileChooser), "destroy",
G_CALLBACK(logfile_select_cb),
GINT_TO_POINTER(0));
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(pc->logFileChooser)->ok_button),
"clicked", G_CALLBACK(logfile_select_cb), GINT_TO_POINTER(1));
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(pc->logFileChooser)->cancel_button),
"clicked", G_CALLBACK(logfile_select_cb), GINT_TO_POINTER(2));
gtk_file_selection_set_filename(GTK_FILE_SELECTION(pc->logFileChooser),
Closure->logFile);
}
gtk_widget_show(pc->logFileChooser);
break;
case LOGFILE_DELETE:
{ GtkWidget *dialog = gtk_message_dialog_new(Closure->prefsWindow,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_OK_CANCEL,
"%s", _utf("Delete the log file?"));
int answer;
ReverseCancelOK(GTK_DIALOG(dialog));
answer = gtk_dialog_run(GTK_DIALOG(dialog));
if(answer == GTK_RESPONSE_OK)
LargeUnlink(Closure->logFile);
gtk_widget_destroy(dialog);
break;
}
}
}
/***
*** Error correction method selection
***/
static void method_select_cb(GtkWidget *widget, gpointer data)
{ Method *method;
prefs_context *pc = (prefs_context*)data;
int n;
n = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
if(n<0 || !pc->methodNotebook)
return;
method = g_ptr_array_index(Closure->methodList, n);
/* Switch methods if selection changed */
if(strncmp(Closure->methodName, method->name, 4))
{ GtkWidget *other;
strncpy(Closure->methodName, method->name, 4);
gtk_notebook_set_current_page(GTK_NOTEBOOK(pc->methodNotebook), n);
if(pc->methodChooserA == widget)
other = pc->methodChooserB;
else other = pc->methodChooserA;
gtk_combo_box_set_active(GTK_COMBO_BOX(other), n);
}
}
/*
* Setting the notebook page does not work at creation time.
*/
static gboolean notebook_idle_func(gpointer data)
{ prefs_context *pc = (prefs_context*)data;
int n;
n = gtk_combo_box_get_active(GTK_COMBO_BOX(pc->methodChooserA));
if(n>=0)
gtk_notebook_set_current_page(GTK_NOTEBOOK(pc->methodNotebook), n);
gtk_notebook_set_current_page(GTK_NOTEBOOK(pc->mainNotebook), 0);
return FALSE;
}
/***
*** Assemble and open the preferences window.
***/
void UpdateMethodPreferences(void)
{ int i;
for(i=0; i<Closure->methodList->len; i++)
{ Method *method = g_ptr_array_index(Closure->methodList, i);
if(method->resetPrefsPage)
method->resetPrefsPage(method);
}
}
void CreatePreferencesWindow(void)
{
if(!Closure->prefsWindow) /* No window to reuse? */
{ GtkWidget *window, *outer_box, *notebook, *space;
GtkWidget *hbox, *vbox, *vbox2, *vbox3, *button, *frame, *table;
GtkWidget *lab;
LabelWithOnlineHelp *lwoh,*lwoh_clone;
prefs_context *pc = g_malloc0(sizeof(prefs_context));
int i, method_idx = 0;
pc->helpPages = g_ptr_array_new();
Closure->prefsContext = pc;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Closure->prefsWindow = GTK_WINDOW(window);
gtk_window_set_title(GTK_WINDOW(window), _utf("Preferences"));
gtk_window_set_default_size(GTK_WINDOW(window), -1, 150);
gtk_window_set_icon(GTK_WINDOW(window), Closure->windowIcon);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width(GTK_CONTAINER(window), 12);
/* Connect with the close button from the window manager */
g_signal_connect(window, "delete_event", G_CALLBACK(delete_cb), NULL);
/* Create the main layout of the window */
outer_box = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), outer_box);
notebook = pc->mainNotebook = gtk_notebook_new();
gtk_box_pack_start(GTK_BOX(outer_box), notebook, TRUE, TRUE, 0);
space = gtk_image_new();
gtk_box_pack_start(GTK_BOX(outer_box), space, FALSE, FALSE, 4);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(outer_box), hbox, FALSE, FALSE, 0);
button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(close_cb), NULL);
/*** Image creation page */
vbox = create_page(notebook, _utf("Image"));
/** Reading preferences */
frame = gtk_frame_new(_utf("Image creation"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 20);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* Reading strategy */
lwoh = CreateLabelWithOnlineHelp(_("Reading strategy"), _("Reading strategy: "));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *lab, *radio1, *radio2;
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
radio1 = gtk_radio_button_new(NULL);
if(!i) pc->radioLinearA = radio1;
else pc->radioLinearB = radio1;
g_signal_connect(G_OBJECT(radio1), "toggled", G_CALLBACK(strategy_cb), pc);
gtk_box_pack_start(GTK_BOX(hbox), radio1, FALSE, FALSE, 0);
lab = gtk_label_new(_utf("Linear"));
gtk_container_add(GTK_CONTAINER(radio1), lab);
radio2 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio1));
if(!i) pc->radioAdaptiveA = radio2;
else pc->radioAdaptiveB = radio2;
g_signal_connect(G_OBJECT(radio2), "toggled", G_CALLBACK(strategy_cb), pc);
gtk_box_pack_start(GTK_BOX(hbox), radio2, FALSE, FALSE, 0);
lab = gtk_label_new(_utf("Adaptive (for defective media)"));
gtk_container_add(GTK_CONTAINER(radio2), lab);
if(Closure->adaptiveRead)
activate_toggle_button(GTK_TOGGLE_BUTTON(radio2), TRUE);
else activate_toggle_button(GTK_TOGGLE_BUTTON(radio1), TRUE);
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Reading strategy</b>\n\n"
"Use the <b>linear strategy</b> for:\n"
"- processing undamaged media, or\n"
"- reading defective media when no error correction data is available.\n\n"
"The <b>adaptive strategy</b> is optimized for\n"
"- reading defective media\n"
"- if (and only if) error correction data is available.\n\n"
"Using the adaptive strategy without error correction data "
"is possible but it is recommended to use linear reading in that case."), Closure->invisibleDash);
/* Reading range */
lwoh = CreateLabelWithOnlineHelp(_("Reading range"), _("Read/Scan from sector"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *toggle,*spin1, *spin2;
// toggle = gtk_check_button_new_with_label(_utf("Read/Scan from sector"));
toggle = gtk_check_button_new();
if(!i) pc->rangeToggleA = toggle;
else pc->rangeToggleB = toggle;
g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_RANGE));
gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox,
FALSE, FALSE, 0);
spin1 = gtk_spin_button_new_with_range(0, 10000000, 1000);
if(!i) pc->rangeSpin1A = spin1;
else pc->rangeSpin1B = spin1;
gtk_entry_set_width_chars(GTK_ENTRY(spin1), 9);
set_widget_sensitive(spin1, FALSE);
g_signal_connect(spin1, "value-changed", G_CALLBACK(read_range_cb), pc);
gtk_box_pack_start(GTK_BOX(hbox), spin1, FALSE, FALSE, 0);
lab = gtk_label_new(_utf("to sector"));
gtk_box_pack_start(GTK_BOX(hbox), lab, FALSE, FALSE, 0);
spin2 = gtk_spin_button_new_with_range(0, 1, 10000);
if(!i) pc->rangeSpin2A = spin2;
else pc->rangeSpin2B = spin2;
gtk_entry_set_width_chars(GTK_ENTRY(spin2), 9);
set_widget_sensitive(spin2, FALSE);
g_signal_connect(spin2, "value-changed", G_CALLBACK(read_range_cb), pc);
gtk_box_pack_start(GTK_BOX(hbox), spin2, FALSE, FALSE, 0);
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
activate_toggle_button(GTK_TOGGLE_BUTTON(toggle), FALSE);
}
AddHelpParagraph(lwoh,
_("<b>Reading range</b>\n\n"
"Reading can be limited to a part of the medium (in sectors holding 2KB each). "
"The values include the borders: 0-100 will read 101 sectors.\n\n"
"<b>Note:</b> Limiting the reading range is not recommended for <i>adaptive reading</i> since it might "
"prevent sectors from being read which are required for a successful error correction.\n\n"
"These settings are only effective for the current session and will not be saved."));
/*** Image recognization */
frame = gtk_frame_new(_utf("Error correction data recognization"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 15);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* RS02 */
lwoh = CreateLabelWithOnlineHelp(_("Exhaustive RS02 header search"), _("Perform exhaustive search for RS02 headers"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
if(!i) pc->recogRS02A = button;
else pc->recogRS02B = button;
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->examineRS02);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_RECOG_RS02));
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Exhaustive RS02 header search</b>\n\n"
"When this setting is off only a quick check "
"for RS02 data is performed. If the medium or "
"image is damaged, the quick test may not suffice "
"to identify the image as being augmented with RS02.\n\n"
"Therefore you should turn this option <b>on</b> "
"if a medium/image contains RS02 data, but is not "
"being recognized as such. Searching for the RS02 "
"information may cause a significant delay at the "
"start of reading and scanning processes.\n\n"
"Leave this option <b>off</b> when you are "
"processing media or images which are not augmented "
"with RS02 data. Otherwise you will waste a lot of "
"time searching for the RS02 signatures and increase "
"wear on the drive."
));
/* RS03 */
lwoh = CreateLabelWithOnlineHelp(_("Recover RS03 signatures"), _("Find and recover RS03 signatures"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
if(!i) pc->recogRS03A = button;
else pc->recogRS03B = button;
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->examineRS03);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_RECOG_RS03));
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Exhaustive RS03 header search</b>\n\n"
"When this setting is off only a quick check "
"for RS03 data is performed. If the medium or "
"image is damaged, the quick test may not suffice "
"to identify the image as being augmented with RS03.\n\n"
"Therefore you should turn this option <b>on</b> "
"if a medium/image contains RS03 data, but is not "
"being recognized as such. Searching for the RS03 "
"information may cause a significant delay at the "
"start of reading and scanning processes.\n\n"
"Leave this option <b>off</b> when you are "
"processing media or images which are not augmented "
"with RS03 data. Otherwise you will waste a lot of "
"time searching for the RS03 signatures and increase "
"wear on the drive."
));
/** Image properties */
frame = gtk_frame_new(_utf("Image properties"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 15);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* Query size from drive */
lwoh = CreateLabelWithOnlineHelp(_("Ignore ISO/UDF meta data"), _("Ignore image size recorded in ISO/UDF file system"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
if(!i) pc->ignoreISOSizeA = button;
else pc->ignoreISOSizeB = button;
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->ignoreIsoSize);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_SIZEDRIVE));
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Ignore image size recorded in ISO/UDF filesystem</b>\n\n"
"When reading or scanning optical discs, the overall size of the medium "
"needs to be determined. dvdisaster will always use the image size "
"recorded in the error correction data if such data is present. "
"Otherwise, image size is queried in the following order:\n\n"
"1. Image size recorded in the ISO/UDF file system\n"
"2. Image size reported by the optical drive.\n\n"
"Using this order makes sense as image sizes reported by most drives "
"are unreliable in many cases. However in some rare cases "
"the image size recorded in the ISO/UDF filesystem is wrong. Some "
"GNU/Linux live CDs may have this problem. If you read back the ISO "
"image from such CDs and its md5sum does not match the advertised one, "
"try re-reading the image with this option turned on.\n"
"Do <b>not blindly turn this option on</b> as it will most likely "
"create sub optimal or corrupted ISO images, especially if you "
"plan to use the image for error correction data generation."));
/* DAO button */
lwoh = CreateLabelWithOnlineHelp(_("DAO mode"), _("Assume image to be written in DAO mode (don't truncate)"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
if(!i) pc->daoButtonA = button;
else pc->daoButtonB = button;
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->noTruncate);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_DAO));
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Assume DAO mode</b>\n\n"
"Media written in \"TAO\" (\"track at once\") mode may contain two sectors "
"with pseudo read errors at the end. By default these two sectors are ignored.\n\n"
"If you are extremely unlucky to have a \"DAO\" (\"disc at once\") medium "
"with exactly one or two real read errors at the end, dvdisaster may treat "
"this as a \"TAO\" disc and truncate the image by two sectors. In that case "
"activate this option to have the last two read errors handled correctly.\n\n"
"<b>Tip:</b> To avoid these problems, consider using the \"DAO / Disc at once\" "
"(sometimes also called \"SAO / Session at once\") mode for writing single "
"session media."));
/*** Image format */
frame = gtk_frame_new(_utf("Image format"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 15);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* new style missing sector marker */
lwoh = CreateLabelWithOnlineHelp(_("Missing sector tags"), _("Use old style missing sector tags (not recommended)"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
if(!i) pc->dsmButtonA = button;
else pc->dsmButtonB = button;
activate_toggle_button(GTK_TOGGLE_BUTTON(button), !Closure->dsmVersion);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_DSM));
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Missing sector tagging</b>\n\n"
"Missing sectors are tagged with a special code sequence "
"in the image. By default, an improved "
"code is used which can detect some wilfully damaged "
"content. This includes media which have been created "
"from partially recovered images, and images containing "
"files from such partial media.\n"
"However only dvdisaster 0.72 and up will recognize "
"the improved tags. Activate this switch to force using the "
"older format when this image will be processed with older "
"dvdisaster versions. Otherwise the older dvdisaster versions "
"will not see any missing sectors in the resulting images.\n"
"N.b.: dvdisaster >= 0.72 will automatically recognize "
"both tag formats when reading images; setting this value "
"only affects the creation of new images."));
/** byte filling */
if(Closure->debugMode)
{
lwoh = CreateLabelWithOnlineHelp(_("Filling of unreadable sectors"),
_("Fill unreadable sectors with byte:"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *check, *entry;
check = gtk_check_button_new();
g_signal_connect(check, "toggled", G_CALLBACK(bytefill_check_cb), pc);
gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
entry = gtk_entry_new();
g_signal_connect(entry, "activate", G_CALLBACK(bytefill_cb), pc);
gtk_entry_set_width_chars(GTK_ENTRY(entry), 5);
gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
if(!i)
{ pc->byteCheckA = check;
pc->byteEntryA = entry;
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
}
else
{ pc->byteCheckB = check;
pc->byteEntryB = entry;
AddHelpWidget(lwoh, hbox);
}
if(Closure->fillUnreadable >= 0)
{ char value[11];
g_snprintf(value, 10, "0x%02x", Closure->fillUnreadable);
gtk_entry_set_text(GTK_ENTRY(entry), value);
activate_toggle_button(GTK_TOGGLE_BUTTON(check), TRUE);
}
else set_widget_sensitive(entry, FALSE);
}
AddHelpParagraph(lwoh,
_("<b>Filling of unreadable sectors</b>\n\n"
"dvdisaster marks unreadable sectors with a special filling pattern which "
"is very unlikely to occur in undamaged media.\n"
"In other data recovery software it is common to fill unreadable sectors "
"with a certain byte value. To allow interoperability with such programs, "
"you can specify the byte value they are using:\n"));
AddHelpListItem(lwoh,
_("0xb0 (176 decimal): for compatibility with h2cdimage published by \"c't\", "
"a German periodical.\n"));
AddHelpParagraph(lwoh,
_("<b>Note:</b> Using zero filling (0x00, decimal 0) is highly discouraged. "
"Most media contain regular zero filled sectors which can not be told apart "
"from unreadable sectors if zero filling is used."));
}
/*** Drive parameters page */
vbox = create_page(notebook, _utf("Drive"));
/** Drive initialisation */
frame = gtk_frame_new(_utf("Drive initialisation"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
lwoh = CreateLabelWithOnlineHelp(_("Drive initialisation"),
_("Wait"));
RegisterPreferencesHelpWindow(lwoh);
lwoh_clone = CloneLabelWithOnlineHelp(lwoh, _("seconds for drive to spin up"));
RegisterPreferencesHelpWindow(lwoh_clone);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *spin;
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
spin = gtk_spin_button_new_with_range(0, 30, 1);
gtk_entry_set_width_chars(GTK_ENTRY(spin), 3);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), Closure->spinupDelay);
g_signal_connect(spin, "value-changed", G_CALLBACK(spin_cb), (gpointer)SPIN_DELAY);
gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh_clone->normalLabel : lwoh_clone->linkBox, FALSE, FALSE, 0);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
if(!i)
{ pc->spinUpA = spin;
gtk_container_add(GTK_CONTAINER(frame), hbox);
}
else
{ pc->spinUpB = spin;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Drive initialisation</b>\n\n"
"Waits the specified amount of seconds for letting the drive spin up. "
"This avoids speed jumps at the beginning of the reading curve."));
/** Drive raw reading parameters */
frame = gtk_frame_new(_utf("Raw reading parameters"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 15);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* Raw reading mode */
lwoh = CreateLabelWithOnlineHelp(_("Raw reading mode"), _("Raw reading mode: "));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *lab, *radio1, *radio2, *radio3, *entry;
char value[11];
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
radio1 = gtk_radio_button_new(NULL);
if(!i) pc->radioRawMode20A = radio1;
else pc->radioRawMode20B = radio1;
g_signal_connect(G_OBJECT(radio1), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_RAW_20H));
gtk_box_pack_start(GTK_BOX(hbox), radio1, FALSE, FALSE, 0);
lab = gtk_label_new("0x20");
gtk_container_add(GTK_CONTAINER(radio1), lab);
radio2 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio1));
if(!i) pc->radioRawMode21A = radio2;
else pc->radioRawMode21B = radio2;
g_signal_connect(G_OBJECT(radio2), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_RAW_21H));
gtk_box_pack_start(GTK_BOX(hbox), radio2, FALSE, FALSE, 0);
lab = gtk_label_new("0x21");
gtk_container_add(GTK_CONTAINER(radio2), lab);
radio3 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radio2));
if(!i) pc->radioRawModeOtherA = radio3;
else pc->radioRawModeOtherB = radio3;
g_signal_connect(G_OBJECT(radio3), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_RAW_OTHER));
gtk_box_pack_start(GTK_BOX(hbox), radio3, FALSE, FALSE, 0);
lab = gtk_label_new(_utf("other:"));
gtk_container_add(GTK_CONTAINER(radio3), lab);
entry = gtk_entry_new();
g_signal_connect(entry, "activate", G_CALLBACK(rawvalue_cb), pc);
gtk_entry_set_width_chars(GTK_ENTRY(entry), 5);
gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
if(!i) pc->rawModeValueA = entry;
else pc->rawModeValueB = entry;
g_snprintf(value, 10, "0x%02x", Closure->rawMode);
gtk_entry_set_text(GTK_ENTRY(entry), value);
switch(Closure->rawMode)
{ case 0x20:
activate_toggle_button(GTK_TOGGLE_BUTTON(radio1), TRUE);
set_widget_sensitive(entry, FALSE);
break;
case 0x21:
activate_toggle_button(GTK_TOGGLE_BUTTON(radio2), TRUE);
set_widget_sensitive(entry, FALSE);
break;
default:
activate_toggle_button(GTK_TOGGLE_BUTTON(radio3), TRUE);
break;
}
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Raw reading mode</b>\n\n"
"There are several ways to put the drive into a mode "
"which transfers partially read data from defective sectors:\n\n"
"<b>0x20</b> This is the <i>recommended</i> mode. "
"The drive tries to apply "
"the built-in error correction to the best possible extent "
"before transferring a defective sector.\n\n"
"<b>0x21</b> In this mode the drive skips the last stage "
"of its internal error correction and returns the "
"uncorrected sector instead. This may result in sectors "
"being tagged and processed as defective which would come "
"out good in other reading modes, causing unnecessary "
"work or even uncorrectable sectors.\n"
"However some drives appear to be unable to transfer data "
"in mode 0x20, but can do so in mode 0x21, so this is your "
"last resort then. Also, if sectors are not recoverable "
"after reading and caching sectors in mode 0x20, then adding "
"some mode 0x21 reads to the cache might deliver additional information.\n\n"
"<b>0x01</b> Some drives do the right thing when given this value, "
"although this makes no sense according to the SCSI specs. Try entering "
"this value in the \"other\" field if the other choices do not work. "
"See the mode page 01h documentation in chapter 6 of MMC3 or later "
"for additional information."));
/* Firmware rereads */
lwoh = CreateLabelWithOnlineHelp(_("Internal read attempts"),
_("Reread defective sectors"));
RegisterPreferencesHelpWindow(lwoh);
lwoh_clone = CloneLabelWithOnlineHelp(lwoh, _("times"));
RegisterPreferencesHelpWindow(lwoh_clone);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *spin;
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
spin = gtk_spin_button_new_with_range(-1, 10, 1);
gtk_entry_set_width_chars(GTK_ENTRY(spin), 3);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), Closure->internalAttempts);
g_signal_connect(spin, "value-changed", G_CALLBACK(spin_cb), (gpointer)SPIN_INTERNAL_ATTEMPTS);
gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh_clone->normalLabel : lwoh_clone->linkBox, FALSE, FALSE, 0);
// gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
if(!i)
{ pc->internalAttemptsA = spin;
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
// gtk_container_add(GTK_CONTAINER(frame), hbox);
}
else
{ pc->internalAttemptsB = spin;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Internal read attempts</b>\n\n"
"The drive firmware usually retries unreadable sectors "
"a few times before giving up and returning a read error.\n"
"But it is usually more efficient to manage the reading "
"attempts from the client software, e.g. through the "
"settings in the \"Read attempts\" preferences tab.\n"
"Lowering this value to 0 or 1 can speed up processing "
"of damaged media and reduce the drive wear; however "
"most drives will simply ignore what you enter here.\n"
"Use the value -1 to leave the drive at its default setting."));
/* Fatal error handling */
frame = gtk_frame_new(_utf("Fatal error handling"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
lwoh = CreateLabelWithOnlineHelp(_("Fatal error handling"),
_("Ignore fatal errors"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *toggle;
toggle = gtk_check_button_new();
activate_toggle_button(GTK_TOGGLE_BUTTON(toggle), Closure->ignoreFatalSense);
g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_FATAL_SENSE));
gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0);
if(!i)
{ pc->fatalSenseA = toggle;
gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(frame), hbox);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
}
else
{ pc->fatalSenseB = toggle;
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Fatal error handling</b>\n\n"
"By default dvdisaster stops reading when the drive "
"reports a fatal error. This prevents further fruitless "
"read attempts and possible damage to the drive.\n"
"However some drives produce unfounded fatal messages. "
"For such drives ignoring fatal errors may be needed to "
"do uninterrupted reading of damaged media."));
/* Eject medium */
frame = gtk_frame_new(_utf("Media ejection"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
lwoh = CreateLabelWithOnlineHelp(_("Eject medium after successful read"),
_("Eject medium after successful read"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *toggle;
toggle = gtk_check_button_new();
activate_toggle_button(GTK_TOGGLE_BUTTON(toggle), Closure->eject);
g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_EJECT));
gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0);
if(!i)
{ pc->ejectA = toggle;
gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(frame), hbox);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 12);
}
else
{ pc->ejectB = toggle;
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Medium ejection</b>\n\n"
"Activate this option to have the medium ejected after "
"a successful read or scan operation.\n\n"
"Note that the desktop environment "
"may prevent other applications from ejecting media. "
"In that case eject the medium through the desktop "
"user interface."));
/*** "Read attempts" page */
vbox = create_page(notebook, _utf("Read attempts"));
/** Reading preferences */
frame = gtk_frame_new(_utf("Sector read errors"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 20);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* Raw verify */
lwoh = CreateLabelWithOnlineHelp(_("Raw reading"), _("Read and analyze raw sectors"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
if(!i) pc->rawButtonA = button;
else pc->rawButtonB = button;
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->readRaw);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_RAW));
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Raw reading</b> (affects CD media only)\n\n"
"Activating this option has several effects:\n\n"
"C2 quality scanning will be performed when supported "
"by the drive.\n\n"
"Media sectors are read in raw mode. The L-EC P/Q "
"vectors, EDC checksum and MSF address contained "
"in the raw data are checked to make sure that the "
"sector was correctly read.\n\n"
"Additional data recovery heuristics and raw sector "
"caching becomes available if either\n"
"- adaptive reading is used, or\n"
"- linear reading is configured to skip 0 sectors after a read error.\n"
"Raw sector caching also needs checking of the respective option."
));
/* Minimum reading attempts */
lwoh = CreateLabelWithOnlineHelp(_("Minimum number of reading attempts"), "ignore");
RegisterPreferencesHelpWindow(lwoh);
LockLabelSize(GTK_LABEL(lwoh->normalLabel), _utf("Min. %d reading attempts per sector"), 99);
LockLabelSize(GTK_LABEL(lwoh->linkLabel), _utf("Min. %d reading attempts per sector"), 99);
pc->minAttemptsScaleLwoh = lwoh;
pc->minAttemptsScaleInfoA = g_malloc0(sizeof(non_linear_info));
pc->minAttemptsScaleInfoB = g_malloc0(sizeof(non_linear_info));
pc->minAttemptsScaleInfoA->format = g_strdup(_("Min. %d reading attempts per sector"));
pc->minAttemptsScaleInfoB->format = g_strdup(_("Min. %d reading attempts per sector"));
pc->minAttemptsScaleInfoA->lwoh = lwoh;
for(i=0; i<2; i++)
{ GtkWidget *scale,*scale_box;
scale = non_linear_scale(&scale_box,
i ? pc->minAttemptsScaleInfoB : pc->minAttemptsScaleInfoA,
i ? lwoh->normalLabel : lwoh->linkLabel,
pc, SLIDER_MIN_READ_ATTEMPTS, min_attempts_values, MIN_ATTEMPTS_VALUE_LENGTH,
Closure->minReadAttempts);
if(!i) pc->minAttemptsScaleA = scale;
else pc->minAttemptsScaleB = scale;
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), scale_box, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, scale_box);
}
AddHelpParagraph(lwoh,
_("<b>Minimum number of reading attempts</b>\n\n"
"If an unreadable sector is encountered, "
"dvdisaster tries to re-read it the given number of times.\n\n"
"Increasing the number of reading attempts may improve data recovery "
"on marginal media, but will also increase processing time and "
"mechanical wear on the drive."));
/* Maximum reading attempts */
lwoh = CreateLabelWithOnlineHelp(_("Maximum number of reading attempts"), "ignore");
RegisterPreferencesHelpWindow(lwoh);
LockLabelSize(GTK_LABEL(lwoh->normalLabel), _utf("Max. %d reading attempts per sector"), 100);
LockLabelSize(GTK_LABEL(lwoh->linkLabel), _utf("Max. %d reading attempts per sector"), 100);
pc->maxAttemptsScaleLwoh = lwoh;
pc->maxAttemptsScaleInfoA = g_malloc0(sizeof(non_linear_info));
pc->maxAttemptsScaleInfoB = g_malloc0(sizeof(non_linear_info));
pc->maxAttemptsScaleInfoA->format = g_strdup(_("Max. %d reading attempts per sector"));
pc->maxAttemptsScaleInfoB->format = g_strdup(_("Max. %d reading attempts per sector"));
pc->maxAttemptsScaleInfoA->lwoh = lwoh;
for(i=0; i<2; i++)
{ GtkWidget *scale,*scale_box;
scale = non_linear_scale(&scale_box,
i ? pc->maxAttemptsScaleInfoB : pc->maxAttemptsScaleInfoA,
i ? lwoh->normalLabel : lwoh->linkLabel,
pc, SLIDER_MAX_READ_ATTEMPTS, max_attempts_values, MAX_ATTEMPTS_VALUE_LENGTH,
Closure->maxReadAttempts);
if(!i) pc->maxAttemptsScaleA = scale;
else pc->maxAttemptsScaleB = scale;
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), scale_box, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, scale_box);
}
AddHelpParagraph(lwoh,
_("<b>Maximum number of reading attempts</b>\n\n"
"When the minimum number of reading attempts is reached "
"without success, dvdisaster might choose to perform additional "
"reading attempts up to this number.\n\n"
"The decision to do more attempts depends on the quality of "
"data gathered so far, which in turn is influenced by the "
"capabilities of your optical drive and the operating system. "
"So depending on your configuration, you may or "
"may not see dvdisaster using the maximum value."
));
/* Jump selector */
lwoh = CreateLabelWithOnlineHelp(_("Treatment of unreadable areas"), "ignore");
RegisterPreferencesHelpWindow(lwoh);
if( GetLabelWidth(GTK_LABEL(lwoh->normalLabel), _utf("Skip %d sectors after read error"), 20480)
> GetLabelWidth(GTK_LABEL(lwoh->normalLabel), _utf("Stop reading when unreadable intervals &lt; %d"), 20480))
{ LockLabelSize(GTK_LABEL(lwoh->normalLabel), _utf("Skip %d sectors after read error"), 20480);
LockLabelSize(GTK_LABEL(lwoh->linkLabel), _utf("Skip %d sectors after read error"), 20480);
}
else
{ LockLabelSize(GTK_LABEL(lwoh->normalLabel), _utf("Stop reading when unreadable intervals &lt; %d"), 20480);
LockLabelSize(GTK_LABEL(lwoh->linkLabel), _utf("Stop reading when unreadable intervals &lt; %d"), 20480);
}
pc->jumpScaleLwoh = lwoh;
pc->formatLinear = g_strdup(_("Skip %d sectors after read error"));
pc->formatAdaptive = g_strdup(_("Stop reading when unreadable intervals &lt; %d"));
pc->jumpScaleInfoA = g_malloc0(sizeof(non_linear_info));
pc->jumpScaleInfoB = g_malloc0(sizeof(non_linear_info));
pc->jumpScaleInfoA->format = Closure->adaptiveRead ? pc->formatAdaptive : pc->formatLinear;
pc->jumpScaleInfoB->format = Closure->adaptiveRead ? pc->formatAdaptive : pc->formatLinear;
pc->jumpScaleInfoA->lwoh = lwoh;
for(i=0; i<2; i++)
{ GtkWidget *scale, *scale_box;
scale = non_linear_scale(&scale_box,
i ? pc->jumpScaleInfoB : pc->jumpScaleInfoA,
i ? lwoh->normalLabel : lwoh->linkLabel,
pc, SLIDER_JUMP, jump_values, JUMP_VALUE_LENGTH,
Closure->sectorSkip);
if(!i) pc->jumpScaleA = scale;
else pc->jumpScaleB = scale;
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), scale_box, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, scale_box);
}
AddHelpParagraph(lwoh,
_("<b>Treatment of unreadable areas</b>\n\n"
"Defective media usually contain numerous read errors in a contigous region. "
"Skipping sectors after a read error reduces the processing time and the "
"mechanical wear on the drive, but leaves larger gaps in the image file.\n\n"
"Effects on the <b>linear reading strategy</b>:"));
AddHelpListItem(lwoh,
_("Skipping a large number of sectors (e.g. 1024) gives a quick overview of "
"damaged areas, but will usually not collect enough data for repairing the image."));
AddHelpListItem(lwoh,
_("Smaller values like 16, 32 or 64 are a good trade-off: The processing time will be"
"considerably shortened, but still enough data for repairing the image is collected.\n"));
AddHelpParagraph(lwoh,
_("The <b>adaptive reading strategy</b> uses this setting only if no error correction data "
"is available. In that case the reading process will stop when no unread areas "
"larger than the selected size remain. Values smaller than 128 <i>are not recommended</i> "
"as they cause the drive to carry out lots of laser head repositioning during the "
"final phase of the reading process. If adaptive reading with a setting of 128 is not "
"sufficient, try reading the remaining sectors with an additional linear reading pass.\n\n"
"On DVD and BD media read errors do usually extend over at least 16 sectors for technical "
"reasons. Therefore selecting a value less than 16 is not recommended for DVD and BD."
));
/** Media re-reads */
frame = gtk_frame_new(_utf("Media read attempts"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
lwoh = CreateLabelWithOnlineHelp(_("Media read attempts"),
_("Read the whole medium "));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *spin;
GtkWidget *label;
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
spin = gtk_spin_button_new_with_range(1, 200, 1);
gtk_entry_set_width_chars(GTK_ENTRY(spin), 3);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin),
Closure->readingPasses < 2 ? 1 : Closure->readingPasses);
g_signal_connect(spin, "value-changed", G_CALLBACK(spin_cb), (gpointer)SPIN_READ_MEDIUM);
gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
label = gtk_label_new(_utf(" times"));
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
if(!i)
{ pc->readMediumA = spin;
gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
gtk_container_add(GTK_CONTAINER(frame), hbox);
}
else
{ pc->readMediumB = spin;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Media read attempts</b> for the linear reading strategy\n\n"
"If unreadable sectors remain after reading the medium from start to end, "
"the medium is read again up to he given number of times.\n\n"
"Only the missing sectors will be tried in the additional reading passes."));
/** Defective sector caching */
frame = gtk_frame_new(_utf("Raw sector caching"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 20);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* Toggle button */
lwoh = CreateLabelWithOnlineHelp(_("Raw sector caching"),
_("Keep uncorrectable raw sectors in the following directory:"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *table = gtk_table_new(3,2,FALSE);
GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *label = gtk_label_new(Closure->dDumpDir);
GtkWidget *select = gtk_button_new_with_label(_utf("Select"));
button = gtk_check_button_new();
gtk_table_attach(GTK_TABLE(table), button,
0, 1, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
gtk_table_attach(GTK_TABLE(table), i ? lwoh->normalLabel : lwoh->linkBox,
1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
gtk_misc_set_alignment(GTK_MISC(lwoh->linkLabel), 0.0, 0.0);
gtk_misc_set_alignment(GTK_MISC(lwoh->normalLabel), 0.0, 0.0);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
gtk_table_attach(GTK_TABLE(table), hbox,
1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
gtk_table_attach(GTK_TABLE(table), select,
2, 3, 0, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
g_signal_connect(G_OBJECT(select), "clicked", G_CALLBACK(cache_defective_dir_cb), pc);
if(!i)
{ pc->cacheDefectiveA = button;
pc->cacheDefectiveDirA = label;
}
else
{ pc->cacheDefectiveB = button;
pc->cacheDefectiveDirB = label;
}
if(Closure->readRaw && Closure->defectiveDump)
activate_toggle_button(GTK_TOGGLE_BUTTON(button), TRUE);
else activate_toggle_button(GTK_TOGGLE_BUTTON(button), FALSE);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_CACHE_DEFECTIVE));
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), table, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, table);
}
AddHelpParagraph(lwoh,
_("<b>Raw sector caching</b>\n\n"
"Some drives are capable of delivering partial data from defective "
"sectors. While one partial sector is useless by itself, "
"20 or more of them might combine into a complete sector.\n\n"
"If you activate this button, dvdisaster will collect partial "
"sectors in the selected directory. "
"When enough parts have been gathered in subsequent reading passes, "
"the respective sector is automatically recombined from the "
"stored parts.\n\n"
"Please note that not all drives and operating systems "
"support reading partial data. "
"It is not an error of the cache directory remains empty.\n"
"dvdisaster will not remove any files from the given directory; "
"you need to clean it up manually after a successful medium recovery."
));
/* Sector cache file prefix */
lwoh = CreateLabelWithOnlineHelp(_("Raw sector file prefix"),
_("Raw sector file prefix: "));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
g_signal_connect(entry, "activate", G_CALLBACK(defective_prefix_cb), pc);
gtk_entry_set_width_chars(GTK_ENTRY(entry), 20);
gtk_entry_set_text(GTK_ENTRY(entry), Closure->dDumpPrefix);
gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
if(!i) pc->cacheDefectivePrefixA = entry;
else pc->cacheDefectivePrefixB = entry;
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, hbox);
}
AddHelpParagraph(lwoh,
_("<b>Raw sector file prefix</b>\n\n"
"Use a different prefix for each disc you are trying "
"to recover, e.g. \"disc1-\" and so on."));
/*** "Error correction" page */
/* Method chooser menu */
vbox = create_page(notebook, _utf("Error correction"));
lwoh = CreateLabelWithOnlineHelp(_("Error correction method"),
_("Storage method:"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
GtkWidget *chooser;
int j;
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
chooser = gtk_combo_box_new_text();
g_signal_connect(G_OBJECT(chooser), "changed", G_CALLBACK(method_select_cb), pc);
for(j=0; j<Closure->methodList->len; j++)
{ Method *method = g_ptr_array_index(Closure->methodList, j);
char *utf;
utf = g_locale_to_utf8(method->menuEntry, -1, NULL, NULL, NULL);
gtk_combo_box_append_text(GTK_COMBO_BOX(chooser), utf);
g_free(utf);
if(!strncmp(Closure->methodName, method->name, 4))
method_idx = j;
}
gtk_combo_box_set_active(GTK_COMBO_BOX(chooser), method_idx);
gtk_box_pack_start(GTK_BOX(hbox), chooser, FALSE, FALSE, 0);
if(!i)
{ pc->methodChooserA = chooser;
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
}
else
{ pc->methodChooserB = chooser;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh, _("<b>Error correction method</b>\n\n"
"dvdisaster creates error correction data which is used to recover "
"unreadable sectors if the disc becomes damaged later on. There are "
"different codecs and ways available for storing the error correction "
"information:\n"));
AddHelpListItem(lwoh, _("The RS01 codec\n"
"RS01 is the recommended codec for storing error correction data in separate files.\n"));
AddHelpListItem(lwoh, _("The RS02 codec\n"
"RS02 is the currently recommended codec for "
"augmenting images with error correction data.\n"));
AddHelpListItem(lwoh, _("The RS03 codec (Warning: experimental)\n"
"RS03 can either store error correction data in a separate file "
"or augment the image with it. It provides multithreading "
"to scale with multicore processors and contains some subtle improvements "
"over RS01 and RS02. However it should not be used for productive work "
"unless a stable version is released with dvdisaster V0.80."));
/* sub pages for individual method configuration */
pc->methodNotebook = gtk_notebook_new();
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(pc->methodNotebook), FALSE);
gtk_notebook_set_show_border(GTK_NOTEBOOK(pc->methodNotebook), FALSE);
gtk_box_pack_start(GTK_BOX(vbox), pc->methodNotebook, TRUE, TRUE, 0);
for(i=0; i<Closure->methodList->len; i++)
{ Method *method = g_ptr_array_index(Closure->methodList, i);
GtkWidget *vbox2 = gtk_vbox_new(FALSE, 0);
GtkWidget *ignore = gtk_label_new("method_tab");
if(method->createPrefsPage)
method->createPrefsPage(method, vbox2);
else
{ GtkWidget *lab;
lab = gtk_label_new("This method has no configuration options.");
gtk_box_pack_start(GTK_BOX(vbox2), lab, TRUE, TRUE, 0);
}
gtk_notebook_append_page(GTK_NOTEBOOK(pc->methodNotebook), vbox2, ignore);
if(i==method_idx)
gtk_notebook_set_current_page(GTK_NOTEBOOK(pc->methodNotebook), method_idx);
}
g_idle_add(notebook_idle_func, pc);
/*** "Files" page */
vbox = create_page(notebook, _utf("Files"));
/* file extension */
frame = gtk_frame_new(_utf("Local files (on hard disk)"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 15);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
lwoh = CreateLabelWithOnlineHelp(_("Automatic file suffixes"), _("Automatically add .iso and .ecc file suffixes"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->autoSuffix);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_SUFFIX));
if(!i)
{ pc->suffixA = button;
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
}
else
{ pc->suffixB = button;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Automatically add file suffixes</b>\n\n"
"When this switch is set, files will be automatically appended with \".iso\" "
"or \".ecc\" suffixes if no other file name extension is already present."));
/*** Automatic file creation and deletion */
frame = gtk_frame_new(_utf("Automatic file creation and deletion"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 15);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* automatic creation */
lwoh = CreateLabelWithOnlineHelp(_("Automatic .ecc file creation"), _("Create error correction file after reading image"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->readAndCreate);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_READ_CREATE));
if(!i)
{ pc->readAndCreateButtonA = button;
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
}
else
{ pc->readAndCreateButtonB = button;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Automatic error correction file creation</b>\n\n"
"Automatically creates an error correction file after reading an image. "
"Together with the \"Remove image\" option this will speed up error correction "
"file generation for a series of different media."));
/* automatic deletion */
lwoh = CreateLabelWithOnlineHelp(_("Automatic image file removal"), _("Remove image after error correction file creation"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->unlinkImage);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_UNLINK));
if(!i)
{ pc->unlinkImageButtonA = button;
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
}
else
{ pc->unlinkImageButtonB = button;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Automatic image file removal</b>\n\n"
"If this switch is set the image file will be deleted following the successful "
"generation of the respective error correction file."));
/*** Deletion confirmation */
frame = gtk_frame_new(_utf("Confirm file overwriting"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 15);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* automatic creation */
lwoh = CreateLabelWithOnlineHelp(_("Confirm file overwriting"), _("Ask before overwriting image and ecc files"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->confirmDeletion);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_CONFIRM_DELETION));
if(!i)
{ pc->confirmDeletionA = button;
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
}
else
{ pc->confirmDeletionB = button;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Ask before overwriting image and ecc files</b>\n\n"
"dvdisaster will ask you for confirmation "
"when it is going to overwrite an existing image "
"or error correction file if this option is checked."));
/*** GUI page */
vbox = create_page(notebook, _utf("Appearance"));
/** Color scheme
Using a table gives better control over spacing between the frames. */
table = gtk_table_new(2, 4, FALSE);
gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
vbox3 = gtk_vbox_new(FALSE, 0);
gtk_table_attach(GTK_TABLE(table), vbox3,
0, 1, 0, 3, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 5, 5);
frame = gtk_frame_new(_utf("Sector coloring"));
gtk_box_pack_start(GTK_BOX(vbox3), frame, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox3), gtk_label_new(NULL), TRUE, TRUE, 0);
vbox2 = gtk_vbox_new(FALSE, 20);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* Green color */
lwoh = CreateLabelWithOnlineHelp(_("Good sectors"), _("Good sector"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->greenSector, COLOR_GREEN);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->greenA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->greenB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Good sectors</b>\n\n"
"This color indicates good sectors."));
/* Yellow color */
lwoh = CreateLabelWithOnlineHelp(_("Checksum errors"), _("Checksum error"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->yellowSector, COLOR_YELLOW);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->yellowA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->yellowB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Checksum errors</b>\n\n"
"This color is used for displaying sectors with wrong check sums."));
/* Red color */
lwoh = CreateLabelWithOnlineHelp(_("Unreadable sectors"), _("Unreadable"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->redSector, COLOR_RED);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->redA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->redB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Unreadable sectors</b>\n\n"
"This color is used for marking unreadable sectors."));
/* Dark color */
lwoh = CreateLabelWithOnlineHelp(_("Present sectors"), _("Present sector"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->darkSector, COLOR_DARK);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->darkA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->darkB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Present sectors</b>\n\n"
"Sectors which are already present are marked with this color."));
/* Blue color */
lwoh = CreateLabelWithOnlineHelp(_("Ignored sectors"), _("Ignored sector"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->blueSector, COLOR_BLUE);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->blueA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->blueB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Ignored sectors</b>\n\n"
"Sectors marked with this color will not be processed "
"in the current run."));
/* White color */
lwoh = CreateLabelWithOnlineHelp(_("Highlit sectors"), _("Highlit sector"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->whiteSector, COLOR_WHITE);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->whiteA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->whiteB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Highlit sectors</b>\n\n"
"This color is used for temporarily highlighting "
"sectors during adaptive reading."));
/** Text colors */
frame = gtk_frame_new(_utf("Text colors"));
gtk_table_attach(GTK_TABLE(table), frame,
1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 5, 5);
vbox2 = gtk_vbox_new(FALSE, 20);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* Positive text */
lwoh = CreateLabelWithOnlineHelp(_("Positive text"), _("Positive text"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->greenText, COLOR_GREEN_TEXT);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->greenTextA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->greenTextB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Positive text</b>\n\n"
"Good news are printed in this color."));
/* Positive text */
lwoh = CreateLabelWithOnlineHelp(_("Negative text"), _("Negative text"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->redText, COLOR_RED_TEXT);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->redTextA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->redTextB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Negative text</b>\n\n"
"Bad news are printed in this color."));
/** Curve colors */
frame = gtk_frame_new(_utf("Curve colors"));
gtk_table_attach(GTK_TABLE(table), frame,
1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 5, 5);
vbox2 = gtk_vbox_new(FALSE, 20);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
/* Reading speed curve */
lwoh = CreateLabelWithOnlineHelp(_("Curve color"), _("Curve color"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->curveColor, COLOR_CURVE);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->curveColorA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->curveColorB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Curve color and labels</b>\n\n"
"The reading speed curve, its left side and top labels "
"are printed in this color."));
/* Logarithmic scale (C2 errors) */
lwoh = CreateLabelWithOnlineHelp(_("C2 errors"), _("C2 errors"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->logColor, COLOR_LOG);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->logColorA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->logColorB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>C2 error color</b>\n\n"
"The logarithmic bar graph showing the C2 errors "
"is rendered in this color during the \"read\" "
"and \"scan\" operations."));
/* Error correction load */
lwoh = CreateLabelWithOnlineHelp(_("Error correction load"), _("Error correction load"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 4);
color_button_info *cbi;
cbi = create_color_button(Closure->barColor, COLOR_BAR);
gtk_box_pack_start(GTK_BOX(hbox), cbi->button, FALSE, FALSE, 0);
if(!i)
{ gtk_box_pack_start(GTK_BOX(hbox), lwoh->linkBox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
pc->barColorA = cbi;
}
else
{
gtk_box_pack_start(GTK_BOX(hbox), lwoh->normalLabel, FALSE, FALSE, 0);
AddHelpWidget(lwoh, hbox);
pc->barColorB = cbi;
}
}
AddHelpParagraph(lwoh,
_("<b>Error correction load</b>\n\n"
"The bar graph showing the error correction load "
"is rendered in this color during the \"Fix\" operation."));
/* Padding space */
#if 0
lab = gtk_label_new("");
gtk_table_attach(GTK_TABLE(table), lab,
1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 5, 5);
#endif
/* Default color scheme */
button = gtk_button_new_with_label(_utf("Default color scheme"));
gtk_table_attach(GTK_TABLE(table), button,
1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 5, 5);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(default_color_cb), NULL);
/** Reverse OK and Cancel buttons */
frame = gtk_frame_new(_utf("Dialog boxes"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
lwoh = CreateLabelWithOnlineHelp(_("Reverse OK / Cancel buttons"), _("Reverse OK / Cancel buttons"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->reverseCancelOK);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_CANCEL_OK));
if(!i)
{ pc->cancelOKA = button;
gtk_container_add(GTK_CONTAINER(frame), hbox);
}
else
{ pc->cancelOKB = button;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Reverse OK / Cancel buttons</b>\n\n"
"This switch reverses the order of dialog buttons "
"(e.g. OK, Cancel).\n\n"
"Changes will become active after restarting dvdisaster."));
/*** "Misc" page */
vbox = create_page(notebook, _utf("Misc"));
/** Logging **/
frame = gtk_frame_new(_utf("Logging"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
vbox2 = gtk_vbox_new(FALSE, 15);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 10);
gtk_container_add(GTK_CONTAINER(frame), vbox2);
lwoh = CreateLabelWithOnlineHelp(_("Verbose logging"), _("Verbose logging"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *button = gtk_check_button_new();
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), i ? lwoh->normalLabel : lwoh->linkBox, FALSE, FALSE, 0);
activate_toggle_button(GTK_TOGGLE_BUTTON(button), Closure->verbose);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_VERBOSE));
if(!i)
{ pc->verboseA = button;
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
}
else
{ pc->verboseB = button;
AddHelpWidget(lwoh, hbox);
}
}
AddHelpParagraph(lwoh,
_("<b>Verbose logging</b>\n\n"
"More information will be supplied in the Log window "
"and/or log file. Useful for debugging, but may lead "
"to slower performance."));
/** Log file */
lwoh = CreateLabelWithOnlineHelp(_("Logfile:"),
_("Copy log to file:"));
RegisterPreferencesHelpWindow(lwoh);
for(i=0; i<2; i++)
{ GtkWidget *table = gtk_table_new(4,2,FALSE);
GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
GtkWidget *label = gtk_label_new(Closure->logFile);
GtkWidget *select = gtk_button_new_with_label(_utf("Select"));
GtkWidget *delete = gtk_button_new_with_label(_utf("Delete"));
button = gtk_check_button_new();
gtk_table_attach(GTK_TABLE(table), button,
0, 1, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
gtk_table_attach(GTK_TABLE(table), i ? lwoh->normalLabel : lwoh->linkBox,
1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
gtk_misc_set_alignment(GTK_MISC(lwoh->linkLabel), 0.0, 0.0);
gtk_misc_set_alignment(GTK_MISC(lwoh->normalLabel), 0.0, 0.0);
gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
gtk_table_attach(GTK_TABLE(table), hbox,
1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
gtk_table_attach(GTK_TABLE(table), select,
2, 3, 0, 2, GTK_SHRINK, GTK_SHRINK, 10, 0);
g_signal_connect(G_OBJECT(select), "clicked", G_CALLBACK(logfile_cb),
GINT_TO_POINTER(LOGFILE_SELECT));
gtk_table_attach(GTK_TABLE(table), delete,
3, 4, 0, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
g_signal_connect(G_OBJECT(delete), "clicked", G_CALLBACK(logfile_cb),
GINT_TO_POINTER(LOGFILE_DELETE));
if(!i)
{ pc->logFileA = button;
pc->logFilePathA = label;
}
else
{ pc->logFileB = button;
pc->logFilePathB = label;
}
if(Closure->verbose && Closure->logFileEnabled)
activate_toggle_button(GTK_TOGGLE_BUTTON(button), TRUE);
else activate_toggle_button(GTK_TOGGLE_BUTTON(button), FALSE);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_cb), GINT_TO_POINTER(TOGGLE_LOGFILE));
if(!i) gtk_box_pack_start(GTK_BOX(vbox2), table, FALSE, FALSE, 0);
else AddHelpWidget(lwoh, table);
}
AddHelpParagraph(lwoh,
_("<b>Logfile</b>\n\n"
"A copy of the logging information from the log window "
"is written to the specified log file. This is useful to "
"collect information on program crashes, but affects "
"performance negatively."));
}
/* Show the created / reused window */
gtk_widget_show_all(GTK_WIDGET(Closure->prefsWindow));
}