summaryrefslogtreecommitdiff
path: root/src/xsane-front-gtk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xsane-front-gtk.c')
-rw-r--r--src/xsane-front-gtk.c1664
1 files changed, 1664 insertions, 0 deletions
diff --git a/src/xsane-front-gtk.c b/src/xsane-front-gtk.c
new file mode 100644
index 0000000..b4373ed
--- /dev/null
+++ b/src/xsane-front-gtk.c
@@ -0,0 +1,1664 @@
+/* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend
+
+ xsane-front-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-preferences.h"
+#include "xsane-preview.h"
+#include "xsane-save.h"
+#include "xsane-gamma.h"
+#include "xsane-setup.h"
+#include <md5.h>
+
+#ifdef HAVE_LIBPNG
+#ifdef HAVE_LIBZ
+#include <png.h>
+#include <zlib.h>
+#endif
+#endif
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+/* forward declarations: */
+
+int xsane_parse_options(char *options, char *argv[]);
+void xsane_get_bounds(const SANE_Option_Descriptor *opt, double *minp, double *maxp);
+double xsane_find_best_resolution(int well_known_option, double dpi);
+int xsane_set_resolution(int well_known_option, double resolution);
+void xsane_set_all_resolutions(void);
+void xsane_define_maximum_output_size();
+void xsane_close_dialog_callback(GtkWidget *widget, gpointer data);
+void xsane_authorization_button_callback(GtkWidget *widget, gpointer data);
+gint xsane_authorization_callback(SANE_String_Const resource,
+ SANE_Char username[SANE_MAX_USERNAME_LEN],
+ SANE_Char password[SANE_MAX_PASSWORD_LEN]);
+void xsane_progress_cancel(GtkWidget *widget, gpointer data);
+void xsane_progress_new(char *bar_text, char *info, GtkSignalFunc callback, int *cancel_data_pointer);
+void xsane_progress_update(gfloat newval);
+void xsane_progress_clear();
+GtkWidget *xsane_vendor_pixmap_new(GdkWindow *window, GtkWidget *parent);
+GtkWidget *xsane_toggle_button_new_with_pixmap(GdkWindow *window, GtkWidget *parent, const char *xpm_d[], const char *desc,
+ int *state, void *xsane_toggle_button_callback);
+GtkWidget *xsane_button_new_with_pixmap(GdkWindow *window, GtkWidget *parent, const char *xpm_d[], const char *desc,
+ void *xsane_button_callback, gpointer data);
+void xsane_option_menu_new(GtkWidget *parent, char *str_list[], const char *val, int option_number, const char *desc,
+ void *option_menu_callback, SANE_Int settable, const gchar *widget_name);
+void xsane_option_menu_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc,
+ char *str_list[], const char *val,
+ GtkObject **data, int option,
+ void *option_menu_callback, SANE_Int settable, const gchar *widget_name);
+void xsane_scale_new(GtkBox *parent, char *labeltext, const char *desc,
+ float min, float max, float quant, float step, float page_step,
+ int digits, double *val, GtkObject **data, void *xsane_scale_callback, SANE_Int settable);
+void xsane_scale_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc,
+ float min, float max, float quant, float step, float page_step, int digits,
+ double *val, GtkObject **data, int option, void *xsane_scale_callback, SANE_Int settable);
+void xsane_separator_new(GtkWidget *xsane_parent, int dist);
+GtkWidget *xsane_info_table_text_new(GtkWidget *table, gchar *text, int row, int colomn);
+GtkWidget *xsane_info_text_new(GtkWidget *parent, gchar *text);
+void xsane_refresh_dialog(void);
+void xsane_set_sensitivity(SANE_Int sensitivity);
+void xsane_update_param(void *arg);
+void xsane_define_output_filename(void);
+int xsane_identify_output_format(char *filename, char **ext);
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+int xsane_parse_options(char *options, char *argv[])
+{
+ int optpos = 0;
+ int bufpos = 0;
+ int arg = 0;
+ char buf[256];
+
+ DBG(DBG_proc, "xsane_parse_options\n");
+
+ while (options[optpos] != 0)
+ {
+ switch(options[optpos])
+ {
+ case ' ':
+ buf[bufpos] = 0;
+ argv[arg++] = strdup(buf);
+ bufpos = 0;
+ optpos++;
+ break;
+
+ case '\"':
+ optpos++; /* skip " */
+ while ((options[optpos] != 0) && (options[optpos] != '\"'))
+ {
+ buf[bufpos++] = options[optpos++];
+ }
+ optpos++; /* skip " */
+ break;
+
+ default:
+ buf[bufpos++] = options[optpos++];
+ break;
+ }
+ }
+ buf[bufpos] = 0;
+ argv[arg++] = strdup(buf);
+
+ return arg;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_get_bounds(const SANE_Option_Descriptor *opt, double *minp, double *maxp)
+{
+ double min, max;
+ int i;
+
+ DBG(DBG_proc, "xsane_get_bounds\n");
+
+ min = -INF;
+ max = INF;
+ switch (opt->constraint_type)
+ {
+ case SANE_CONSTRAINT_RANGE:
+ min = opt->constraint.range->min;
+ max = opt->constraint.range->max;
+ break;
+
+ case SANE_CONSTRAINT_WORD_LIST:
+ min = INF;
+ max = -INF;
+
+ for (i = 1; i <= opt->constraint.word_list[0]; ++i)
+ {
+ if (opt->constraint.word_list[i] < min)
+ {
+ min = opt->constraint.word_list[i];
+ }
+ if (opt->constraint.word_list[i] > max)
+ {
+ max = opt->constraint.word_list[i];
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (opt->type == SANE_TYPE_FIXED)
+ {
+ if (min > -INF && min < INF)
+ {
+ min = SANE_UNFIX (min);
+ }
+ if (max > -INF && max < INF)
+ {
+ max = SANE_UNFIX (max);
+ }
+ }
+ *minp = min;
+ *maxp = max;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+double xsane_find_best_resolution(int well_known_option, double dpi)
+{
+ const SANE_Option_Descriptor *opt;
+ double bestdpi;
+
+ DBG(DBG_proc, "xsane_find_best_resolution\n");
+
+ opt = xsane_get_option_descriptor(xsane.dev, well_known_option);
+
+ if (!opt)
+ {
+ return -1.0; /* option does not exits */
+ }
+
+ if (opt->constraint_type == SANE_CONSTRAINT_RANGE)
+ {
+ double quant=0;
+ double min=0;
+ double max=0;
+
+ switch (opt->type)
+ {
+ case SANE_TYPE_INT:
+ min = opt->constraint.range->min;
+ max = opt->constraint.range->max;
+ quant = opt->constraint.range->quant;
+ break;
+
+ case SANE_TYPE_FIXED:
+ min = SANE_UNFIX(opt->constraint.range->min);
+ max = SANE_UNFIX(opt->constraint.range->max);
+ quant = SANE_UNFIX(opt->constraint.range->quant);
+ break;
+
+ default:
+ DBG(DBG_error, "find_best_resolution: %s %d\n", ERR_UNKNOWN_TYPE, opt->type);
+ }
+
+ bestdpi = dpi;
+
+ if (quant != 0) /* make sure selected value fits into quantisation */
+ {
+ int factor;
+ double diff;
+
+ factor = (int) (dpi - min) / quant;
+
+ diff = dpi - min - factor * quant;
+ bestdpi = min + factor * quant;
+
+ if (diff >quant/2.0)
+ {
+ bestdpi += quant;
+ }
+ }
+
+ if (bestdpi < min)
+ {
+ bestdpi = min;
+ }
+
+ if (bestdpi > max)
+ {
+ bestdpi = max;
+ }
+ }
+ else if (opt->constraint_type == SANE_CONSTRAINT_WORD_LIST)
+ {
+ SANE_Word diff;
+ SANE_Word val;
+ int items;
+ int i;
+
+ items = opt->constraint.word_list[0];
+
+ bestdpi = opt->constraint.word_list[1];
+ if (opt->type == SANE_TYPE_FIXED)
+ {
+ bestdpi = SANE_UNFIX(bestdpi);
+ }
+
+ diff = abs(bestdpi - dpi);
+
+ for (i=1; i<=items; i++)
+ {
+ val = opt->constraint.word_list[i];
+ if (opt->type == SANE_TYPE_FIXED)
+ {
+ val = SANE_UNFIX(val);
+ }
+
+ if (abs(val - dpi) < diff)
+ {
+ diff = abs(val - dpi);
+ bestdpi = val;
+ }
+ }
+ }
+ else
+ {
+ DBG(DBG_error, "find_best_resolution: %s %d\n", ERR_UNKNOWN_CONSTRAINT_TYPE, opt->constraint_type);
+ return -1; /* error */
+ }
+
+ return bestdpi;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+int xsane_set_resolution(int well_known_option, double resolution)
+{
+ const SANE_Option_Descriptor *opt;
+ double bestdpi;
+ SANE_Word dpi;
+
+ DBG(DBG_proc, "xsane_set_resolution\n");
+
+ opt = xsane_get_option_descriptor(xsane.dev, well_known_option);
+
+ if (!opt)
+ {
+ return -1; /* option does not exits */
+ }
+
+ if (!SANE_OPTION_IS_ACTIVE(opt->cap))
+ {
+ return -1; /* option is not active */
+ }
+
+ bestdpi = xsane_find_best_resolution(well_known_option, resolution);
+
+ if (bestdpi < 0)
+ {
+ DBG(DBG_error, "set_resolution: %s\n", ERR_FAILED_SET_RESOLUTION);
+ return -1;
+ }
+
+ switch (opt->type)
+ {
+ case SANE_TYPE_INT:
+ dpi = bestdpi;
+ break;
+
+ case SANE_TYPE_FIXED:
+ dpi = SANE_FIX(bestdpi);
+ break;
+
+ default:
+ DBG(DBG_error, "set_resolution: %s %d\n", ERR_UNKNOWN_TYPE, opt->type);
+ return 1; /* error */
+ }
+
+ xsane_control_option(xsane.dev, well_known_option, SANE_ACTION_SET_VALUE, &dpi, 0);
+ return 0; /* everything is ok */
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_set_all_resolutions(void)
+{
+ int printer_resolution;
+
+ DBG(DBG_proc, "xsane_set_all_resolutions\n");
+
+#if 0
+ xsane_set_resolution(xsane.well_known.dpi_y, xsane.resolution_y); /* set y resolution if possible */
+ if (xsane_set_resolution(xsane.well_known.dpi_x, xsane.resolution_x)) /* set x resolution if possible */
+ {
+ xsane_set_resolution(xsane.well_known.dpi, xsane.resolution); /* set common resolution if necessary */
+ xsane.resolution_x = xsane.resolution;
+ xsane.resolution_y = xsane.resolution;
+ }
+#else
+ if (xsane_set_resolution(xsane.well_known.dpi_y, xsane.resolution_y)) /* set y resolution if possible */
+ {
+ xsane_set_resolution(xsane.well_known.dpi, xsane.resolution); /* set common resolution if necessary */
+ xsane.resolution_x = xsane.resolution;
+ xsane.resolution_y = xsane.resolution;
+ }
+ else
+ {
+ xsane_set_resolution(xsane.well_known.dpi_x, xsane.resolution_x); /* set x resolution if possible */
+ }
+#endif
+
+ switch (xsane.param.format)
+ {
+ case SANE_FRAME_GRAY:
+ if (xsane.param.depth == 1)
+ {
+ printer_resolution = preferences.printer[preferences.printernr]->lineart_resolution;
+ }
+ else
+ {
+ printer_resolution = preferences.printer[preferences.printernr]->grayscale_resolution;
+ }
+ break;
+
+ case SANE_FRAME_RGB:
+ case SANE_FRAME_RED:
+ case SANE_FRAME_GREEN:
+ case SANE_FRAME_BLUE:
+ default:
+ printer_resolution = preferences.printer[preferences.printernr]->color_resolution;
+ break;
+ }
+
+ xsane.zoom = xsane.resolution / printer_resolution;
+ xsane.zoom_x = xsane.resolution_x / printer_resolution;
+ xsane.zoom_y = xsane.resolution_y / printer_resolution;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_define_maximum_output_size()
+{
+ const SANE_Option_Descriptor *opt;
+
+ DBG(DBG_proc, "xsane_define_maximum_output_size\n");
+
+ opt = xsane_get_option_descriptor(xsane.dev, xsane.well_known.coord[0]);
+
+ if ( (opt) && (opt->unit== SANE_UNIT_MM) )
+ {
+ switch(xsane.xsane_mode)
+ {
+ case XSANE_SAVE:
+
+ xsane_define_output_filename();
+ xsane.xsane_output_format = xsane_identify_output_format(xsane.output_filename, 0);
+
+ preview_set_maximum_output_size(xsane.preview, INF, INF);
+ break;
+
+ case XSANE_VIEWER:
+ preview_set_maximum_output_size(xsane.preview, INF, INF);
+ break;
+
+ case XSANE_COPY:
+ if (preferences.psrotate) /* rotate: landscape */
+ {
+ preview_set_maximum_output_size(xsane.preview,
+ preferences.printer[preferences.printernr]->height / xsane.zoom_y,
+ preferences.printer[preferences.printernr]->width / xsane.zoom_x);
+ }
+ else /* do not rotate: portrait */
+ {
+ preview_set_maximum_output_size(xsane.preview,
+ preferences.printer[preferences.printernr]->width / xsane.zoom_x,
+ preferences.printer[preferences.printernr]->height / xsane.zoom_y);
+ }
+ break;
+
+ case XSANE_FAX:
+ preview_set_maximum_output_size(xsane.preview, preferences.fax_width, preferences.fax_height);
+ break;
+
+ case XSANE_MAIL:
+ preview_set_maximum_output_size(xsane.preview, INF, INF);
+ break;
+
+ default:
+ preview_set_maximum_output_size(xsane.preview, INF, INF);
+ }
+ }
+ else
+ {
+ preview_set_maximum_output_size(xsane.preview, INF, INF);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_close_dialog_callback(GtkWidget *widget, gpointer data)
+{
+ GtkWidget *dialog_widget = data;
+
+ DBG(DBG_proc, "xsane_close_dialog_callback\n");
+
+ gtk_widget_destroy(dialog_widget);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+int authorization_flag;
+
+void xsane_authorization_button_callback(GtkWidget *widget, gpointer data)
+{
+ DBG(DBG_proc, "xsane_authorization_button_callback\n");
+
+ authorization_flag = (long) data;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+gint xsane_authorization_callback(SANE_String_Const resource,
+ SANE_Char username[SANE_MAX_USERNAME_LEN],
+ SANE_Char password[SANE_MAX_PASSWORD_LEN])
+{
+ GtkWidget *authorize_dialog, *vbox, *hbox, *button, *label;
+ GtkWidget *username_widget, *password_widget;
+ char buf[SANE_MAX_PASSWORD_LEN+SANE_MAX_USERNAME_LEN+128];
+ char *input;
+ char *resource_string;
+ int len;
+ int resource_len;
+ int secure_password_transmission = 0;
+ char password_filename[PATH_MAX];
+ struct stat password_stat;
+ FILE *password_file;
+ unsigned char md5digest[16];
+ int query_user = 1;
+
+ DBG(DBG_proc, "xsane_authorization_callback\n");
+
+ if (strstr(resource, "$MD5$") != NULL) /* secure password authorisation */
+ {
+ DBG(DBG_info, "xsane_authorization_callback: secure (MD5) password transmission requested\n");
+ secure_password_transmission = 1;
+ resource_len = strstr(resource, "$MD5$") - resource;
+ }
+ else
+ {
+ DBG(DBG_info, "xsane_authorization_callback: insecure password transmission requested\n");
+ resource_len = strlen(resource);
+ }
+ resource_string = alloca(resource_len+1);
+ snprintf(resource_string, resource_len+1, "%s", resource);
+
+ xsane_back_gtk_make_path(sizeof(password_filename), password_filename, NULL, NULL, "pass", NULL, NULL, XSANE_PATH_LOCAL_SANE);
+
+ /* if password transmission is secure and file ~/.sane/pass exists and it's permissions are x00 then
+ try to read username and pasword for resource from that file */
+ if ((stat(password_filename, &password_stat) == 0) && (secure_password_transmission))
+ {
+ if ((password_stat.st_mode & 63) != 0) /* 63 = 0x077 */
+ {
+ snprintf(buf, sizeof(buf), ERR_PASSWORD_FILE_INSECURE, password_filename);
+ xsane_back_gtk_error(buf, TRUE);
+ }
+ else /* ok, password file has secure permissions, we can use it */
+ {
+ password_file = fopen(password_filename, "r");
+
+ if (password_file)
+ {
+ DBG(DBG_info, "xsane authorization: opened %s as password file\n", password_filename);
+ /* file format: "username:password:resource" */
+ while (fgets(buf, sizeof(buf), password_file))
+ {
+ char *stored_username;
+ char *stored_password;
+ char *stored_resource;
+ char *marker;
+
+ marker = strrchr(buf, '\n');
+ if (marker)
+ {
+ *marker = 0; /* remove \n at end of read line */
+ }
+
+ marker = strrchr(buf, '\r');
+ if (marker)
+ {
+ *marker = 0; /* remove \r at end of read line (eg for windows file) */
+ }
+
+ marker = strchr(buf, ':');
+ if (marker)
+ {
+ stored_username = buf;
+ *marker = 0; /* set \0 to end of stored_username */
+ stored_password = marker + 1;
+
+ marker = strchr(stored_password, ':');
+ if (marker)
+ {
+ *marker = 0; /* set \0 to end of stored_password */
+ stored_resource = marker + 1;
+
+ if (strcmp(stored_resource, resource_string) == 0) /* password file resource equals requested resource */
+ {
+ strcpy(username, stored_username);
+ strcpy(password, stored_password);
+ query_user = 0;
+ }
+ }
+ }
+ }
+
+ fclose(password_file);
+ }
+ else
+ {
+ DBG(DBG_info, "xsane authorization: could not open existing password file %s\n", password_filename);
+ }
+ }
+ }
+ else
+ {
+ DBG(DBG_info, "xsane authorization: password file %s does not exist\n", password_filename);
+ }
+
+ if (query_user)
+ {
+ authorize_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_window_set_position(GTK_WINDOW(authorize_dialog), GTK_WIN_POS_CENTER);
+ gtk_window_set_policy(GTK_WINDOW(authorize_dialog), FALSE, FALSE, FALSE);
+ gtk_signal_connect(GTK_OBJECT(authorize_dialog), "delete_event",
+ GTK_SIGNAL_FUNC(xsane_authorization_button_callback), (void *) -1); /* -1 = cancel */
+ snprintf(buf, sizeof(buf), "%s %s", xsane.prog_name, WINDOW_AUTHORIZE);
+ gtk_window_set_title(GTK_WINDOW(authorize_dialog), buf);
+ xsane_set_window_icon(authorize_dialog, 0);
+
+ vbox = gtk_vbox_new(/* not homogeneous */ FALSE, 10); /* y-space between all box items */
+ gtk_container_add(GTK_CONTAINER(authorize_dialog), vbox);
+ gtk_widget_show(vbox);
+
+ /* print resourece string */
+ snprintf(buf, sizeof(buf), "\n\n%s %s", TEXT_AUTHORIZATION_REQ, resource_string);
+ label = gtk_label_new(buf);
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); /* y-space around authorization text */
+ gtk_widget_show(label);
+
+ /* print securety of password transmission */
+ if (secure_password_transmission)
+ {
+ snprintf(buf, sizeof(buf), "%s\n", TEXT_AUTHORIZATION_SECURE);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), "%s\n", TEXT_AUTHORIZATION_INSECURE);
+ }
+ label = gtk_label_new(buf);
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); /* y-space around authorization text */
+ gtk_widget_show(label);
+
+ /* ask for username */
+ hbox = gtk_hbox_new(FALSE, 10); /* x-space between label and input filed */
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* y-space around inner items */
+
+ label = gtk_label_new(TEXT_USERNAME);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10); /* x-space around label */
+ gtk_widget_show(label);
+
+ username_widget = gtk_entry_new_with_max_length(SANE_MAX_USERNAME_LEN-1);
+ gtk_widget_set_usize(username_widget, 250, 0);
+ gtk_entry_set_text(GTK_ENTRY(username_widget), "");
+ gtk_box_pack_end(GTK_BOX(hbox), username_widget, FALSE, FALSE, 10); /* x-space around input filed */
+ gtk_widget_show(username_widget);
+ gtk_widget_show(hbox);
+
+
+ /* ask for password */
+ hbox = gtk_hbox_new(FALSE, 10); /* x-space between label and input filed */
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* y-space around inner items */
+
+ label = gtk_label_new(TEXT_PASSWORD);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10); /* x-space around label */
+ gtk_widget_show(label);
+
+ password_widget = gtk_entry_new_with_max_length(SANE_MAX_PASSWORD_LEN-1);
+ gtk_entry_set_visibility(GTK_ENTRY(password_widget), FALSE); /* make entered text invisible */
+ gtk_widget_set_usize(password_widget, 250, 0);
+ gtk_entry_set_text(GTK_ENTRY(password_widget), "");
+ gtk_box_pack_end(GTK_BOX(hbox), password_widget, FALSE, FALSE, 10); /* x-space around input filed */
+ gtk_widget_show(password_widget);
+ gtk_widget_show(hbox);
+
+ /* buttons */
+ hbox = gtk_hbox_new(TRUE, 10); /* x-space between buttons */
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 10); /* y-space around buttons */
+
+ button = gtk_button_new_with_label(BUTTON_OK);
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(xsane_authorization_button_callback), (void *) 1);
+ gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 10); /* x-space around OK-button */
+ gtk_widget_grab_default(button);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label(BUTTON_CANCEL);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(xsane_authorization_button_callback), (void *) -1);
+ gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 10); /* x-space around cancel-button */
+ gtk_widget_show(button);
+
+ gtk_widget_show(hbox);
+
+ gtk_widget_show(authorize_dialog);
+
+
+ username[0]=0;
+ password[0]=0;
+
+ authorization_flag = 0;
+
+ /* wait for ok or cancel */
+ while (authorization_flag == 0)
+ {
+ gtk_main_iteration();
+ }
+
+ if (authorization_flag == 1) /* 1=ok, -1=cancel */
+ {
+ input = gtk_entry_get_text(GTK_ENTRY(username_widget));
+ len = strlen(input);
+ memcpy(username, input, len);
+ username[len] = 0;
+
+ input = gtk_entry_get_text(GTK_ENTRY(password_widget));
+ len = strlen(input);
+ memcpy(password, input, len);
+ password[len] = 0;
+ }
+ gtk_widget_destroy(authorize_dialog);
+ }
+
+ if (secure_password_transmission)
+ {
+ DBG(DBG_info, "xsane authorization: calculating md5digest of password\n");
+
+ snprintf(buf, sizeof(buf), "%s%s", (strstr(resource, "$MD5$")) + 5, password); /* random string from backend + password */
+ md5_buffer(buf, strlen(buf), md5digest); /* calculate md5digest */
+#if 0 /* makes problems with WIN32 */
+ memset(password, 0, SANE_MAX_PASSWORD_LEN); /* clear password */
+#endif
+
+ sprintf(password, "$MD5$%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ md5digest[0], md5digest[1], md5digest[2], md5digest[3],
+ md5digest[4], md5digest[5], md5digest[6], md5digest[7],
+ md5digest[8], md5digest[9], md5digest[10], md5digest[11],
+ md5digest[12], md5digest[13], md5digest[14], md5digest[15]);
+ }
+
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_progress_cancel(GtkWidget *widget, gpointer data)
+{
+ void *cancel_data_pointer;
+ GtkFunction callback = (GtkFunction) data;
+
+ DBG(DBG_proc, "xsane_progress_cancel\n");
+
+ cancel_data_pointer = gtk_object_get_data(GTK_OBJECT(widget), "progress-cancel-data-pointer");
+
+ (callback)(cancel_data_pointer);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_progress_new(char *bar_text, char *info, GtkSignalFunc callback, int *cancel_data_pointer)
+{
+ DBG(DBG_proc, "xsane_progress_new\n");
+
+ gtk_label_set(GTK_LABEL(xsane.info_label), info);
+ gtk_progress_set_format_string(GTK_PROGRESS(xsane.progress_bar), bar_text);
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(xsane.progress_bar), 0.0);
+ gtk_widget_set_sensitive(GTK_WIDGET(xsane.cancel_button), TRUE);
+ gtk_object_set_data(GTK_OBJECT(xsane.cancel_button), "progress-cancel-data-pointer", cancel_data_pointer);
+ gtk_signal_connect(GTK_OBJECT(xsane.cancel_button), "clicked", (GtkSignalFunc) xsane_progress_cancel, callback);
+ xsane.cancel_callback = callback;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_progress_clear()
+{
+ DBG(DBG_proc, "xsane_progress_clear\n");
+
+ /* do not call xsane_update_param() here because it overrites the good scanning parameters with bad guessed ones */
+ gtk_progress_set_format_string(GTK_PROGRESS(xsane.progress_bar), "");
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(xsane.progress_bar), 0.0);
+ gtk_widget_set_sensitive(GTK_WIDGET(xsane.cancel_button), FALSE);
+
+ if (xsane.cancel_callback)
+ {
+ gtk_signal_disconnect_by_func(GTK_OBJECT(xsane.cancel_button), (GtkSignalFunc) xsane_progress_cancel, xsane.cancel_callback);
+ xsane.cancel_callback = 0;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_progress_update(gfloat newval)
+{
+ DBG(DBG_proc, "xsane_progress_update\n");
+
+ if (newval < 0.0)
+ {
+ newval = 0.0;
+ }
+
+ if (newval > 1.0)
+ {
+ newval = 1.0;
+ }
+
+ gtk_progress_bar_update(GTK_PROGRESS_BAR(xsane.progress_bar), newval);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+/* add the scanner vendorīs logo if available */
+/* when the logo is not available use the xsane logo */
+GtkWidget *xsane_vendor_pixmap_new(GdkWindow *window, GtkWidget *parent)
+{
+ char filename[PATH_MAX];
+ GtkWidget *hbox, *vbox;
+ GtkWidget *pixmapwidget = NULL;
+ GdkBitmap *mask;
+ GdkPixmap *pixmap = NULL;
+
+ if (xsane.devlist[xsane.selected_dev]->vendor)
+ {
+ xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, NULL, xsane.devlist[xsane.selected_dev]->vendor, "-logo.xpm", XSANE_PATH_SYSTEM);
+ pixmap = gdk_pixmap_create_from_xpm(window, &mask, xsane.bg_trans, filename);
+ }
+
+ if (!pixmap) /* vendor logo not available, use backend logo */
+ {
+ xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, NULL, xsane.backend, "-logo.xpm", XSANE_PATH_SYSTEM);
+ pixmap = gdk_pixmap_create_from_xpm(window, &mask, xsane.bg_trans, filename);
+ }
+
+ if (!pixmap) /* backend logo not available, use xsane logo */
+ {
+ xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", NULL, NULL, "sane-xsane", "-logo.xpm", XSANE_PATH_SYSTEM);
+ pixmap = gdk_pixmap_create_from_xpm(window, &mask, xsane.bg_trans, filename);
+ }
+
+ if (pixmap) /* ok, we have a pixmap, so letīs show it */
+ {
+ vbox = gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(parent), vbox, FALSE, FALSE, 0);
+ gtk_widget_show(vbox);
+
+ hbox = gtk_hbox_new(TRUE /* homogeneous */ , 2);
+ gtk_container_add(GTK_CONTAINER(vbox), hbox);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
+ gtk_widget_show(hbox);
+
+ pixmapwidget = gtk_pixmap_new(pixmap, mask); /* now add the pixmap */
+ gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE /* expand */, FALSE /* fill */, 2);
+ gdk_pixmap_unref(pixmap);
+ gtk_widget_show(pixmapwidget);
+ }
+
+ return pixmapwidget;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+GtkWidget *xsane_toggle_button_new_with_pixmap(GdkWindow *window, GtkWidget *parent, const char *xpm_d[], const char *desc,
+ int *state, void *xsane_toggle_button_callback)
+{
+ GtkWidget *button;
+ GtkWidget *pixmapwidget;
+ GdkBitmap *mask;
+ GdkPixmap *pixmap;
+
+ DBG(DBG_proc, "xsane_toggle_button_new_with_pixmap\n");
+
+ button = gtk_toggle_button_new();
+ xsane_back_gtk_set_tooltip(xsane.tooltips, button, desc);
+
+ pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, xsane.bg_trans, (gchar **) xpm_d);
+ pixmapwidget = gtk_pixmap_new(pixmap, mask);
+ gtk_container_add(GTK_CONTAINER(button), pixmapwidget);
+ gtk_widget_show(pixmapwidget);
+ gdk_pixmap_unref(pixmap);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), *state);
+ gtk_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_toggle_button_callback, (GtkObject *) state);
+ gtk_box_pack_start(GTK_BOX(parent), button, FALSE, FALSE, 0);
+ gtk_widget_show(button);
+
+ return button;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+GtkWidget *xsane_button_new_with_pixmap(GdkWindow *window, GtkWidget *parent, const char *xpm_d[], const char *desc,
+ void *xsane_button_callback, gpointer data)
+{
+ GtkWidget *button;
+ GtkWidget *pixmapwidget;
+ GdkBitmap *mask;
+ GdkPixmap *pixmap;
+
+ DBG(DBG_proc, "xsane_button_new_with_pixmap\n");
+
+ button = gtk_button_new();
+ xsane_back_gtk_set_tooltip(xsane.tooltips, button, desc);
+
+ pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, xsane.bg_trans, (gchar **) xpm_d);
+ pixmapwidget = gtk_pixmap_new(pixmap, mask);
+ gtk_container_add(GTK_CONTAINER(button), pixmapwidget);
+ gtk_widget_show(pixmapwidget);
+ gdk_pixmap_unref(pixmap);
+
+ if (xsane_button_callback)
+ {
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_button_callback, data);
+ }
+ gtk_box_pack_start(GTK_BOX(parent), button, FALSE, FALSE, 0);
+ gtk_widget_show(button);
+
+ return(button);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int xsane_option_menu_lookup(GSGMenuItem menu_items[], const char *string)
+{
+ int i;
+
+ DBG(DBG_proc, "xsane_option_menu_lookup\n");
+
+ for (i = 0; strcmp(menu_items[i].label, string) != 0; ++i);
+ return i;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static void xsane_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_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_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_option_menu_new(GtkWidget *parent, char *str_list[], const char *val, int option_number, const char *desc,
+ void *option_menu_callback, SANE_Int settable, const gchar *widget_name)
+{
+ GtkWidget *option_menu, *menu, *item;
+ GSGMenuItem *menu_items;
+ GSGDialogElement *elem;
+ int i, num_items;
+
+ DBG(DBG_proc, "xsane_option_menu_new\n");
+
+ elem = xsane.element + option_number;
+
+ for (num_items = 0; str_list[num_items]; ++num_items);
+ menu_items = malloc(num_items * sizeof(menu_items[0]));
+
+ menu = gtk_menu_new();
+ if (widget_name)
+ {
+ gtk_widget_set_name(menu, widget_name);
+ }
+
+ 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);
+
+ if (option_menu_callback)
+ {
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) option_menu_callback, menu_items + i);
+ }
+ else
+ {
+ gtk_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_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();
+ xsane_back_gtk_set_tooltip(xsane.tooltips, option_menu, desc);
+ gtk_box_pack_end(GTK_BOX(parent), 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_option_menu_lookup(menu_items, val));
+
+ gtk_widget_show(option_menu);
+
+ gtk_widget_set_sensitive(option_menu, settable);
+
+ elem->widget = option_menu;
+ elem->menu_size = num_items;
+ elem->menu = menu_items;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_option_menu_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc,
+ char *str_list[], const char *val,
+ GtkObject **data, int option,
+ void *option_menu_callback, SANE_Int settable, const gchar *widget_name)
+{
+ GtkWidget *hbox;
+ GtkWidget *pixmapwidget;
+ GdkBitmap *mask;
+ GdkPixmap *pixmap;
+
+ DBG(DBG_proc, "xsane_option_menu_new_with_pixmap\n");
+
+ hbox = gtk_hbox_new(FALSE, 5);
+ gtk_box_pack_start(parent, hbox, FALSE, FALSE, 0);
+
+ pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, xsane.bg_trans, (gchar **) xpm_d);
+ pixmapwidget = gtk_pixmap_new(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2);
+ gtk_widget_show(pixmapwidget);
+
+ xsane_option_menu_new(hbox, str_list, val, option, desc, option_menu_callback, settable, widget_name);
+ gtk_widget_show(hbox);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_scale_new(GtkBox *parent, char *labeltext, const char *desc,
+ float min, float max, float quant, float page_step, float page_size,
+ int digits, double *val, GtkObject **data, void *xsane_scale_callback, SANE_Int settable)
+{
+ GtkWidget *hbox;
+ GtkWidget *label;
+ GtkWidget *scale;
+
+ DBG(DBG_proc, "xsane_scale_new\n");
+
+ hbox = gtk_hbox_new(FALSE, 5);
+ gtk_box_pack_start(parent, hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new(labeltext);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
+
+ *data = gtk_adjustment_new(*val, min, max, quant, page_step, page_size);
+ scale = gtk_hscale_new(GTK_ADJUSTMENT(*data));
+ xsane_back_gtk_set_tooltip(xsane.tooltips, scale, desc);
+ gtk_widget_set_usize(scale, 201, 0); /* minimum scale with = 201 pixels */
+ gtk_range_set_update_policy(GTK_RANGE(scale), preferences.gtk_update_policy);
+ /* GTK_UPDATE_CONTINUOUS, GTK_UPDATE_DISCONTINUOUS, GTK_UPDATE_DELAYED */
+ gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP);
+ gtk_scale_set_digits(GTK_SCALE(scale), digits);
+ gtk_box_pack_end(GTK_BOX(hbox), scale, FALSE, TRUE, 5); /* make scale not sizeable */
+
+ if (xsane_scale_callback)
+ {
+ gtk_signal_connect(*data, "value_changed", (GtkSignalFunc) xsane_scale_callback, val);
+ }
+
+ gtk_widget_show(label);
+ gtk_widget_show(scale);
+ gtk_widget_show(hbox);
+
+ gtk_widget_set_sensitive(scale, settable);
+
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_scale_new_with_pixmap(GdkWindow *window, GtkBox *parent, const char *xpm_d[], const char *desc,
+ float min, float max, float quant, float page_step, float page_size,
+ int digits, double *val, GtkObject **data, int option, void *xsane_scale_callback, SANE_Int settable)
+{
+ GtkWidget *hbox;
+ GtkWidget *scale;
+ GtkWidget *pixmapwidget;
+ GdkBitmap *mask;
+ GdkPixmap *pixmap;
+
+ DBG(DBG_proc, "xsane_scale_new_with_pixmap\n");
+
+ hbox = gtk_hbox_new(FALSE, 5);
+ gtk_box_pack_start(parent, hbox, FALSE, FALSE, 0);
+
+ pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, xsane.bg_trans, (gchar **) xpm_d);
+ pixmapwidget = gtk_pixmap_new(pixmap, mask);
+ gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 2);
+
+ *data = gtk_adjustment_new(*val, min, max, quant, page_step, page_size);
+ scale = gtk_hscale_new(GTK_ADJUSTMENT(*data));
+ xsane_back_gtk_set_tooltip(xsane.tooltips, scale, desc);
+ gtk_widget_set_usize(scale, 201, 0); /* minimum scale with = 201 pixels */
+ gtk_range_set_update_policy(GTK_RANGE(scale), preferences.gtk_update_policy);
+ /* GTK_UPDATE_CONTINUOUS, GTK_UPDATE_DISCONTINUOUS, GTK_UPDATE_DELAYED */
+ gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_TOP);
+ gtk_scale_set_digits(GTK_SCALE(scale), digits);
+ gtk_box_pack_end(GTK_BOX(hbox), scale, TRUE, TRUE, 5); /* make scale sizeable */
+
+ if (xsane_scale_callback)
+ {
+ gtk_signal_connect(*data, "value_changed", (GtkSignalFunc) xsane_scale_callback, val);
+ }
+
+ gtk_widget_show(pixmapwidget);
+ gtk_widget_show(scale);
+ gtk_widget_show(hbox);
+
+ gtk_widget_set_sensitive(scale, settable);
+
+ gdk_pixmap_unref(pixmap);
+
+ if (option)
+ {
+ GSGDialogElement *elem;
+
+ elem=xsane.element + option;
+ elem->data = *data;
+ elem->widget = scale;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_separator_new(GtkWidget *xsane_parent, int dist)
+{
+ GtkWidget *xsane_separator;
+
+ DBG(DBG_proc, "xsane_separator_new\n");
+
+ xsane_separator = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(xsane_parent), xsane_separator, FALSE, FALSE, dist);
+ gtk_widget_show(xsane_separator);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+GtkWidget *xsane_info_table_text_new(GtkWidget *table, gchar *text, int row, int colomn)
+{
+ GtkWidget *hbox, *label;
+
+ DBG(DBG_proc, "xsane_info_table_text_new\n");
+
+ hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), hbox, row, row+1, colomn, colomn+1);
+ gtk_widget_show(hbox);
+
+ label = gtk_label_new(text);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
+ gtk_widget_show(label);
+
+ return label;
+}
+/* ---------------------------------------------------------------------------------------------------------------------- */
+#if 0
+GtkWidget *xsane_info_text_new(GtkWidget *parent, gchar *text)
+{
+ GtkWidget *hbox, *label;
+
+ DBG(DBG_proc, "xsane_info_text_new\n");
+
+ hbox = gtk_hbox_new(/* homogeneous */ FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(parent), hbox, TRUE, TRUE, 5);
+ gtk_widget_show(hbox);
+
+ label = gtk_label_new(text);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 10);
+ gtk_widget_show(label);
+
+ return label;
+}
+#endif
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_refresh_dialog(void)
+{
+ DBG(DBG_proc, "xsane_refresh_dialog\n");
+
+ xsane_back_gtk_refresh_dialog();
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+/* Update the info line with the latest size information and update histogram. */
+void xsane_update_param(void *arg)
+{
+ gchar buf[200];
+ const char *unit;
+
+ DBG(DBG_proc, "xsane_update_param\n");
+
+ if (!xsane.info_label)
+ {
+ return;
+ }
+
+ if (xsane.block_update_param) /* if we change more than one value, we only want to update all once */
+ {
+ return;
+ }
+
+ if (xsane.preview)
+ {
+ preview_update_surface(xsane.preview, 0);
+ }
+
+ if (sane_get_parameters(xsane.dev, &xsane.param) == SANE_STATUS_GOOD)
+ {
+ float size = (float) xsane.param.bytes_per_line * (float) xsane.param.lines;
+ int depth = xsane.param.depth;
+
+ if ( (depth == 16) && (preferences.reduce_16bit_to_8bit) )
+ {
+ depth = 8;
+ size /= 2;
+ }
+
+ unit = "B";
+
+ if (xsane.param.format >= SANE_FRAME_RED && xsane.param.format <= SANE_FRAME_BLUE)
+ {
+ size *= 3.0;
+ depth *= 3;
+ }
+ else if (xsane.param.format == SANE_FRAME_RGB)
+ {
+ depth *= 3;
+ }
+#ifdef SUPPORT_RGBA
+ else if (xsane.param.format == SANE_FRAME_RGBA)
+ {
+ depth *= 4;
+ }
+#endif
+
+ if (size >= 1024.0 * 1024.0)
+ {
+ size /= 1024.0 * 1024.0;
+ unit = "MB";
+ }
+ else if (size >= 1024.0)
+ {
+ size /= 1024.0;
+ unit = "KB";
+ }
+ snprintf(buf, sizeof(buf), "%d*%d*%d (%1.1f %s)", xsane.param.pixels_per_line, xsane.param.lines, depth, size, unit);
+
+ if (xsane.param.format == SANE_FRAME_GRAY)
+ {
+ xsane.xsane_colors = 1;
+ }
+#ifdef SUPPORT_RGBA
+ else if (xsane.param.format == SANE_FRAME_RGBA)
+ {
+ xsane.xsane_colors = 4;
+ }
+#endif
+ else /* RGB */
+ {
+ xsane.xsane_colors = 3;
+ }
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), TEXT_INVALID_PARAMS);
+ }
+
+ gtk_label_set(GTK_LABEL(xsane.info_label), buf);
+
+
+ if (xsane.preview->surface_unit == SANE_UNIT_MM)
+ {
+ double dx, dy;
+
+ unit = xsane_back_gtk_unit_string(xsane.preview->surface_unit);
+
+ dx = fabs(xsane.preview->selection.coordinate[2] - xsane.preview->selection.coordinate[0]) / preferences.length_unit;
+ dy = fabs(xsane.preview->selection.coordinate[3] - xsane.preview->selection.coordinate[1]) / preferences.length_unit;
+
+ snprintf(buf, sizeof(buf), "%1.2f %s x %1.2f %s", dx, unit, dy, unit);
+ gtk_progress_set_format_string(GTK_PROGRESS(xsane.progress_bar), buf);
+ }
+
+ xsane_update_histogram(TRUE /* update raw */);
+
+ preview_display_valid(xsane.preview);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_define_output_filename(void)
+{
+ char buffer[256];
+
+ DBG(DBG_proc, "xsane_define_output_filename\n");
+
+ if (xsane.output_filename)
+ {
+ free(xsane.output_filename);
+ xsane.output_filename = 0;
+ }
+
+ if (!xsane.force_filename)
+ {
+ if (xsane.filetype)
+ {
+ snprintf(buffer, sizeof(buffer), "%s%s", preferences.filename, xsane.filetype);
+ xsane.output_filename = strdup(buffer);
+ }
+ else
+ {
+ xsane.output_filename = strdup(preferences.filename);
+ }
+ }
+ else
+ {
+ xsane.output_filename = strdup(xsane.external_filename);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+int xsane_identify_output_format(char *filename, char **ext)
+{
+ char *extension;
+ int output_format=-1;
+
+ DBG(DBG_proc, "xsane_identify_output_format\n");
+
+ extension = strrchr(filename, '.');
+ if (extension)
+ {
+ extension++; /* skip "." */
+ }
+
+ output_format = XSANE_UNKNOWN;
+
+ if (extension)
+ {
+ if (!strcasecmp(extension, "raw"))
+ {
+ if (xsane.param.depth == 16)
+ {
+ output_format = XSANE_RAW16;
+ }
+ }
+ else if ( (!strcasecmp(extension, "pnm")) || (!strcasecmp(extension, "ppm")) ||
+ (!strcasecmp(extension, "pgm")) || (!strcasecmp(extension, "pbm")) )
+ {
+ if (xsane.param.depth == 16)
+ {
+ output_format = XSANE_PNM16;
+ }
+ else
+ {
+ output_format = XSANE_PNM;
+ }
+ }
+#ifdef HAVE_LIBPNG
+#ifdef HAVE_LIBZ
+ else if (!strcasecmp(extension, "png"))
+ {
+ output_format = XSANE_PNG;
+ }
+#endif
+#endif
+#ifdef HAVE_LIBJPEG
+ else if ( (!strcasecmp(extension, "jpg")) || (!strcasecmp(extension, "jpeg")) )
+ {
+ output_format = XSANE_JPEG;
+ }
+#endif
+ else if (!strcasecmp(extension, "ps"))
+ {
+ output_format = XSANE_PS;
+ }
+#ifdef HAVE_LIBTIFF
+ else if ( (!strcasecmp(extension, "tif")) || (!strcasecmp(extension, "tiff")) )
+ {
+ output_format = XSANE_TIFF;
+ }
+#endif
+#ifdef SUPPORT_RGBA
+ else if (!strcasecmp(extension, "rgba"))
+ {
+ output_format = XSANE_RGBA;
+ }
+#endif
+ }
+
+ if (ext)
+ {
+ if (extension)
+ {
+ *ext = strdup(extension);
+ }
+ else
+ {
+ *ext = 0;
+ }
+ }
+
+ return output_format;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_change_working_directory(void)
+{
+ char filename[PATH_MAX];
+ char windowname[256];
+
+ DBG(DBG_proc, "xsane_change_working_directory\n");
+
+ xsane_set_sensitivity(FALSE);
+
+ sprintf(windowname, "%s %s %s", xsane.prog_name, WINDOW_CHANGE_WORKING_DIR, xsane.device_text);
+ if (getcwd(filename, sizeof(filename)))
+ {
+ xsane_back_gtk_get_filename(windowname, filename, sizeof(filename), filename, TRUE, FALSE, TRUE);
+ if (chdir(filename))
+ {
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "%s %s (%s).", ERR_CHANGE_WORKING_DIR, filename, strerror(errno));
+ xsane_back_gtk_error(buf, TRUE);
+ xsane_set_sensitivity(TRUE);
+ return;
+ }
+ }
+
+ xsane_set_sensitivity(TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+static int license_flag;
+static GtkWidget *license_dialog = NULL;
+
+static void xsane_license_button_callback(GtkWidget *widget, gpointer data)
+{
+ license_flag = (int) data;
+
+ DBG(DBG_proc ,"xsane_license_button_callback(%d)\n", license_flag);
+
+ gtk_widget_destroy(license_dialog);
+ license_dialog = NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+int xsane_display_license(int ask_for_accept)
+/* returns FALSE if accepted, TRUE if not accepted */
+{
+ GtkWidget *vbox, *hbox, *button, *label;
+ GtkWidget *text, *vscrollbar;
+ GtkAccelGroup *accelerator_group;
+ char buf[1024];
+ char filename[PATH_MAX];
+ FILE *infile;
+
+ DBG(DBG_proc, "xsane_display_license(%d)\n", ask_for_accept);
+
+ if (license_dialog) /* make sure the dialog is only opend once */
+ {
+ return 0;
+ }
+
+ license_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
+ gtk_widget_set_usize(license_dialog, 550, 580);
+ gtk_window_set_position(GTK_WINDOW(license_dialog), GTK_WIN_POS_CENTER);
+ gtk_window_set_policy(GTK_WINDOW(license_dialog), FALSE, TRUE, FALSE);
+ gtk_signal_connect(GTK_OBJECT(license_dialog), "delete_event",
+ GTK_SIGNAL_FUNC(xsane_license_button_callback), (void *) -1); /* -1 = cancel */
+ snprintf(buf, sizeof(buf), "%s %s", xsane.prog_name, WINDOW_LICENSE);
+ gtk_window_set_title(GTK_WINDOW(license_dialog), buf);
+ xsane_set_window_icon(license_dialog, 0);
+
+ accelerator_group = gtk_accel_group_new();
+ gtk_accel_group_attach(accelerator_group, GTK_OBJECT(license_dialog));
+
+ vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
+ gtk_container_add(GTK_CONTAINER(license_dialog), vbox);
+ gtk_widget_show(vbox);
+
+ /* display XSane copyright message */
+ snprintf(buf, sizeof(buf), "XSane %s %s\n"
+ "%s %s\n"
+ "\n"
+ "%s\n"
+ "%s %s\n"
+ "%s %s\n",
+ TEXT_VERSION, XSANE_VERSION,
+ XSANE_COPYRIGHT_SIGN, XSANE_COPYRIGHT_TXT,
+ TEXT_GPL,
+ TEXT_HOMEPAGE, XSANE_HOMEPAGE,
+ TEXT_EMAIL, XSANE_EMAIL);
+
+ label = gtk_label_new(buf);
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ /* add hbox with text and scrollbar to display the license text */
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show(hbox);
+
+ /* Create the GtkText widget */
+ text = gtk_text_new(NULL, NULL);
+ gtk_text_set_editable(GTK_TEXT(text), FALSE); /* text is not editable */
+ gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); /* wrap complete words */
+ gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 0);
+ gtk_widget_show(text);
+
+ /* Add a vertical scrollbar to the GtkText widget */
+ vscrollbar = gtk_vscrollbar_new(GTK_TEXT(text)->vadj);
+ gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
+ gtk_widget_show(vscrollbar);
+
+ /* Freeze the text widget, ready for multiple updates */
+ gtk_text_freeze(GTK_TEXT(text));
+
+ /* Load the file text.c into the text window */
+ xsane_back_gtk_make_path(sizeof(filename), filename, "xsane", 0, "xsane-license", 0, ".txt", XSANE_PATH_SYSTEM);
+ infile = fopen(filename, "r");
+
+ if (infile)
+ {
+ char buffer[4096];
+ int nchars;
+
+ while (!feof(infile))
+ {
+ nchars = fread(buffer, 1, 4096, infile);
+ gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buffer, nchars);
+ }
+
+ fclose(infile);
+ }
+ else
+ {
+ DBG(DBG_error0, "ERROR: license text not found. Looks like xsane is not installed correct.\n");
+ return TRUE;
+ }
+
+ /* Thaw the text widget, allowing the updates to become visible */
+ gtk_text_thaw(GTK_TEXT(text));
+
+
+
+ hbox = gtk_hbox_new(FALSE, 2);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+ if (ask_for_accept) /* show accept + not accept buttons */
+ {
+ button = gtk_button_new_with_label(BUTTON_ACCEPT);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_license_button_callback, (void *) 0 /* accept */);
+ gtk_container_add(GTK_CONTAINER(hbox), button);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label(BUTTON_NOT_ACCEPT);
+ gtk_widget_add_accelerator(button, "clicked", accelerator_group, GDK_Escape, 0, GTK_ACCEL_LOCKED);
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_license_button_callback, (void *) 1 /* not accept */);
+ gtk_container_add(GTK_CONTAINER(hbox), button);
+ gtk_widget_grab_default(button);
+ gtk_widget_show(button);
+ }
+ else /* show close button */
+ {
+ button = gtk_button_new_with_label(BUTTON_CLOSE);
+ gtk_widget_add_accelerator(button, "clicked", accelerator_group, GDK_Escape, 0, GTK_ACCEL_LOCKED);
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_license_button_callback, (void *) 0 /* ok = accept */);
+ gtk_container_add(GTK_CONTAINER(hbox), button);
+ gtk_widget_grab_default(button);
+ gtk_widget_show(button);
+ }
+
+ gtk_widget_show(hbox);
+ gtk_widget_show(vbox);
+ gtk_widget_show(license_dialog);
+
+ if (ask_for_accept == 0) /* do not ask for accept */
+ {
+ return 0;
+ }
+
+ license_flag = -255;
+
+ while(license_flag == -255)
+ {
+ gtk_main_iteration(); /* allow gtk to react to user action */
+ }
+
+ while (gtk_events_pending())
+ {
+ gtk_main_iteration();
+ }
+
+ return license_flag;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_widget_get_uposition(GtkWidget *gtk_window, gint *x, gint *y)
+{
+ if (xsane.get_deskrelative_origin)
+ {
+ DBG(DBG_proc, "xsane_widget_get_uposition(deskrelative)\n");
+ gdk_window_get_deskrelative_origin(gtk_window->window, x, y);
+ }
+ else
+ {
+ DBG(DBG_proc, "xsane_widget_get_uposition(root)\n");
+ gdk_window_get_root_origin(gtk_window->window, x, y);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */
+
+void xsane_widget_test_uposition(GtkWidget *gtk_window)
+{
+ gint x, y, x_orig, y_orig;
+
+ DBG(DBG_proc, "xsane_widget_test_uposition\n");
+
+ gtk_widget_realize(gtk_window);
+
+ while (!GTK_WIDGET_REALIZED(gtk_window) || (gtk_events_pending()))
+ {
+ gtk_main_iteration();
+ }
+
+ xsane_widget_get_uposition(gtk_window, &x, &y);
+ xsane_widget_get_uposition(gtk_window, &x, &y);
+
+ DBG(DBG_info, "xsane_widget_test_uposition: original position = %d, %d\n", x, y);
+
+ x_orig = x;
+ y_orig = y;
+ gtk_widget_set_uposition(gtk_window, x, y);
+
+ xsane_widget_get_uposition(gtk_window, &x, &y);
+ DBG(DBG_info, "xsane_widget_test_uposition: new position = %d, %d\n", x, y);
+
+ if ( (x != x_orig) || (y != y_orig) )
+ {
+ DBG(DBG_proc, "xsane_widget_test_uposition: using deskrelative function\n");
+ xsane.get_deskrelative_origin = 1;
+ }
+ else
+ {
+ DBG(DBG_proc, "xsane_widget_test_uposition: using root function\n");
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------------------------- */