Files
dvdisaster/menubar.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

590 lines
19 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 <limits.h>
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
/***
*** Forward declarations
***/
static void file_select_cb(GtkWidget*, gpointer);
/***
*** The Menu and Toolbar action dispatcher
***/
typedef enum
{ MENU_FILE_IMAGE,
MENU_FILE_IMAGE_OK,
MENU_FILE_IMAGE_CANCEL,
MENU_FILE_IMAGE_DESTROY,
MENU_FILE_ECC,
MENU_FILE_ECC_OK,
MENU_FILE_ECC_CANCEL,
MENU_FILE_ECC_DESTROY,
MENU_FILE_QUIT,
MENU_TOOLS_MEDIUM_INFO,
MENU_TOOLS_RAW_EDITOR,
MENU_PREFERENCES,
MENU_HELP_MANUAL,
MENU_HELP_ABOUT,
MENU_HELP_GPL,
MENU_HELP_CHANGELOG,
MENU_HELP_CREDITS,
MENU_HELP_TODO
} menu_actions;
static void menu_cb(GtkWidget *widget, gpointer data)
{
switch(GPOINTER_TO_INT(data))
{ case MENU_FILE_IMAGE:
case MENU_FILE_ECC:
file_select_cb(widget, data);
break;
case MENU_FILE_QUIT:
/* If an action is currently running with spawned threads,
give them time to terminate cleanly. */
if(Closure->subThread)
{ Closure->stopActions = STOP_SHUTDOWN_ALL;
g_thread_join(Closure->subThread);
}
/* Extract current file selections so that they are saved in the .dvdisaster file */
g_free(Closure->imageName);
Closure->imageName = g_strdup(gtk_entry_get_text(GTK_ENTRY(Closure->imageEntry)));
if(!Closure->imageName || !strlen(Closure->imageName))
{ if(Closure->imageName) g_free(Closure->imageName);
Closure->imageName = g_strdup("none");
}
g_free(Closure->eccName);
Closure->eccName = g_strdup(gtk_entry_get_text(GTK_ENTRY(Closure->eccEntry)));
if(!Closure->eccName || !strlen(Closure->eccName))
{ if(Closure->eccName) g_free(Closure->eccName);
Closure->eccName = g_strdup("none");
}
/* and quit */
gtk_main_quit();
break;
case MENU_TOOLS_MEDIUM_INFO:
CreateMediumInfoWindow();
break;
case MENU_TOOLS_RAW_EDITOR:
CreateRawEditor();
break;
case MENU_PREFERENCES:
CreatePreferencesWindow();
break;
case MENU_HELP_MANUAL:
ShowPDF(NULL);
break;
case MENU_HELP_ABOUT:
AboutDialog();
break;
case MENU_HELP_GPL:
ShowGPL();
break;
case MENU_HELP_CHANGELOG:
ShowTextfile(_("windowtitle|Change log"),
_("<big>Change log</big>\n"
"<i>Major differences from earlier program versions.</i>"),
"CHANGELOG", NULL, NULL);
break;
case MENU_HELP_CREDITS:
ShowTextfile(_("windowtitle|Credits"),
_("<big>Credits</big>\n"
"<i>Thanks go out to...</i>"),
"CREDITS", NULL, NULL);
break;
case MENU_HELP_TODO:
ShowTextfile(_("windowtitle|To do list"),
_("<big>To do list</big>\n"
"<i>A sneak preview of coming features ... perhaps ;-)</i>"),
"TODO", NULL, NULL);
break;
default:
g_print("Menu/Toolbar action %d\n",GPOINTER_TO_INT(data));
break;
}
}
/***
*** The Menu system
***/
/*
* Helper functions for creating the menu system
*/
static GtkWidget* add_menu_button(GtkWidget *parent, char *title, int action)
{ char *utf_title = g_locale_to_utf8(title, -1, NULL, NULL, NULL);
GtkWidget *item;
item = gtk_menu_item_new_with_label(utf_title);
g_free(utf_title);
gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu_cb), GINT_TO_POINTER(action));
return item;
}
static void add_menu_separator(GtkWidget *parent)
{ GtkWidget *sep;
sep = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(parent), sep);
}
#if 0
static void append_sub_menu(GtkWidget *parent, GtkWidget *strip, char *name)
{ char *utf_name = g_locale_to_utf8(name, -1, NULL, NULL, NULL);
GtkWidget *anchor;
anchor = gtk_menu_item_new_with_label(utf_name);
g_free(utf_name);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(anchor), strip);
gtk_menu_shell_append(GTK_MENU_SHELL(parent), anchor);
}
#endif
/*
* Assemble the menu system.
* Using the itemfactory would make things more complicated wrt localization.
*/
GtkWidget *CreateMenuBar(GtkWidget *parent)
{ GtkWidget *menu_bar, *menu_anchor, *menu_strip, *item;
/* The overall menu bar */
menu_bar = gtk_menu_bar_new();
// gtk_widget_set_name(menu_bar, "menu-bar");
/* The file menu */
menu_strip = gtk_menu_new();
Closure->fileMenuImage = add_menu_button(menu_strip, _("menu|Select Image"), MENU_FILE_IMAGE);
Closure->fileMenuEcc = add_menu_button(menu_strip, _("menu|Select Parity File"), MENU_FILE_ECC);
add_menu_button(menu_strip, _("menu|Quit"), MENU_FILE_QUIT);
menu_anchor = gtk_menu_item_new_with_label(_utf("menu|File"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_anchor), menu_strip);
gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), menu_anchor);
/* The tools menu */
menu_strip = gtk_menu_new();
item = add_menu_button(menu_strip, _("menu|Medium info"), MENU_TOOLS_MEDIUM_INFO);
if(!Closure->deviceNodes->len)
gtk_widget_set_sensitive(item, FALSE);
if(Closure->debugMode && !Closure->screenShotMode)
add_menu_button(menu_strip, _("menu|Raw sector editor"), MENU_TOOLS_RAW_EDITOR);
Closure->toolMenuAnchor = menu_anchor = gtk_menu_item_new_with_label(_utf("menu|Tools"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_anchor), menu_strip);
gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), menu_anchor);
/* The help menu */
menu_strip = gtk_menu_new();
add_menu_button(menu_strip, _("menu|About"), MENU_HELP_ABOUT);
add_menu_button(menu_strip, _("menu|User manual"), MENU_HELP_MANUAL);
add_menu_separator(menu_strip);
add_menu_button(menu_strip, _("menu|Credits"), MENU_HELP_CREDITS);
add_menu_button(menu_strip, _("menu|Licence (GPL)"), MENU_HELP_GPL);
add_menu_separator(menu_strip);
add_menu_button(menu_strip, _("menu|Change log"), MENU_HELP_CHANGELOG);
add_menu_button(menu_strip, _("menu|To do list"), MENU_HELP_TODO);
menu_anchor = gtk_menu_item_new_with_label(_utf("menu|Help"));
gtk_menu_item_right_justify(GTK_MENU_ITEM(menu_anchor));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_anchor), menu_strip);
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_anchor);
return menu_bar;
}
/***
*** The toolbar
***/
/*
* Callback for displaying the help message
*/
static gint tooltip_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
{
switch(event->type)
{ case GDK_ENTER_NOTIFY:
gtk_label_set_text(Closure->status, (gchar*)data);
break;
case GDK_LEAVE_NOTIFY:
gtk_label_set_text(Closure->status, "");
break;
default:
break;
}
return FALSE; /* don't intercept the default button callbacks! */
}
void AttachTooltip(GtkWidget *widget, char *short_descr, char *long_descr)
{ char *long_copy = g_locale_to_utf8(long_descr, -1, NULL, NULL, NULL);
char *short_copy = g_locale_to_utf8(short_descr, -1, NULL, NULL, NULL);
g_signal_connect(G_OBJECT(widget), "enter_notify_event", G_CALLBACK(tooltip_cb), (gpointer)long_copy);
g_signal_connect(G_OBJECT(widget), "leave_notify_event", G_CALLBACK(tooltip_cb), (gpointer)long_copy);
gtk_tooltips_set_tip(Closure->tooltips, widget, short_copy, long_copy);
g_free(short_copy);
FORGET(long_copy); /* long_copy must be kept during programs life */
}
/*
* Callback for drive selection
*/
static void drive_select_cb(GtkWidget *widget, gpointer data)
{ int n;
char *dnode;
if(!Closure->deviceNodes->len) /* No drives available */
return;
n = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
if(n<0)
return;
dnode = g_ptr_array_index(Closure->deviceNodes, n);
g_free(Closure->device);
Closure->device = g_strdup(dnode);
if(Closure->mediumDrive) /* propagate to medium info window */
gtk_combo_box_set_active(GTK_COMBO_BOX(Closure->mediumDrive), n);
}
/*
* Callback for the image and ecc file selection.
* Creates and runs the file selection dialogs.
*/
static void file_select_cb(GtkWidget *widget, gpointer data)
{ int action = GPOINTER_TO_INT(data);
switch(action)
{ /*** Image file selection */
case MENU_FILE_IMAGE:
if(!Closure->imageFileSel)
{ Closure->imageFileSel = gtk_file_selection_new(_utf("windowtitle|Image file selection"));
ReverseCancelOK(GTK_DIALOG(Closure->imageFileSel));
g_signal_connect(G_OBJECT(Closure->imageFileSel), "destroy",
G_CALLBACK(file_select_cb), GINT_TO_POINTER(MENU_FILE_IMAGE_DESTROY));
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(Closure->imageFileSel)->ok_button),"clicked",
G_CALLBACK(file_select_cb), GINT_TO_POINTER(MENU_FILE_IMAGE_OK));
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(Closure->imageFileSel)->cancel_button),"clicked",
G_CALLBACK(file_select_cb), GINT_TO_POINTER(MENU_FILE_IMAGE_CANCEL));
}
gtk_file_selection_set_filename(GTK_FILE_SELECTION(Closure->imageFileSel),
gtk_entry_get_text(GTK_ENTRY(Closure->imageEntry)));
gtk_widget_show(Closure->imageFileSel);
break;
case MENU_FILE_IMAGE_DESTROY:
Closure->imageFileSel = NULL;
break;
case MENU_FILE_IMAGE_OK:
g_free(Closure->imageName);
Closure->imageName = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(Closure->imageFileSel)));
if(Closure->autoSuffix)
Closure->imageName = ApplyAutoSuffix(Closure->imageName, "iso");
gtk_entry_set_text(GTK_ENTRY(Closure->imageEntry), Closure->imageName);
gtk_editable_set_position(GTK_EDITABLE(Closure->imageEntry), -1);
gtk_widget_hide(Closure->imageFileSel);
break;
case MENU_FILE_IMAGE_CANCEL:
gtk_widget_hide(Closure->imageFileSel);
break;
/*** Same stuff again for ecc file selection */
case MENU_FILE_ECC:
if(!Closure->eccFileSel)
{ Closure->eccFileSel = gtk_file_selection_new(_utf("windowtitle|Error correction file selection"));
ReverseCancelOK(GTK_DIALOG(Closure->eccFileSel));
g_signal_connect(G_OBJECT(Closure->eccFileSel), "destroy",
G_CALLBACK(file_select_cb), GINT_TO_POINTER(MENU_FILE_ECC_DESTROY));
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(Closure->eccFileSel)->ok_button),"clicked",
G_CALLBACK(file_select_cb), GINT_TO_POINTER(MENU_FILE_ECC_OK));
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(Closure->eccFileSel)->cancel_button),"clicked",
G_CALLBACK(file_select_cb), GINT_TO_POINTER(MENU_FILE_ECC_CANCEL));
}
gtk_file_selection_set_filename(GTK_FILE_SELECTION(Closure->eccFileSel),
gtk_entry_get_text(GTK_ENTRY(Closure->eccEntry)));
gtk_widget_show(Closure->eccFileSel);
break;
case MENU_FILE_ECC_DESTROY:
Closure->eccFileSel = NULL;
break;
case MENU_FILE_ECC_OK:
g_free(Closure->eccName);
Closure->eccName = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(Closure->eccFileSel)));
if(Closure->autoSuffix)
Closure->eccName = ApplyAutoSuffix(Closure->eccName, "ecc");
gtk_entry_set_text(GTK_ENTRY(Closure->eccEntry), Closure->eccName);
gtk_editable_set_position(GTK_EDITABLE(Closure->eccEntry), -1);
gtk_widget_hide(Closure->eccFileSel);
break;
case MENU_FILE_ECC_CANCEL:
gtk_widget_hide(Closure->eccFileSel);
break;
}
}
/*
* Set file path for a text entry.
* Completes relative paths.
*/
void set_path(GtkWidget *entry, char *path)
{
if(path[0] == '/' || path[0] == '\\' || path[1] == ':' || strlen(path) < 1)
{ gtk_entry_set_text(GTK_ENTRY(entry), path);
gtk_editable_set_position(GTK_EDITABLE(entry), -1);
}
else
{ char buf[PATH_MAX + strlen(path) + 2];
if (!getcwd(buf, PATH_MAX)) return;
strcat(buf,"/");
strcat(buf,path);
gtk_entry_set_text(GTK_ENTRY(entry), buf);
gtk_editable_set_position(GTK_EDITABLE(entry), -1);
}
}
/*
* Callback for adding file suffixes
*/
static void suffix_cb(GtkWidget *widget, gpointer data)
{ int ecc_file = GPOINTER_TO_INT(data);
if(!Closure->autoSuffix)
return;
if(!ecc_file)
{ Closure->imageName = g_strdup(gtk_entry_get_text(GTK_ENTRY(Closure->imageEntry)));
Closure->imageName = ApplyAutoSuffix(Closure->imageName, "iso");
gtk_entry_set_text(GTK_ENTRY(Closure->imageEntry), Closure->imageName);
}
else
{ Closure->eccName = g_strdup(gtk_entry_get_text(GTK_ENTRY(Closure->eccEntry)));
Closure->eccName = ApplyAutoSuffix(Closure->eccName, "ecc");
gtk_entry_set_text(GTK_ENTRY(Closure->eccEntry), Closure->eccName);
}
}
/*
* Create the toolbar
*/
GtkWidget *CreateToolBar(GtkWidget *parent)
{ GtkWidget *box, *button, *ebox, *icon, *prefs, *help, *quit, *sep, *space;
GtkWidget *combo_box;
int dev_idx = 0;
unsigned int i;
/*** Create the toolbar */
box = gtk_hbox_new(FALSE, 0);
/*** Drive selection */
space = gtk_label_new(NULL);
gtk_box_pack_start(GTK_BOX(box), space, FALSE, FALSE, 5);
ebox = gtk_event_box_new();
gtk_widget_set_events(ebox, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
gtk_box_pack_start(GTK_BOX(box), ebox, FALSE, FALSE, 0);
AttachTooltip(ebox, _("tooltip|Drive selection"), _("Use the nearby drop-down list to select the input drive."));
icon = gtk_image_new_from_stock("dvdisaster-cd", GTK_ICON_SIZE_LARGE_TOOLBAR);
gtk_container_add(GTK_CONTAINER(ebox), icon);
Closure->driveCombo = combo_box = gtk_combo_box_new_text();
g_signal_connect(G_OBJECT(combo_box), "changed", G_CALLBACK(drive_select_cb), NULL);
for(i=0; i<Closure->deviceNames->len; i++)
{
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box),
g_ptr_array_index(Closure->deviceNames,i));
if(!strcmp(Closure->device, g_ptr_array_index(Closure->deviceNodes,i)))
dev_idx = i;
}
if(!Closure->deviceNodes->len)
{ gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), _utf("No drives found"));
}
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), dev_idx);
gtk_widget_set_size_request(combo_box, 200, -1);
gtk_box_pack_start(GTK_BOX(box), combo_box, FALSE, FALSE, 7);
AttachTooltip(combo_box, _("tooltip|Drive selection"), _("Selects the input drive for reading images."));
space = gtk_label_new(NULL);
gtk_box_pack_start(GTK_BOX(box), space, FALSE, FALSE, 1);
sep = gtk_vseparator_new();
gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 3);
/*** Image file selection */
icon = gtk_image_new_from_stock("dvdisaster-open-img", GTK_ICON_SIZE_LARGE_TOOLBAR);
button = gtk_button_new();
gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
gtk_container_add(GTK_CONTAINER(button), icon);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(file_select_cb),
GINT_TO_POINTER(MENU_FILE_IMAGE));
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
Closure->imageEntry = gtk_entry_new();
set_path(Closure->imageEntry, Closure->imageName);
g_signal_connect(G_OBJECT(Closure->imageEntry), "activate",
G_CALLBACK(suffix_cb), GINT_TO_POINTER(FALSE));
gtk_box_pack_start(GTK_BOX(box), Closure->imageEntry, TRUE, TRUE, 0);
space = gtk_label_new(NULL);
gtk_box_pack_start(GTK_BOX(box), space, FALSE, FALSE, 5);
sep = gtk_vseparator_new();
gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 3);
AttachTooltip(button, _("tooltip|Image file selection"), _("Selects a new image file."));
AttachTooltip(Closure->imageEntry, _("tooltip|Current image file"), _("Shows the name of the current image file."));
/*** Ecc file selection */
icon = gtk_image_new_from_stock("dvdisaster-open-ecc", GTK_ICON_SIZE_LARGE_TOOLBAR);
button = gtk_button_new();
gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
gtk_container_add(GTK_CONTAINER(button), icon);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(file_select_cb),
GINT_TO_POINTER(MENU_FILE_ECC));
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
Closure->eccEntry = gtk_entry_new();
set_path(Closure->eccEntry, Closure->eccName);
g_signal_connect(G_OBJECT(Closure->eccEntry), "activate",
G_CALLBACK(suffix_cb), GINT_TO_POINTER(TRUE));
gtk_box_pack_start(GTK_BOX(box), Closure->eccEntry, TRUE, TRUE, 0);
space = gtk_label_new(NULL);
gtk_box_pack_start(GTK_BOX(box), space, FALSE, FALSE, 5);
sep = gtk_vseparator_new();
gtk_box_pack_start(GTK_BOX(box), sep, FALSE, FALSE, 3);
AttachTooltip(button, _("tooltip|Error correction file selection"), _("Selects a new error correction file."));
AttachTooltip(Closure->eccEntry, _("tooltip|Current error correction file"), _("Shows the name of the current error correction file."));
/*** Preferences button */
icon = gtk_image_new_from_stock("dvdisaster-gtk-preferences", GTK_ICON_SIZE_LARGE_TOOLBAR);
Closure->prefsButton = prefs = gtk_button_new();
gtk_button_set_relief(GTK_BUTTON(prefs), GTK_RELIEF_NONE);
gtk_container_add(GTK_CONTAINER(prefs), icon);
g_signal_connect(G_OBJECT(prefs), "clicked", G_CALLBACK(menu_cb), (gpointer)MENU_PREFERENCES);
gtk_box_pack_start(GTK_BOX(box), prefs, FALSE, FALSE, 0);
AttachTooltip(prefs, _("tooltip|Preferences"), _("Customize settings for creating images, error correction files and other stuff."));
/*** Help button */
icon = gtk_image_new_from_stock("dvdisaster-gtk-help", GTK_ICON_SIZE_LARGE_TOOLBAR);
Closure->helpButton = help = gtk_button_new();
gtk_button_set_relief(GTK_BUTTON(help), GTK_RELIEF_NONE);
gtk_container_add(GTK_CONTAINER(help), icon);
g_signal_connect(G_OBJECT(help), "clicked", G_CALLBACK(menu_cb), (gpointer)MENU_HELP_MANUAL);
gtk_box_pack_start(GTK_BOX(box), help, FALSE, FALSE, 0);
AttachTooltip(help, _("tooltip|User manual"), _("Displays the user manual (external PDF viewer required)."));
/*** Quit button */
icon = gtk_image_new_from_stock("dvdisaster-gtk-quit", GTK_ICON_SIZE_LARGE_TOOLBAR);
quit = gtk_button_new();
gtk_button_set_relief(GTK_BUTTON(quit), GTK_RELIEF_NONE);
gtk_container_add(GTK_CONTAINER(quit), icon);
g_signal_connect(G_OBJECT(quit), "clicked", G_CALLBACK(menu_cb), (gpointer)MENU_FILE_QUIT);
gtk_box_pack_start(GTK_BOX(box), quit, FALSE, FALSE, 0);
AttachTooltip(quit, _("tooltip|Quit"), _("Quit dvdisaster"));
return box;
}