summaryrefslogtreecommitdiff
path: root/src/xsane-back-gtk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xsane-back-gtk.c')
-rw-r--r--src/xsane-back-gtk.c1622
1 files changed, 1622 insertions, 0 deletions
diff --git a/src/xsane-back-gtk.c b/src/xsane-back-gtk.c
new file mode 100644
index 0000000..bced94d
--- /dev/null
+++ b/src/xsane-back-gtk.c
@@ -0,0 +1,1622 @@
+/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend
+
+ xsane-back-gtk.c
+
+ Oliver Rauch <Oliver.Rauch@rauch-domain.de>
+ Copyright (C) 1998-2002 Oliver Rauch
+ This file is part of the XSANE package.
+
+ This program 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 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+#include "xsane.h"
+#include "xsane-back-gtk.h"
+#include "xsane-front-gtk.h"
+#include "xsane-preferences.h"
+#include "xsane-gamma.h"
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+/* extern declarations */
+extern void xsane_panel_build(void);
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+/* forward declarations: */
+SANE_Status xsane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int *info);
+const SANE_Option_Descriptor *xsane_get_option_descriptor(SANE_Handle handle, SANE_Int option);
+const char *xsane_back_gtk_unit_string(SANE_Unit unit);
+void xsane_back_gtk_set_tooltip(GtkTooltips *tooltips, GtkWidget *widget, const gchar *desc);
+int xsane_back_gtk_make_path(size_t buf_size, char *buf, const char *prog_name, const char *dir_name,
+ const char *prefix, const char *dev_name, const char *postfix, int location);
+void xsane_back_gtk_set_option(int opt_num, void *val, SANE_Action action);
+
+static void xsane_back_gtk_panel_rebuild(void);
+void xsane_set_sensitivity(SANE_Int sensitivity);
+void xsane_set_window_icon(GtkWidget *gtk_window, gchar **xpm_d);
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_bound_int(int *value, int min, int max)
+{
+ DBG(DBG_proc3, "xsane_bound_int\n");
+
+ if (min > max)
+ {
+ int help = min;
+ min = max;
+ max = help;
+ }
+
+ if (*value < min)
+ {
+ *value = min;
+ }
+
+ if (*value > max)
+ {
+ *value = max;
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_bound_float(float *value, float min, float max)
+{
+ DBG(DBG_proc3, "xsane_bound_float\n");
+
+ if (min > max)
+ {
+ double help = min;
+ min = max;
+ max = help;
+ }
+
+ if (*value < min)
+ {
+ *value = min;
+ }
+
+ if (*value > max)
+ {
+ *value = max;
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_bound_double(double *value, double min, double max)
+{
+ DBG(DBG_proc3, "xsane_bound_double\n");
+
+ if (min > max)
+ {
+ double help = min;
+ min = max;
+ max = help;
+ }
+
+ if (*value < min)
+ {
+ *value = min;
+ }
+
+ if (*value > max)
+ {
+ *value = max;
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+/* returns 1 if value is in bounds */
+int xsane_check_bound_double(double value, double min, double max)
+{
+ int in_bounds = 1;
+
+ DBG(DBG_proc3, "xsane_check_bound_double\n");
+
+ if (min > max)
+ {
+ double help = min;
+ min = max;
+ max = help;
+ }
+
+ if (value < min)
+ {
+ in_bounds = 0;
+ }
+
+ if (value > max)
+ {
+ in_bounds = 0;
+ }
+
+ return (in_bounds);
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+const SANE_Option_Descriptor *xsane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
+{
+ DBG(DBG_optdesc, "xsane_get_option_descriptor(%d)\n", option);
+
+ if (option >= 0)
+ {
+ return sane_get_option_descriptor(handle, option);
+ }
+ return NULL;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+SANE_Status xsane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int *info)
+{
+ DBG(DBG_proc, "xsane_control_option(option = %d, action = %d)\n", option, action);
+
+ if (option >= 0)
+ {
+ SANE_Status status;
+
+ status = sane_control_option(handle, option, action, val, info);
+ if (status)
+ {
+ DBG(DBG_error, "ERROR: xsane_control_option(option = %d, action = %d) failed\n", option, action);
+ }
+
+ return status;
+ }
+
+ return SANE_STATUS_INVAL;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+const char *xsane_back_gtk_unit_string(SANE_Unit unit)
+{
+ DBG(DBG_proc, "xsane_back_gtk_unit_string\n");
+
+ switch (unit)
+ {
+ case SANE_UNIT_NONE: return "none";
+ case SANE_UNIT_PIXEL: return "px";
+ case SANE_UNIT_BIT: return "bit";
+ case SANE_UNIT_DPI: return "dpi";
+ case SANE_UNIT_PERCENT: return "%";
+ case SANE_UNIT_MM:
+ if (preferences.length_unit > 9.9 && preferences.length_unit < 10.1)
+ {
+ return "cm";
+ }
+ else if (preferences.length_unit > 25.3 && preferences.length_unit < 25.5)
+ {
+ return "in";
+ }
+ return "mm";
+ case SANE_UNIT_MICROSECOND: return "\265s";
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_set_tooltip(GtkTooltips *tooltips, GtkWidget *widget, const gchar *desc)
+{
+ DBG(DBG_proc, "xsane_back_gtk_set_tooltip\n");
+
+ if (desc && desc[0])
+ {
+ gtk_tooltips_set_tip(tooltips, widget, desc, 0);
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+int xsane_back_gtk_make_path(size_t buf_size, char *buf, const char *prog_name, const char *dir_name,
+ const char *prefix, const char *dev_name, const char *postfix, int location)
+{
+ size_t len, extra;
+ int i;
+
+ DBG(DBG_proc, "xsane_back_gtk_make_path\n");
+
+ if (location == XSANE_PATH_LOCAL_SANE) /* make path to local file */
+ {
+ if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL)
+ {
+ snprintf(buf, buf_size-2, "%s%c.sane", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), SLASH);
+ }
+ else
+ {
+ snprintf(buf, buf_size-2, "%s", STRINGIFY(XSANE_FIXED_HOME_PATH));
+ }
+ mkdir(buf, 0777); /* ensure ~/.sane directory exists */
+ }
+ else if (location == XSANE_PATH_SYSTEM) /* make path to system file */
+ {
+ snprintf(buf, buf_size-2, "%s", STRINGIFY(PATH_SANE_DATA_DIR));
+ }
+ else /* make path to temporary file */
+ {
+ snprintf(buf, buf_size-2, "%s", preferences.tmp_path);
+ }
+
+ len = strlen(buf);
+
+ buf[len++] = SLASH;
+
+ if (prog_name)
+ {
+ extra = strlen(prog_name);
+ if (len + extra + 2 >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+ memcpy(buf + len, prog_name, extra);
+ len += extra;
+
+ buf[len] = '\0';
+ mkdir(buf, 0777); /* ensure ~/.sane/PROG_NAME directory exists */
+
+ buf[len++] = SLASH; /* OS/2 does not like slash at end of mktemp-path */
+ }
+ if (len >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+ if (dir_name)
+ {
+ extra = strlen(dir_name);
+ if (len + extra + 2 >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+ memcpy(buf + len, dir_name, extra);
+ len += extra;
+
+ buf[len++] = SLASH;
+
+ buf[len] = '\0';
+ mkdir(buf, 0777); /* ensure DIR_NAME directory exists */
+ }
+
+ if (len >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+
+ if (prefix)
+ {
+ extra = strlen(prefix);
+ if (len + extra >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+ memcpy(buf + len, prefix, extra);
+ len += extra;
+ }
+
+ if (dev_name)
+ {
+ /* Turn devicename into valid filename by replacing slashes by "_", "_" gets "__", spaces are erased */
+
+ for (i = 0; dev_name[i]; ++i)
+ {
+ if (len + 2 >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+ switch (dev_name[i])
+ {
+ case '\\': /* "\" -> "_" */
+ buf[len++] = '_';
+ break;
+
+ case '/': /* "/" -> "_" */
+ buf[len++] = '_';
+ break;
+
+#ifdef _WIN32
+ case ':': /* ":" -> "_" */
+ buf[len++] = '_';
+ break;
+#endif
+
+#ifdef HAVE_OS2_H
+ case ':': /* ":" -> "_" */
+ buf[len++] = '_';
+ break;
+#endif
+
+ case ' ': /* erase " " */
+ break;
+
+ case '_': /* "_" -> "__" */
+ buf[len++] = '_';
+ /* fall through */
+ default:
+ buf[len++] = dev_name[i];
+ break;
+ }
+ }
+ }
+
+ if (postfix)
+ {
+ extra = strlen(postfix);
+ if (len + extra >= buf_size)
+ {
+ goto filename_too_long;
+ }
+ memcpy(buf + len, postfix, extra);
+ len += extra;
+ }
+
+ if (len >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+ if (location == XSANE_PATH_TMP) /* tmp dir, add uid */
+ {
+ char tmpbuf[256];
+ uid_t uid;
+ int fd;
+
+ uid = getuid();
+ snprintf(tmpbuf, sizeof(tmpbuf), "-%d-", uid);
+
+ extra = strlen(tmpbuf);
+ if (len + extra >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+ memcpy(buf + len, tmpbuf, extra);
+ len += extra;
+
+ if (len + 7 >= buf_size)
+ {
+ goto filename_too_long;
+ }
+
+ memcpy(buf + len, "XXXXXX", 6); /* create unique filename */
+ len += 6;
+ buf[len] = '\0';
+
+#if 1
+ fd = mkstemp(buf); /* create unique filename and opens/creates the file */
+#else
+ mktemp(buf); /* not safe */
+ umask(0177);
+ fd = open(buf, O_WRONLY | O_EXCL | O_CREAT, 0600);
+ umask(XSANE_DEFAULT_UMASK); /* define new file permissions */
+#endif
+
+ if (fd == -1)
+ {
+ xsane_back_gtk_error(ERR_CREATE_TEMP_FILE, FALSE);
+ return -1;
+ }
+ close(fd); /* will be opened again later */
+ }
+ else
+ {
+ buf[len++] = '\0';
+ }
+
+ DBG(DBG_proc, "path = \"%s\"\n", buf);
+
+ return 0;
+
+
+filename_too_long:
+ xsane_back_gtk_error(ERR_FILENAME_TOO_LONG, FALSE);
+ errno = E2BIG;
+ return -1;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_set_option(int opt_num, void *val, SANE_Action action)
+{
+ SANE_Status status;
+ SANE_Int info;
+ char buf[256];
+ int old_colors = xsane.xsane_colors;
+ int update_gamma = FALSE;
+
+ DBG(DBG_proc, "xsane_back_gtk_set_option\n");
+
+ status = xsane_control_option(xsane.dev, opt_num, action, val, &info);
+ if (status != SANE_STATUS_GOOD)
+ {
+ snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_SET_OPTION, xsane_get_option_descriptor(xsane.dev, opt_num)->name,
+ XSANE_STRSTATUS(status));
+ xsane_back_gtk_error(buf, FALSE);
+ return;
+ }
+
+ if (info & SANE_INFO_RELOAD_PARAMS)
+ {
+ xsane_update_param(0);
+ }
+
+ if (info & SANE_INFO_RELOAD_OPTIONS)
+ {
+ xsane_back_gtk_panel_rebuild();
+
+ if (xsane.preview)
+ {
+ preview_update_surface(xsane.preview, 0);
+ }
+
+ update_gamma = TRUE; /* scanner gamma correction may have changed, medium may need update */
+ }
+
+ if (xsane.xsane_colors != old_colors)
+ {
+ /* we have to update gamma tables and histogram because medium settings */
+ /* may have changed */
+ update_gamma = TRUE;
+ }
+
+ if (update_gamma)
+ {
+ xsane_update_gamma_curve(TRUE);
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_close_dialog_callback(GtkWidget * widget, gpointer data)
+{
+ DBG(DBG_proc, "xsane_back_gtk_close_dialog_callback\n");
+
+ gtk_widget_destroy(data);
+ xsane.back_gtk_message_dialog_active = 0;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static gint decision_flag;
+static GtkWidget *decision_dialog;
+
+void xsane_back_gtk_decision_callback(GtkWidget * widget, gpointer data)
+{
+ DBG(DBG_proc, "xsane_back_gtk_decision_callback\n");
+
+ gtk_widget_destroy(decision_dialog);
+ xsane.back_gtk_message_dialog_active = 0;
+ decision_flag = (long) data;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+gint xsane_back_gtk_decision(gchar *title, gchar **xpm_d, gchar *message, gchar *oktext, gchar *rejecttext, int wait)
+{
+ GtkWidget *main_vbox, *hbox, *label, *button;
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
+ GtkWidget *pixmapwidget;
+
+ DBG(DBG_proc, "xsane_back_gtk_decision\n");
+
+ if (xsane.back_gtk_message_dialog_active)
+ {
+ DBG(DBG_error0, "%s: %s\n", title, message);
+ return TRUE;
+ }
+ xsane.back_gtk_message_dialog_active = 1;
+ decision_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_window_set_position(GTK_WINDOW(decision_dialog), GTK_WIN_POS_MOUSE);
+ gtk_window_set_title(GTK_WINDOW(decision_dialog), title);
+ gtk_signal_connect(GTK_OBJECT(decision_dialog), "delete_event",
+ GTK_SIGNAL_FUNC(xsane_back_gtk_decision_callback), (void *) -1); /* -1 = cancel */
+
+ xsane_set_window_icon(decision_dialog, 0);
+
+ /* create the main vbox */
+ main_vbox = gtk_vbox_new(TRUE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 5);
+ gtk_widget_show(main_vbox);
+
+ gtk_container_add(GTK_CONTAINER(decision_dialog), main_vbox);
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+ gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, FALSE, 0);
+
+ /* the info icon */
+ if (xpm_d)
+ {
+ pixmap = gdk_pixmap_create_from_xpm_d(decision_dialog->window, &mask, xsane.bg_trans, xpm_d);
+ pixmapwidget = gtk_pixmap_new(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 10);
+ gtk_widget_show(pixmapwidget);
+ gdk_pixmap_unref(pixmap);
+ }
+
+ /* the message */
+ label = gtk_label_new(message);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ gtk_widget_show(hbox);
+
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+ gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, FALSE, 0);
+
+ /* the confirmation button */
+ button = gtk_button_new_with_label(oktext);
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_back_gtk_decision_callback, (void *) 1 /* confirm */);
+ gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5);
+ gtk_widget_grab_default(button);
+ gtk_widget_show(button);
+
+
+ if (rejecttext) /* the rejection button */
+ {
+ button = gtk_button_new_with_label(rejecttext);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_back_gtk_decision_callback, (void *) -1 /* reject */);
+ gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5);
+ gtk_widget_show(button);
+ }
+ gtk_widget_show(hbox);
+
+ gtk_widget_show(decision_dialog);
+
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+
+ if (!wait)
+ {
+ return TRUE;
+ }
+
+ decision_flag = 0;
+
+ while (decision_flag == 0)
+ {
+ gtk_main_iteration();
+ }
+
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+
+ if (decision_flag == 1)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_message(gchar *title, gchar **icon_xpm, gchar *message, int wait)
+{
+ DBG(DBG_proc, "xsane_back_gtk_message\n");
+
+ xsane_back_gtk_decision(title, icon_xpm, message, BUTTON_OK, 0 /* no reject text */, wait);
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_error(gchar *error, int wait)
+{
+ DBG(DBG_proc, "xsane_back_gtk_error: %s\n", error);
+
+ if (wait)
+ {
+ SANE_Int old_sensitivity = xsane.sensitivity;
+
+ xsane_set_sensitivity(FALSE);
+ xsane_back_gtk_message(ERR_HEADER_ERROR, (gchar**) error_xpm, error, wait);
+ xsane_set_sensitivity(old_sensitivity);
+ }
+ else
+ {
+ xsane_back_gtk_message(ERR_HEADER_ERROR, (gchar **) error_xpm, error, wait);
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_warning(gchar *warning, int wait)
+{
+ DBG(DBG_proc, "xsane_back_gtk_warning: %s\n", warning);
+
+ if (wait)
+ {
+ SANE_Int old_sensitivity = xsane.sensitivity;
+
+ xsane_set_sensitivity(FALSE);
+ xsane_back_gtk_message(ERR_HEADER_WARNING, (gchar**) warning_xpm, warning, wait);
+ xsane_set_sensitivity(old_sensitivity);
+ }
+ else
+ {
+ xsane_back_gtk_message(ERR_HEADER_WARNING, (gchar**) warning_xpm, warning, wait);
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_info(gchar *info, int wait)
+{
+ DBG(DBG_proc, "xsane_back_gtk_info: %s\n", info);
+
+ if (wait)
+ {
+ SANE_Int old_sensitivity = xsane.sensitivity;
+
+ xsane_set_sensitivity(FALSE);
+ xsane_back_gtk_message(ERR_HEADER_INFO, (gchar**) info_xpm, info, wait);
+ xsane_set_sensitivity(old_sensitivity);
+ }
+ else
+ {
+ xsane_back_gtk_message(ERR_HEADER_INFO, (gchar**) info_xpm, info, wait);
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_back_gtk_get_filename_button_clicked(GtkWidget *w, gpointer data)
+{
+ int *clicked = data;
+
+ DBG(DBG_proc, "xsane_back_gtk_get_filename_button_clicked\n");
+ *clicked = 1;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename,
+ int show_fileopts, int shorten_path, int hide_file_list)
+{
+ int cancel = 0, ok = 0, destroy = 0;
+ GtkWidget *fileselection;
+ GtkAccelGroup *accelerator_group;
+
+ DBG(DBG_proc, "xsane_back_gtk_get_filename\n");
+
+
+ fileselection = gtk_file_selection_new((char *) label);
+ accelerator_group = gtk_accel_group_new();
+ gtk_accel_group_attach(accelerator_group, GTK_OBJECT(fileselection));
+
+ gtk_signal_connect(GTK_OBJECT(fileselection),
+ "destroy", GTK_SIGNAL_FUNC(xsane_back_gtk_get_filename_button_clicked), &destroy);
+
+ gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fileselection)->cancel_button),
+ "clicked", (GtkSignalFunc) xsane_back_gtk_get_filename_button_clicked, &cancel);
+ gtk_widget_add_accelerator(GTK_FILE_SELECTION(fileselection)->cancel_button, "clicked",
+ accelerator_group, GDK_Escape, 0, GTK_ACCEL_LOCKED);
+
+ gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fileselection)->ok_button),
+ "clicked", (GtkSignalFunc) xsane_back_gtk_get_filename_button_clicked, &ok);
+ if (default_name)
+ {
+ DBG(DBG_info, "xsane_back_gtk_get_filename: default_name =%s\n", default_name);
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection), (char *) default_name);
+ }
+
+ if (hide_file_list)
+ {
+ DBG(DBG_info, "xsane_back_gtk_get_filename: hiding file-list and delete-file-widget\n");
+ gtk_widget_hide(GTK_FILE_SELECTION(fileselection)->file_list->parent);
+ gtk_widget_hide(GTK_FILE_SELECTION(fileselection)->fileop_del_file);
+ }
+
+ if (show_fileopts)
+ {
+ DBG(DBG_info, "xsane_back_gtk_get_filename: showing file-options\n");
+ gtk_file_selection_show_fileop_buttons(GTK_FILE_SELECTION(fileselection));
+ }
+ else
+ {
+ DBG(DBG_info, "xsane_back_gtk_get_filename: hiding file-options\n");
+ gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(fileselection));
+ }
+
+ gtk_widget_show(fileselection);
+
+ DBG(DBG_info, "xsane_back_gtk_get_filename: waiting for user action\n");
+ while (!cancel && !ok && !destroy)
+ {
+ if (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+ }
+
+ if (ok)
+ {
+ size_t len, cwd_len;
+ char *cwd;
+
+ DBG(DBG_info, "ok button pressed\n");
+
+ strncpy(filename, gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection)), max_len - 1);
+ filename[max_len - 1] = '\0';
+
+ len = strlen(filename);
+
+ cwd = alloca(len + 2); /* alloca => memory is freed on return */
+ getcwd(cwd, len + 1);
+ cwd_len = strlen(cwd);
+ cwd[cwd_len++] = '/';
+ cwd[cwd_len] = '\0';
+
+ DBG(DBG_info, "xsane_back_gtk_get_filename: full path filename = %s\n", filename);
+ if (shorten_path && (strncmp(filename, cwd, cwd_len) == 0))
+ {
+ memcpy(filename, filename + cwd_len, len - cwd_len + 1);
+ DBG(DBG_info, "xsane_back_gtk_get_filename: short path filename = %s\n", filename);
+ }
+ }
+
+ if (!destroy)
+ {
+ gtk_widget_destroy(fileselection);
+ }
+
+ return ok ? 0 : -1;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static gint xsane_back_gtk_autobutton_update(GtkWidget *widget, GSGDialogElement *elem)
+{
+ int opt_num = elem - xsane.element;
+ const SANE_Option_Descriptor *opt;
+ SANE_Status status;
+ SANE_Word val;
+ char buf[256];
+
+ DBG(DBG_proc, "xsane_back_gtk_autobutton_update\n");
+
+ opt = xsane_get_option_descriptor(xsane.dev, opt_num);
+ if (GTK_TOGGLE_BUTTON(widget)->active)
+ {
+ xsane_back_gtk_set_option(opt_num, 0, SANE_ACTION_SET_AUTO);
+ }
+ else
+ {
+ status = xsane_control_option(xsane.dev, opt_num, SANE_ACTION_GET_VALUE, &val, 0);
+ if (status != SANE_STATUS_GOOD)
+ {
+ snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_GET_OPTION, opt->name, XSANE_STRSTATUS(status));
+ xsane_back_gtk_error(buf, FALSE);
+ }
+ xsane_back_gtk_set_option(opt_num, &val, SANE_ACTION_SET_VALUE);
+ }
+ return FALSE;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_back_gtk_autobutton_new(GtkWidget *parent, GSGDialogElement *elem,
+ GtkWidget *label, GtkTooltips *tooltips)
+{
+ GtkWidget *button, *alignment;
+
+ DBG(DBG_proc, "xsane_back_gtk_autobutton_new\n");
+
+ button = gtk_check_button_new();
+ gtk_container_set_border_width(GTK_CONTAINER(button), 0);
+ gtk_widget_set_usize(button, 20, 20);
+ gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_back_gtk_autobutton_update, elem);
+ xsane_back_gtk_set_tooltip(tooltips, button, "Turns on automatic mode.");
+
+ alignment = gtk_alignment_new(0.0, 1.0, 0.5, 0.5);
+ gtk_container_add(GTK_CONTAINER(alignment), button);
+
+ gtk_box_pack_end(GTK_BOX(parent), label, FALSE, FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(parent), alignment, FALSE, FALSE, 2);
+
+ gtk_widget_show(alignment);
+ gtk_widget_show(button);
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static gint xsane_back_gtk_button_update(GtkWidget * widget, GSGDialogElement * elem)
+{
+ int opt_num = elem - xsane.element;
+ const SANE_Option_Descriptor *opt;
+ SANE_Word val = SANE_FALSE;
+
+ DBG(DBG_proc, "xsane_back_gtk_button_update\n");
+
+ opt = xsane_get_option_descriptor(xsane.dev, opt_num);
+ if (GTK_TOGGLE_BUTTON(widget)->active)
+ {
+ val = SANE_TRUE;
+ }
+ xsane_back_gtk_set_option(opt_num, &val, SANE_ACTION_SET_VALUE);
+
+ return FALSE;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_button_new(GtkWidget * parent, const char *name, SANE_Word val,
+ GSGDialogElement * elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable)
+{
+ GtkWidget *button;
+
+ DBG(DBG_proc, "xsane_back_gtk_button_new\n");
+
+ button = gtk_check_button_new_with_label((char *) name);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), val);
+ gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_back_gtk_button_update, elem);
+ gtk_box_pack_start(GTK_BOX(parent), button, FALSE, TRUE, 0);
+ gtk_widget_show(button);
+ xsane_back_gtk_set_tooltip(tooltips, button, desc);
+
+ gtk_widget_set_sensitive(button, settable);
+
+ elem->widget = button;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_back_gtk_scale_update(GtkAdjustment * adj_data, GSGDialogElement * elem)
+{
+ const SANE_Option_Descriptor *opt;
+ SANE_Word val, new_val;
+ int opt_num;
+ double d;
+
+ DBG(DBG_proc, "xsane_back_gtk_scale_update\n");
+
+ opt_num = elem - xsane.element;
+ opt = xsane_get_option_descriptor(xsane.dev, opt_num);
+ switch(opt->type)
+ {
+ case SANE_TYPE_INT:
+ val = adj_data->value + 0.5;
+ break;
+
+ case SANE_TYPE_FIXED:
+ d = adj_data->value;
+ if (opt->unit == SANE_UNIT_MM)
+ {
+ d *= preferences.length_unit;
+ }
+ val = SANE_FIX(d);
+ break;
+
+ default:
+ DBG(DBG_error, "xsane_back_gtk_scale_update: %s %d\n", ERR_UNKNOWN_TYPE, opt->type);
+ return;
+ }
+
+ xsane_back_gtk_set_option(opt_num, &val, SANE_ACTION_SET_VALUE);
+ xsane_control_option(xsane.dev, opt_num, SANE_ACTION_GET_VALUE, &new_val, 0);
+ if (new_val != val)
+ {
+ val = new_val;
+ goto value_changed;
+ }
+ return; /* value didn't change */
+
+value_changed:
+ switch(opt->type)
+ {
+ case SANE_TYPE_INT:
+ adj_data->value = val;
+ break;
+
+ case SANE_TYPE_FIXED:
+ d = SANE_UNFIX(val);
+ if (opt->unit == SANE_UNIT_MM)
+ {
+ d /= preferences.length_unit;
+ }
+ adj_data->value = d;
+ break;
+
+ default:
+ break;
+ }
+ /* Let widget know that value changed _again_. This must converge
+ quickly---otherwise things would get very slow very quickly (as
+ in "infinite recursion"): */
+ gtk_signal_emit_by_name(GTK_OBJECT(adj_data), "value_changed");
+ return;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_scale_new(GtkWidget * parent, const char *name, gfloat val,
+ gfloat min, gfloat max, gfloat quant, int automatic,
+ GSGDialogElement * elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable)
+{
+ GtkWidget *hbox, *label, *scale;
+
+ DBG(DBG_proc, "xsane_back_gtk_scale_new(%s)\n", name);
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
+ gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new((char *) name);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
+
+ elem->data = gtk_adjustment_new(val, min, max, quant, quant*10, 0.0);
+ scale = gtk_hscale_new(GTK_ADJUSTMENT(elem->data));
+ xsane_back_gtk_set_tooltip(tooltips, scale, desc);
+ gtk_widget_set_usize(scale, 150, 0);
+
+ if (automatic)
+ {
+ xsane_back_gtk_autobutton_new(hbox, elem, scale, tooltips);
+ }
+ else
+ {
+ gtk_box_pack_end(GTK_BOX(hbox), scale, FALSE, FALSE, 0); /* make scales fixed */
+/* gtk_box_pack_end(GTK_BOX(hbox), scale, TRUE, TRUE, 0); */ /* make scales sizeable */
+ }
+
+ gtk_range_set_update_policy(GTK_RANGE(scale), GTK_UPDATE_CONTINUOUS);
+ gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP);
+
+ if (quant - (int) quant == 0.0)
+ {
+ gtk_scale_set_digits(GTK_SCALE(scale), 0);
+ }
+ else
+ {
+ /* set number of digits in dependacne of quantization */
+ gtk_scale_set_digits(GTK_SCALE(scale), (int) log10(1/quant)+0.8);
+ }
+
+ gtk_signal_connect(elem->data, "value_changed", (GtkSignalFunc) xsane_back_gtk_scale_update, elem);
+
+ gtk_widget_show(label);
+ gtk_widget_show(scale);
+ gtk_widget_show(hbox);
+
+ gtk_widget_set_sensitive(scale, settable);
+
+ elem->widget = scale;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_push_button_callback(GtkWidget * widget, gpointer data)
+{
+ GSGDialogElement *elem = data;
+ int opt_num;
+
+ DBG(DBG_proc, "xsane_back_gtk_push_button_callback\n");
+
+ opt_num = elem - xsane.element;
+ xsane_back_gtk_set_option(opt_num, 0, SANE_ACTION_SET_VALUE);
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_back_gtk_option_menu_lookup(GSGMenuItem menu_items[], const char *string)
+{
+ int i;
+
+ DBG(DBG_proc, "xsane_back_gtk_option_menu_lookup\n");
+
+ for (i = 0; strcmp(menu_items[i].label, string) != 0; ++i);
+
+ return i;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_back_gtk_option_menu_callback(GtkWidget * widget, gpointer data)
+{
+ GSGMenuItem *menu_item = data;
+ GSGDialogElement *elem = menu_item->elem;
+ const SANE_Option_Descriptor *opt;
+ int opt_num;
+ double dval;
+ SANE_Word val;
+ void *valp = &val;
+
+ DBG(DBG_proc, "xsane_back_gtk_option_menu_callback\n");
+
+ opt_num = elem - xsane.element;
+ opt = xsane_get_option_descriptor(xsane.dev, opt_num);
+ switch(opt->type)
+ {
+ case SANE_TYPE_INT:
+ sscanf(menu_item->label, "%d", &val);
+ break;
+
+ case SANE_TYPE_FIXED:
+ sscanf(menu_item->label, "%lg", &dval);
+ val = SANE_FIX(dval);
+ break;
+
+ case SANE_TYPE_STRING:
+ valp = menu_item->label;
+ break;
+
+ default:
+ DBG(DBG_error, "xsane_back_gtk_option_menu_callback: %s %d\n", ERR_UNKNOWN_TYPE, opt->type);
+ break;
+ }
+ xsane_back_gtk_set_option(opt_num, valp, SANE_ACTION_SET_VALUE);
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_option_menu_new(GtkWidget *parent, const char *name, char *str_list[],
+ const char *val, GSGDialogElement * elem,
+ GtkTooltips *tooltips, const char *desc, SANE_Int settable)
+{
+ GtkWidget *hbox, *label, *option_menu, *menu, *item;
+ GSGMenuItem *menu_items;
+ int i, num_items;
+
+ DBG(DBG_proc, "xsane_back_gtk_option_menu_new(%s)\n", name);
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
+ gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new((char *) name);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
+
+ for (num_items = 0; str_list[num_items]; ++num_items);
+ menu_items = malloc(num_items * sizeof(menu_items[0]));
+
+ menu = gtk_menu_new();
+ for (i = 0; i < num_items; ++i)
+ {
+ item = gtk_menu_item_new_with_label(_BGT(str_list[i]));
+ gtk_container_add(GTK_CONTAINER(menu), item);
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_back_gtk_option_menu_callback, menu_items + i);
+
+ gtk_widget_show(item);
+
+ menu_items[i].label = str_list[i];
+ menu_items[i].elem = elem;
+ menu_items[i].index = i;
+ }
+
+ option_menu = gtk_option_menu_new();
+ gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 2);
+ gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), xsane_back_gtk_option_menu_lookup(menu_items, val));
+ xsane_back_gtk_set_tooltip(tooltips, option_menu, desc);
+
+ gtk_widget_show(label);
+ gtk_widget_show(option_menu);
+ gtk_widget_show(hbox);
+
+ gtk_widget_set_sensitive(option_menu, settable);
+
+ elem->widget = option_menu;
+ elem->menu_size = num_items;
+ elem->menu = menu_items;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_back_gtk_text_entry_callback(GtkWidget *w, gpointer data)
+{
+ GSGDialogElement *elem = data;
+ const SANE_Option_Descriptor *opt;
+ gchar *text;
+ int opt_num;
+ char *buf;
+
+ DBG(DBG_proc, "xsane_back_gtk_text_entry_callback\n");
+
+ opt_num = elem - xsane.element;
+ opt = xsane_get_option_descriptor(xsane.dev, opt_num);
+
+ buf = alloca(opt->size);
+ buf[0] = '\0';
+
+ text = gtk_entry_get_text(GTK_ENTRY(elem->widget));
+ if (text)
+ {
+ strncpy(buf, text, opt->size);
+ }
+ buf[opt->size - 1] = '\0';
+
+ xsane_back_gtk_set_option(opt_num, buf, SANE_ACTION_SET_VALUE);
+
+ if (strcmp(buf, text) != 0) /* the backend modified the option value; update widget: */
+ {
+ gtk_entry_set_text(GTK_ENTRY(elem->widget), buf);
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_text_entry_new(GtkWidget * parent, const char *name, const char *val, GSGDialogElement *elem,
+ GtkTooltips *tooltips, const char *desc, SANE_Int settable)
+{
+ GtkWidget *hbox, *text, *label;
+
+ DBG(DBG_proc, "xsane_back_gtk_text_entry_new\n");
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
+ gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new((char *) name);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
+
+ text = gtk_entry_new();
+ gtk_entry_set_text(GTK_ENTRY(text), (char *) val);
+/* gtk_box_pack_start(GTK_BOX(hbox), text, FALSE, TRUE, 0); */ /* text entry fixed */
+ gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 0); /* text entry sizeable */
+ gtk_signal_connect(GTK_OBJECT(text), "changed", (GtkSignalFunc) xsane_back_gtk_text_entry_callback, elem);
+ xsane_back_gtk_set_tooltip(tooltips, text, desc);
+
+ gtk_widget_show(hbox);
+ gtk_widget_show(label);
+ gtk_widget_show(text);
+
+ gtk_widget_set_sensitive(text, settable);
+
+ elem->widget = text;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+GtkWidget *xsane_back_gtk_group_new(GtkWidget *parent, const char *title)
+{
+ GtkWidget * frame, * vbox;
+
+ DBG(DBG_proc, "xsane_back_gtk_group_new(%s)\n", title);
+
+ frame = gtk_frame_new((char *) title);
+ gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
+ gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new(FALSE, 4);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
+ gtk_container_add(GTK_CONTAINER(frame), vbox);
+ gtk_widget_show(vbox);
+ return vbox;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+#if 0
+static void tooltips_destroy(void)
+{
+ DBG(DBG_proc, "tooltips_destroy\n");
+
+ gtk_object_unref(GTK_OBJECT(xsane.tooltips));
+ xsane.tooltips = 0;
+}
+#endif
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_back_gtk_panel_destroy(void)
+{
+ const SANE_Option_Descriptor *opt;
+ GSGDialogElement *elem;
+ int i, j;
+
+ DBG(DBG_proc, "xsane_back_gtk_panel_destroy\n");
+
+ gtk_widget_destroy(xsane.xsane_hbox);
+ gtk_widget_destroy(xsane.standard_hbox);
+ gtk_widget_destroy(xsane.advanced_hbox);
+
+ /* free the menu labels of integer/fix-point word-lists: */
+ for (i = 0; i < xsane.num_elements; ++i)
+ {
+ if (xsane.element[i].menu)
+ {
+ opt = xsane_get_option_descriptor(xsane.dev, i);
+ elem = xsane.element + i;
+ if (opt->type != SANE_TYPE_STRING)
+ {
+ for (j = 0; j < elem->menu_size; ++j)
+ {
+ if (elem->menu[j].label)
+ {
+ free(elem->menu[j].label);
+ elem->menu[j].label = 0;
+ }
+ }
+ free(elem->menu);
+ elem->menu = 0;
+ }
+ }
+ }
+ memset(xsane.element, 0, xsane.num_elements * sizeof(xsane.element[0]));
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+/* When an setting an option changes the dialog, everything may
+ change: the option titles, the activity-status of the option, its
+ constraints or what not. Thus, rather than trying to be clever in
+ detecting what exactly changed, we use a brute-force method of
+ rebuilding the entire dialog. */
+
+static void xsane_back_gtk_panel_rebuild(void)
+{
+ DBG(DBG_proc, "xsane_back_gtk_panel_rebuild\n");
+
+ xsane_back_gtk_panel_destroy();
+ xsane_panel_build();
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_refresh_dialog(void)
+{
+ DBG(DBG_proc, "xsane_back_gtk_refresh_dialog\n");
+
+ xsane_back_gtk_panel_rebuild();
+ xsane_update_param(0);
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_update_scan_window(void)
+{
+ const SANE_Option_Descriptor *opt;
+ double old_val, new_val;
+ GSGDialogElement *elem;
+ SANE_Status status;
+ SANE_Word word;
+ int i, optnum;
+ char str[64];
+
+ DBG(DBG_proc, "xsane_back_gtk_update_scan_window\n");
+
+ for (i = 0; i < 4; ++i)
+ {
+ if (xsane.well_known.coord[i] > 0)
+ {
+ optnum = xsane.well_known.coord[i];
+ elem = xsane.element + optnum;
+ opt = xsane_get_option_descriptor(xsane.dev, optnum);
+
+ status = xsane_control_option(xsane.dev, optnum, SANE_ACTION_GET_VALUE, &word, 0);
+ if (status != SANE_STATUS_GOOD)
+ {
+ continue; /* sliently ignore errors */
+ }
+
+ switch(opt->constraint_type)
+ {
+ case SANE_CONSTRAINT_RANGE:
+ if (opt->type == SANE_TYPE_INT)
+ {
+ old_val = GTK_ADJUSTMENT(elem->data)->value;
+ new_val = word;
+ GTK_ADJUSTMENT(elem->data)->value = new_val;
+ }
+ else
+ {
+ old_val = GTK_ADJUSTMENT(elem->data)->value;
+ new_val = SANE_UNFIX(word);
+ if (opt->unit == SANE_UNIT_MM)
+ {
+ new_val /= preferences.length_unit;
+ }
+ GTK_ADJUSTMENT(elem->data)->value = new_val;
+ }
+
+ if (old_val != new_val)
+ {
+ gtk_signal_emit_by_name(GTK_OBJECT(elem->data), "value_changed");
+ }
+ break;
+
+ case SANE_CONSTRAINT_WORD_LIST:
+ if (opt->type == SANE_TYPE_INT)
+ {
+ sprintf(str, "%d", word);
+ }
+ else
+ {
+ sprintf(str, "%g", SANE_UNFIX(word));
+ }
+ /* XXX maybe we should call this only when the value changes... */
+ gtk_option_menu_set_history(GTK_OPTION_MENU(elem->widget), xsane_back_gtk_option_menu_lookup(elem->menu, str));
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+/* Ensure sure the device has up-to-date option values. Except for
+ vectors, all option values are kept current. Vectors are
+ downloaded into the device during this call. */
+void xsane_back_gtk_sync(void)
+{
+ const SANE_Option_Descriptor *opt;
+ gfloat val, *vector;
+ SANE_Word *optval;
+ int i, j, optlen;
+ GtkWidget *curve;
+
+ DBG(DBG_proc, "xsane_back_gtk_sync\n");
+
+ for (i = 1; i < xsane.num_elements; ++i)
+ {
+ opt = xsane_get_option_descriptor(xsane.dev, i);
+
+ if (!SANE_OPTION_IS_ACTIVE(opt->cap))
+ {
+ continue;
+ }
+
+ if (opt->type != SANE_TYPE_INT && opt->type != SANE_TYPE_FIXED)
+ {
+ continue;
+ }
+
+ if (opt->size == sizeof(SANE_Word))
+ {
+ continue;
+ }
+
+ /* ok, we're dealing with an active vector */
+
+ optlen = opt->size / sizeof(SANE_Word);
+ optval = alloca(optlen * sizeof(optval[0]));
+ vector = alloca(optlen * sizeof(vector[0]));
+
+ curve = GTK_GAMMA_CURVE(xsane.element[i].widget)->curve;
+ gtk_curve_get_vector(GTK_CURVE(curve), optlen, vector);
+ for (j = 0; j < optlen; ++j)
+ {
+ val = vector[j];
+ if (opt->type == SANE_TYPE_FIXED)
+ {
+ optval[j] = SANE_FIX(val);
+ }
+ else
+ {
+ optval[j] = val + 0.5;
+ }
+ }
+
+ xsane_back_gtk_set_option(i, optval, SANE_ACTION_SET_VALUE);
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_update_vector(int opt_num, SANE_Int *vector)
+{
+ const SANE_Option_Descriptor *opt;
+ gfloat val;
+ SANE_Word *optval;
+ int j, optlen;
+
+ DBG(DBG_proc, "xsane_back_gtk_update_vector\n");
+
+ if (opt_num < 1)
+ return; /* not defined */
+
+ opt = xsane_get_option_descriptor(xsane.dev, opt_num);
+ if (!SANE_OPTION_IS_ACTIVE(opt->cap))
+ {
+ return; /* inactive */
+ }
+
+ if (opt->type != SANE_TYPE_INT && opt->type != SANE_TYPE_FIXED)
+ {
+ return;
+ }
+
+ if (opt->size == sizeof(SANE_Word))
+ {
+ return;
+ }
+
+ /* ok, we're dealing with an active vector */
+
+ optlen = opt->size / sizeof(SANE_Word);
+ optval = alloca(optlen * sizeof(optval[0]));
+ for (j = 0; j < optlen; ++j)
+ {
+ val = vector[j];
+ if (opt->type == SANE_TYPE_FIXED)
+ {
+ optval[j] = SANE_FIX(val);
+ }
+ else
+ {
+ optval[j] = val + 0.5;
+ }
+ }
+
+ xsane_back_gtk_set_option(opt_num, optval, SANE_ACTION_SET_VALUE);
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_set_tooltips(int enable)
+{
+ DBG(DBG_proc, "xsane_back_gtk_set_tooltips\n");
+
+ if (!xsane.tooltips)
+ {
+ return;
+ }
+
+ if (enable)
+ {
+ gtk_tooltips_enable(xsane.tooltips);
+ }
+ else
+ {
+ gtk_tooltips_disable(xsane.tooltips);
+ }
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_set_sensitivity(int sensitive)
+{
+ const SANE_Option_Descriptor *opt;
+ int i;
+
+ DBG(DBG_proc, "xsane_back_gtk_set_sensitivity\n");
+
+ for (i = 0; i < xsane.num_elements; ++i)
+ {
+ opt = xsane_get_option_descriptor(xsane.dev, i);
+
+ if (!SANE_OPTION_IS_ACTIVE(opt->cap) || !SANE_OPTION_IS_SETTABLE(opt->cap) ||
+ opt->type == SANE_TYPE_GROUP || !xsane.element[i].widget)
+ {
+ continue;
+ }
+
+ if (!(opt->cap & SANE_CAP_ALWAYS_SETTABLE))
+ {
+ gtk_widget_set_sensitive(xsane.element[i].widget, sensitive);
+ }
+ }
+
+ if (xsane.xsanemode_widget)
+ {
+ gtk_widget_set_sensitive(xsane.xsanemode_widget, sensitive);
+ }
+
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+}
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_set_sensitivity(SANE_Int sensitivity)
+{
+ DBG(DBG_proc, "xsane_set_sensitivity\n");
+
+ if (xsane.shell)
+ {
+ gtk_widget_set_sensitive(xsane.menubar, sensitivity);
+ gtk_widget_set_sensitive(xsane.xsane_window, sensitivity);
+ gtk_widget_set_sensitive(GTK_WIDGET(xsane.start_button), sensitivity);
+ gtk_widget_set_sensitive(xsane.standard_options_shell, sensitivity);
+ gtk_widget_set_sensitive(xsane.advanced_options_shell, sensitivity);
+ gtk_widget_set_sensitive(xsane.histogram_dialog, sensitivity);
+
+#ifdef HAVE_WORKING_GTK_GAMMACURVE
+ gtk_widget_set_sensitive(xsane.gamma_dialog, sensitivity);
+#endif
+ }
+
+ if (xsane.preview)
+ {
+ gtk_widget_set_sensitive(xsane.preview->button_box, sensitivity); /* button box at top of window */
+#if 1
+ gtk_widget_set_sensitive(xsane.preview->viewport, sensitivity); /* Preview image selection */
+#endif
+ gtk_widget_set_sensitive(xsane.preview->start, sensitivity); /* Acquire preview button */
+ }
+
+ if (xsane.fax_dialog)
+ {
+ gtk_widget_set_sensitive(xsane.fax_dialog, sensitivity);
+ }
+
+#if 0
+ xsane_back_gtk_set_sensitivity(sensitivity);
+#endif
+
+ while (gtk_events_pending()) /* make sure set_sensitivity is displayed */
+ {
+ gtk_main_iteration();
+ }
+
+ xsane.sensitivity = sensitivity;
+}
+
+/* ----------------------------------------------------------------------------------------------------------------- */
+
+void xsane_back_gtk_destroy_dialog(void)
+{
+ SANE_Handle dev = xsane.dev;
+
+ DBG(DBG_proc, "xsane_back_gtk_destroy_dialog\n");
+
+ xsane_back_gtk_panel_destroy();
+ free((void *) xsane.dev_name);
+ free(xsane.element);
+
+ sane_close(dev);
+}
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_set_window_icon(GtkWidget *gtk_window, gchar **xpm_d)
+{
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
+
+ DBG(DBG_proc, "xsane_set_window_icon\n");
+
+ gtk_widget_realize(gtk_window);
+ if (xpm_d)
+ {
+ pixmap = gdk_pixmap_create_from_xpm_d(gtk_window->window, &mask, xsane.bg_trans, xpm_d);
+ }
+ else
+ {
+ if (xsane.window_icon_pixmap)
+ {
+ pixmap = xsane.window_icon_pixmap;
+ mask = xsane.window_icon_mask;
+ }
+ else
+ {
+ pixmap = gdk_pixmap_create_from_xpm_d(gtk_window->window, &mask, xsane.bg_trans, (gchar **) xsane_window_icon_xpm);
+ }
+ }
+
+ gdk_window_set_icon(gtk_window->window, 0, pixmap, mask);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */