Files
dvdisaster/read-linear-window.c
Stéphane Lesimple 99b27b982a feat: CLI-only version (without GTK)
Modify the build system and the source
files to support building a CLI-only
version with only glib2 as a dependency.
Use CLI_ONLY=1 ./configure, then make clean all.
2020-08-19 21:21:11 +02:00

448 lines
14 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"
#include "read-linear.h"
#include "scsi-layer.h"
#define C2_CLAMP_VALUE 2352
/***
*** Forward declarations
***/
static void redraw_curve(void);
static void update_geometry(void);
/***
*** Routines for updating the GUI from the action thread.
***/
/*
* Set the (predicted) maximum reading speed
*/
static gboolean max_speed_idle_func(gpointer data)
{
gdk_window_clear(Closure->readLinearDrawingArea->window);
update_geometry();
redraw_curve();
return FALSE;
}
void InitializeCurve(void *rc_ptr, int max_rate, int can_c2)
{ read_closure *rc = (read_closure*)rc_ptr;
int i;
Closure->readLinearCurve->maxY = max_rate;
Closure->readLinearCurve->maxX = rc->image->dh->sectors/512;
Closure->readLinearCurve->logMaxY = C2_CLAMP_VALUE;
if(can_c2) Closure->readLinearCurve->enable = DRAW_FCURVE | DRAW_LCURVE;
else Closure->readLinearCurve->enable = DRAW_FCURVE;
rc->lastCopied = (1000*rc->firstSector)/rc->image->dh->sectors;
rc->lastPlotted = rc->lastSegment = rc->lastCopied;
rc->lastPlottedY = 0;
if(Closure->readLinearSpiral)
for(i=rc->lastCopied-1; i>=0; i--)
{ Closure->readLinearSpiral->segmentColor[i] = Closure->blueSector;
Closure->readLinearCurve->ivalue[i] = 0;
}
g_idle_add(max_speed_idle_func, NULL);
}
/*
* Drawing the reading speed curve
*/
typedef struct
{ read_closure *rc;
int percent;
} curve_info;
static gboolean curve_idle_func(gpointer data)
{ curve_info *ci = (curve_info*)data;
read_closure *rc=ci->rc;
gint x0,y0;
char *utf,buf[80];
gint i;
gint resize_curve = FALSE;
/*** Update the textual output */
g_snprintf(buf, 80, _("Current Speed: %d.%dx"),
(int)Closure->readLinearCurve->fvalue[ci->percent],
(int)(fmod(10*Closure->readLinearCurve->fvalue[ci->percent],10)));
utf = g_locale_to_utf8(buf, -1, NULL, NULL, NULL);
gtk_label_set_text(GTK_LABEL(Closure->readLinearSpeed), utf);
g_free(utf);
g_snprintf(buf, 80, _("Unreadable / skipped sectors: %lld"), Closure->readErrors);
utf = g_locale_to_utf8(buf, -1, NULL, NULL, NULL);
gtk_label_set_text(GTK_LABEL(Closure->readLinearErrors), utf);
g_free(utf);
/*** Draw the changed spiral segments */
for(i=rc->lastSegment; i<ci->percent; i++)
switch(Closure->readLinearCurve->ivalue[i])
{ case 0: DrawSpiralSegment(Closure->readLinearSpiral, Closure->blueSector, i); break;
case 1: DrawSpiralSegment(Closure->readLinearSpiral, Closure->greenSector, i); break;
case 2: DrawSpiralSegment(Closure->readLinearSpiral, Closure->redSector, i); break;
case 3: DrawSpiralSegment(Closure->readLinearSpiral, Closure->darkSector, i); break;
case 4: DrawSpiralSegment(Closure->readLinearSpiral, Closure->yellowSector, i); break;
}
rc->lastSegment = ci->percent;
if(rc->pass) /* 2nd or higher reading pass, don't touch the curve */
{ g_free(ci);
g_mutex_lock(rc->rendererMutex);
rc->activeRenderers--;
g_mutex_unlock(rc->rendererMutex);
return FALSE;
}
/*** Resize the Y axes if speed value exceeds current maximum */
for(i=rc->lastPlotted+1; i<=ci->percent; i++)
if(Closure->readLinearCurve->fvalue[i] > Closure->readLinearCurve->maxY)
resize_curve = TRUE;
if(resize_curve)
{ Closure->readLinearCurve->maxY = Closure->readLinearCurve->fvalue[ci->percent] + 1;
update_geometry();
gdk_window_clear(Closure->readLinearDrawingArea->window);
redraw_curve();
rc->lastPlotted = ci->percent;
rc->lastPlottedY = CurveY(Closure->readLinearCurve, Closure->readLinearCurve->fvalue[ci->percent]);
g_free(ci);
g_mutex_lock(rc->rendererMutex);
rc->activeRenderers--;
g_mutex_unlock(rc->rendererMutex);
return FALSE;
}
/*** Draw the changed curve part */
x0 = CurveX(Closure->readLinearCurve, rc->lastPlotted);
y0 = CurveY(Closure->readLinearCurve, Closure->readLinearCurve->fvalue[rc->lastPlotted]);
if(rc->lastPlottedY) y0 = rc->lastPlottedY;
for(i=rc->lastPlotted+1; i<=ci->percent; i++)
{ gint x1 = CurveX(Closure->readLinearCurve, i);
gint y1 = CurveY(Closure->readLinearCurve, Closure->readLinearCurve->fvalue[i]);
gint l1 = CurveLogY(Closure->readLinearCurve, Closure->readLinearCurve->lvalue[i]);
if(Closure->readLinearCurve->lvalue[i])
{ gdk_gc_set_rgb_fg_color(Closure->drawGC, Closure->logColor);
gdk_draw_rectangle(Closure->readLinearDrawingArea->window,
Closure->drawGC, TRUE,
x0, l1,
x0==x1 ? 1 : x1-x0, Closure->readLinearCurve->bottomLY-l1);
}
if(x0<x1)
{ gdk_gc_set_rgb_fg_color(Closure->drawGC, Closure->curveColor);
gdk_draw_line(Closure->readLinearDrawingArea->window,
Closure->drawGC,
x0, y0, x1, y1);
rc->lastPlotted = ci->percent;
x0 = x1;
rc->lastPlottedY = y0 = y1;
}
}
g_free(ci);
g_mutex_lock(rc->rendererMutex);
rc->activeRenderers--;
g_mutex_unlock(rc->rendererMutex);
return FALSE;
}
/*
* Add one new data point
*/
void AddCurveValues(void *rc_ptr, int percent, int color, int c2)
{ read_closure *rc = (read_closure*)rc_ptr;
curve_info *ci;
int i;
if(percent < 0 || percent > 1000)
return;
ci = g_malloc(sizeof(curve_info));
ci->rc = rc;
ci->percent = percent;
/*** Mark unused speed values between lastCopied and Percent */
if(!rc->pass)
{ int c2_clamped = c2 < C2_CLAMP_VALUE ? c2 : C2_CLAMP_VALUE;
Closure->readLinearCurve->fvalue[percent] = rc->speed;
Closure->readLinearCurve->lvalue[percent] = c2_clamped;
for(i=rc->lastCopied+1; i<percent; i++)
{ Closure->readLinearCurve->fvalue[i] = rc->speed > 0.0 ? -1.0 : 0.0;
Closure->readLinearCurve->lvalue[i] = c2_clamped;
}
}
/*** Mark the spiral segments between lastCopied and Percent*/
/* lastCopied+1 ? */
if(rc->lastCopied <= percent)
{ for(i=rc->lastCopied; i<=percent; i++)
Closure->readLinearCurve->ivalue[i] = color;
rc->lastCopied = percent;
}
g_mutex_lock(rc->rendererMutex);
rc->activeRenderers++;
g_mutex_unlock(rc->rendererMutex);
g_idle_add(curve_idle_func, ci);
}
/*
* Mark existing sectors with the dark green color.
*/
static gboolean curve_mark_idle_func(gpointer data)
{
DrawSpiral(Closure->readLinearSpiral);
return FALSE;
}
void MarkExistingSectors(void)
{ int i;
int x = Closure->readLinearCurve->rightX + 20;
Closure->additionalSpiralColor = 3;
DrawSpiralLabel(Closure->readLinearSpiral, Closure->readLinearCurve->layout,
_("Already present"), Closure->darkSector, x, -1);
for(i=0; i<1000; i++)
if(Closure->readLinearSpiral->segmentColor[i] == Closure->greenSector)
{ Closure->readLinearSpiral->segmentColor[i] = Closure->darkSector;
Closure->readLinearCurve->ivalue[i] = 3;
}
g_idle_add(curve_mark_idle_func, NULL);
}
/*
* Redraw the whole curve
*/
/* Calculate the geometry of the curve and spiral */
static void update_geometry(void)
{ GtkWidget *widget = Closure->readLinearDrawingArea;
GtkAllocation *a = &widget->allocation;
/* Curve geometry */
UpdateCurveGeometry(Closure->readLinearCurve, "99x",
Closure->readLinearSpiral->diameter + 30);
/* Spiral center */
Closure->readLinearSpiral->mx = a->width - 15 - Closure->readLinearSpiral->diameter / 2;
Closure->readLinearSpiral->my = a->height / 2;
if(Closure->crcBuf && Closure->crcBuf->crcCached)
{ int w,h;
SetText(Closure->readLinearCurve->layout, _("Sectors with CRC errors"), &w, &h);
Closure->readLinearSpiral->my -= h;
}
/* Label positions in the foot line */
gtk_box_set_child_packing(GTK_BOX(Closure->readLinearFootlineBox), Closure->readLinearSpeed,
TRUE, TRUE, Closure->readLinearCurve->leftX, GTK_PACK_START);
gtk_box_set_child_packing(GTK_BOX(Closure->readLinearFootlineBox), Closure->readLinearErrors,
TRUE, TRUE, Closure->readLinearCurve->leftX, GTK_PACK_START);
}
static void redraw_curve(void)
{ GdkDrawable *d = Closure->readLinearDrawingArea->window;
int x,w,h;
int pos = 1;
/* Draw and label the spiral */
x = Closure->readLinearCurve->rightX + 20;
gdk_gc_set_rgb_fg_color(Closure->drawGC, Closure->curveColor);
SetText(Closure->readLinearCurve->layout, _("Medium state"), &w, &h);
gdk_draw_layout(d, Closure->drawGC,
x,
Closure->readLinearCurve->topY - h - 5,
Closure->readLinearCurve->layout);
if(Closure->additionalSpiralColor == 0)
DrawSpiralLabel(Closure->readLinearSpiral, Closure->readLinearCurve->layout,
_("Not touched this time"), Closure->curveColor, x, -1);
if(Closure->additionalSpiralColor == 3)
DrawSpiralLabel(Closure->readLinearSpiral, Closure->readLinearCurve->layout,
_("Already present"), Closure->darkSector, x, -1);
DrawSpiralLabel(Closure->readLinearSpiral, Closure->readLinearCurve->layout,
_("Successfully read"), Closure->greenSector, x, pos++);
if(Closure->crcBuf && Closure->crcBuf->crcCached)
DrawSpiralLabel(Closure->readLinearSpiral, Closure->readLinearCurve->layout,
_("Sectors with CRC errors"), Closure->yellowSector, x, pos++);
DrawSpiralLabel(Closure->readLinearSpiral, Closure->readLinearCurve->layout,
_("Unreadable / skipped"), Closure->redSector, x, pos++);
DrawSpiral(Closure->readLinearSpiral);
/* Redraw the curve */
RedrawAxes(Closure->readLinearCurve);
RedrawCurve(Closure->readLinearCurve, 1000);
}
static gboolean expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
SetSpiralWidget(Closure->readLinearSpiral, widget);
if(event->count) /* Exposure compression */
return TRUE;
update_geometry();
redraw_curve();
return TRUE;
}
/***
*** Reset the notebook contents for new scan/read action
***/
void ResetLinearReadWindow()
{
gtk_notebook_set_current_page(GTK_NOTEBOOK(Closure->readLinearNotebook), 0);
ZeroCurve(Closure->readLinearCurve);
FillSpiral(Closure->readLinearSpiral, Closure->background);
DrawSpiral(Closure->readLinearSpiral);
}
/*
* Re-layout and redraw the read window while it is in use.
* Required to add the information that CRC data is available,
* since this happens when the the initial rendering of the window
* contents have already been carried out.
*/
static gboolean redraw_idle_func(gpointer data)
{ GdkRectangle rect;
GdkWindow *window;
gint ignore;
/* Trigger an expose event for the drawing area. */
window = gtk_widget_get_parent_window(Closure->readLinearDrawingArea);
if(window)
{ gdk_window_get_geometry(window, &rect.x, &rect.y, &rect.width, &rect.height, &ignore);
gdk_window_invalidate_rect(window, &rect, TRUE);
}
return FALSE;
}
void RedrawReadLinearWindow(void)
{
g_idle_add(redraw_idle_func, NULL);
}
/***
*** Create the notebook contents for the reading and scanning action
***/
void CreateLinearReadWindow(GtkWidget *parent)
{ GtkWidget *sep,*ignore,*d_area,*notebook,*hbox;
Closure->readLinearHeadline = gtk_label_new(NULL);
gtk_misc_set_alignment(GTK_MISC(Closure->readLinearHeadline), 0.0, 0.0);
gtk_misc_set_padding(GTK_MISC(Closure->readLinearHeadline), 5, 0);
gtk_label_set_ellipsize(GTK_LABEL(Closure->readLinearHeadline), PANGO_ELLIPSIZE_END);
gtk_box_pack_start(GTK_BOX(parent), Closure->readLinearHeadline, FALSE, FALSE, 3);
sep = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
sep = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
d_area = Closure->readLinearDrawingArea = gtk_drawing_area_new();
gtk_box_pack_start(GTK_BOX(parent), d_area, TRUE, TRUE, 0);
g_signal_connect(G_OBJECT(d_area), "expose_event", G_CALLBACK(expose_cb), NULL);
notebook = Closure->readLinearNotebook = gtk_notebook_new();
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
gtk_box_pack_end(GTK_BOX(parent), notebook, FALSE, FALSE, 0);
hbox = Closure->readLinearFootlineBox = gtk_hbox_new(FALSE, 0);
Closure->readLinearSpeed = gtk_label_new(NULL);
gtk_misc_set_alignment(GTK_MISC(Closure->readLinearSpeed), 0.0, 0.0);
gtk_box_pack_start(GTK_BOX(hbox), Closure->readLinearSpeed, FALSE, FALSE, 0);
Closure->readLinearErrors = gtk_label_new(NULL);
gtk_misc_set_alignment(GTK_MISC(Closure->readLinearErrors), 1.0, 0.0);
gtk_box_pack_start(GTK_BOX(hbox), Closure->readLinearErrors, TRUE, TRUE, 0);
ignore = gtk_label_new("progress_tab");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, ignore);
Closure->readLinearFootline = gtk_label_new(NULL);
gtk_misc_set_alignment(GTK_MISC(Closure->readLinearFootline), 0.0, 0.5);
gtk_misc_set_padding(GTK_MISC(Closure->readLinearFootline), 5, 0);
ignore = gtk_label_new("footer_tab");
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), Closure->readLinearFootline, ignore);
Closure->readLinearCurve = CreateCurve(d_area, _("Speed"), "%dx", 1000, CURVE_MEGABYTES);
Closure->readLinearCurve->leftLogLabel = g_strdup(_("C2 errors"));
Closure->readLinearSpiral = CreateSpiral(Closure->grid, Closure->background, 10, 5, 1000);
}