1 /* xsane -- a graphical (X11, gtk) scanner-oriented SANE frontend
2
3 xsane-back-gtk.c
4
5 Oliver Rauch <Oliver.Rauch@rauch-domain.de>
6 Copyright (C) 1998-2010 Oliver Rauch
7 This file is part of the XSANE package.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
22
23 /* ----------------------------------------------------------------------------------------------------------------- */
24
25 #include "xsane.h"
26 #include "xsane-back-gtk.h"
27 #include "xsane-front-gtk.h"
28 #include "xsane-preferences.h"
29 #include "xsane-gamma.h"
30
31 /* ----------------------------------------------------------------------------------------------------------------- */
32
33 /* extern declarations */
34 extern void xsane_panel_build(void);
35
36 /* ----------------------------------------------------------------------------------------------------------------- */
37
38 /* forward declarations: */
39 SANE_Status xsane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int *info);
40 const SANE_Option_Descriptor *xsane_get_option_descriptor(SANE_Handle handle, SANE_Int option);
41 const char *xsane_back_gtk_unit_string(SANE_Unit unit);
42 void xsane_back_gtk_set_tooltip(GtkTooltips *tooltips, GtkWidget *widget, const gchar *desc);
43 int xsane_back_gtk_make_path(size_t buf_size, char *buf, const char *prog_name, const char *dir_name,
44 const char *prefix, const char *dev_name, const char *postfix, int location);
45 void xsane_back_gtk_set_option(int opt_num, void *val, SANE_Action action);
46
47 static void xsane_back_gtk_panel_rebuild(void);
48 void xsane_set_sensitivity(SANE_Int sensitivity);
49 void xsane_set_window_icon(GtkWidget *gtk_window, gchar **xpm_d);
50
51 /* ----------------------------------------------------------------------------------------------------------------- */
52
xsane_bound_int(int * value,int min,int max)53 void xsane_bound_int(int *value, int min, int max)
54 {
55 DBG(DBG_proc3, "xsane_bound_int\n");
56
57 if (min > max)
58 {
59 int help = min;
60 min = max;
61 max = help;
62 }
63
64 if (*value < min)
65 {
66 *value = min;
67 }
68
69 if (*value > max)
70 {
71 *value = max;
72 }
73 }
74
75 /* ----------------------------------------------------------------------------------------------------------------- */
76
xsane_bound_float(float * value,float min,float max)77 void xsane_bound_float(float *value, float min, float max)
78 {
79 DBG(DBG_proc3, "xsane_bound_float\n");
80
81 if (min > max)
82 {
83 double help = min;
84 min = max;
85 max = help;
86 }
87
88 if (*value < min)
89 {
90 *value = min;
91 }
92
93 if (*value > max)
94 {
95 *value = max;
96 }
97 }
98
99 /* ----------------------------------------------------------------------------------------------------------------- */
100
xsane_bound_double(double * value,double min,double max)101 void xsane_bound_double(double *value, double min, double max)
102 {
103 DBG(DBG_proc3, "xsane_bound_double\n");
104
105 if (min > max)
106 {
107 double help = min;
108 min = max;
109 max = help;
110 }
111
112 if (*value < min)
113 {
114 *value = min;
115 }
116
117 if (*value > max)
118 {
119 *value = max;
120 }
121 }
122
123 /* ----------------------------------------------------------------------------------------------------------------- */
124
125 /* returns 1 if value is in bounds */
xsane_check_bound_double(double value,double min,double max)126 int xsane_check_bound_double(double value, double min, double max)
127 {
128 int in_bounds = 1;
129
130 DBG(DBG_proc3, "xsane_check_bound_double\n");
131
132 if (min > max)
133 {
134 double help = min;
135 min = max;
136 max = help;
137 }
138
139 if (value < min)
140 {
141 in_bounds = 0;
142 }
143
144 if (value > max)
145 {
146 in_bounds = 0;
147 }
148
149 return (in_bounds);
150 }
151
152 /* ----------------------------------------------------------------------------------------------------------------- */
153
xsane_get_option_descriptor(SANE_Handle handle,SANE_Int option)154 const SANE_Option_Descriptor *xsane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
155 {
156 DBG(DBG_optdesc, "xsane_get_option_descriptor(%d)\n", option);
157
158 if (option >= 0)
159 {
160 return sane_get_option_descriptor(handle, option);
161 }
162 return NULL;
163 }
164
165 /* ----------------------------------------------------------------------------------------------------------------- */
166
xsane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * val,SANE_Int * info)167 SANE_Status xsane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int *info)
168 {
169 DBG(DBG_proc, "xsane_control_option(option = %d, action = %d)\n", option, action);
170
171 if (option >= 0)
172 {
173 SANE_Status status;
174
175 #if 1
176 /* I am not sure about a correct and intelligent way to handle an option that has not defined SANE_CAP_SOFT_DETECT */
177 /* the test backend creates an option without SANE_CAP_SOFT_DETECT that causes an error message when I do not do the following */
178 if (action == SANE_ACTION_GET_VALUE)
179 {
180 const SANE_Option_Descriptor *opt;
181
182 opt = xsane_get_option_descriptor(xsane.dev, option);
183 if ((opt) && (!(opt->cap & SANE_CAP_SOFT_DETECT)))
184 {
185 DBG(DBG_warning, "WARNING: xsane_control_option(option = %d, action = %d): SANE_CAP_SOFT_DETECT is not set\n", option, action);
186 if (option > 0) /* continue for option == 0, otherwise we can not read this option */
187 {
188 return SANE_STATUS_GOOD;
189 }
190 }
191 }
192 #endif
193
194 status = sane_control_option(handle, option, action, val, info);
195 if (status)
196 {
197 DBG(DBG_error, "ERROR: xsane_control_option(option = %d, action = %d) failed\n", option, action);
198 }
199
200 return status;
201 }
202
203 return SANE_STATUS_INVAL;
204 }
205
206 /* ----------------------------------------------------------------------------------------------------------------- */
207
xsane_back_gtk_unit_string(SANE_Unit unit)208 const char *xsane_back_gtk_unit_string(SANE_Unit unit)
209 {
210 DBG(DBG_proc, "xsane_back_gtk_unit_string\n");
211
212 switch (unit)
213 {
214 case SANE_UNIT_NONE: return "none";
215 case SANE_UNIT_PIXEL: return "px";
216 case SANE_UNIT_BIT: return "bit";
217 case SANE_UNIT_DPI: return "dpi";
218 case SANE_UNIT_PERCENT: return "%";
219 case SANE_UNIT_MM:
220 if (preferences.length_unit > 9.9 && preferences.length_unit < 10.1)
221 {
222 return "cm";
223 }
224 else if (preferences.length_unit > 25.3 && preferences.length_unit < 25.5)
225 {
226 return "in";
227 }
228 return "mm";
229 case SANE_UNIT_MICROSECOND: return "\302\265s"; /* UTF8 µs */
230 }
231 return 0;
232 }
233
234 /* ----------------------------------------------------------------------------------------------------------------- */
235
xsane_back_gtk_set_tooltip(GtkTooltips * tooltips,GtkWidget * widget,const gchar * desc)236 void xsane_back_gtk_set_tooltip(GtkTooltips *tooltips, GtkWidget *widget, const gchar *desc)
237 {
238 DBG(DBG_proc, "xsane_back_gtk_set_tooltip\n");
239
240 if (desc && desc[0])
241 {
242 gtk_tooltips_set_tip(tooltips, widget, desc, 0);
243 }
244 }
245
246 /* ----------------------------------------------------------------------------------------------------------------- */
247
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)248 int xsane_back_gtk_make_path(size_t buf_size, char *buf, const char *prog_name, const char *dir_name,
249 const char *prefix, const char *dev_name, const char *postfix, int location)
250 {
251 size_t len, extra;
252 int i;
253
254 DBG(DBG_proc, "xsane_back_gtk_make_path\n");
255
256 if (location == XSANE_PATH_LOCAL_SANE) /* make path to local file */
257 {
258 if (getenv(STRINGIFY(ENVIRONMENT_APPDATA_DIR_NAME)) != NULL)
259 {
260 snprintf(buf, buf_size-2, "%s%c.sane", getenv(STRINGIFY(ENVIRONMENT_APPDATA_DIR_NAME)), SLASH);
261 }
262 else
263 {
264 snprintf(buf, buf_size-2, "%s", STRINGIFY(XSANE_FIXED_APPDATA_DIR));
265 }
266 mkdir(buf, 0777); /* ensure ~/.sane directory exists */
267 }
268 else if (location == XSANE_PATH_SYSTEM) /* make path to system file */
269 {
270 snprintf(buf, buf_size-2, "%s", STRINGIFY(PATH_SANE_DATA_DIR));
271 }
272 else /* make path to temporary file XSANE_PATH_TMP */
273 {
274 snprintf(buf, buf_size-2, "%s", preferences.tmp_path);
275 }
276
277 len = strlen(buf);
278
279 buf[len++] = SLASH;
280
281 if (prog_name)
282 {
283 extra = strlen(prog_name);
284 if (len + extra + 2 >= buf_size)
285 {
286 goto filename_too_long;
287 }
288
289 memcpy(buf + len, prog_name, extra);
290 len += extra;
291
292 buf[len] = '\0';
293 mkdir(buf, 0777); /* ensure ~/.sane/PROG_NAME directory exists */
294
295 buf[len++] = SLASH; /* OS/2 does not like slash at end of mktemp-path */
296 }
297
298 if (len >= buf_size)
299 {
300 goto filename_too_long;
301 }
302
303 if (dir_name)
304 {
305 extra = strlen(dir_name);
306 if (len + extra + 2 >= buf_size)
307 {
308 goto filename_too_long;
309 }
310
311 memcpy(buf + len, dir_name, extra);
312 len += extra;
313
314 buf[len++] = SLASH;
315
316 buf[len] = '\0';
317 mkdir(buf, 0777); /* ensure DIR_NAME directory exists */
318 }
319
320 if (len >= buf_size)
321 {
322 goto filename_too_long;
323 }
324
325
326 if (prefix)
327 {
328 extra = strlen(prefix);
329 if (len + extra >= buf_size)
330 {
331 goto filename_too_long;
332 }
333
334 memcpy(buf + len, prefix, extra);
335 len += extra;
336 }
337
338 if (dev_name)
339 {
340 /* Turn devicename into valid filename by replacing slashes and other forbidden characters by "_", "_" gets "__", spaces are erased */
341
342 for (i = 0; dev_name[i]; ++i)
343 {
344 if (len + 2 >= buf_size)
345 {
346 goto filename_too_long;
347 }
348
349 switch (dev_name[i])
350 {
351 case '\\': /* "\" -> "_" */
352 buf[len++] = '_';
353 break;
354
355 case '/': /* "/" -> "_" */
356 buf[len++] = '_';
357 break;
358
359 case '*': /* "*" -> "_" */
360 buf[len++] = '_';
361 break;
362
363 case '?': /* "?" -> "_" */
364 buf[len++] = '_';
365 break;
366
367 #ifdef _WIN32
368 case ':': /* ":" -> "_" */
369 buf[len++] = '_';
370 break;
371 #endif
372
373 #ifdef HAVE_OS2_H
374 case ':': /* ":" -> "_" */
375 buf[len++] = '_';
376 break;
377 #endif
378
379 case ' ': /* erase " " */
380 break;
381
382 case '_': /* "_" -> "__" */
383 buf[len++] = '_';
384 /* fall through */
385 default:
386 buf[len++] = dev_name[i];
387 break;
388 }
389 }
390 }
391
392 if (postfix)
393 {
394 extra = strlen(postfix);
395 if (len + extra >= buf_size)
396 {
397 goto filename_too_long;
398 }
399 memcpy(buf + len, postfix, extra);
400 len += extra;
401 }
402
403 if (len >= buf_size)
404 {
405 goto filename_too_long;
406 }
407
408 if (location == XSANE_PATH_TMP) /* tmp dir, add uid */
409 {
410 char tmpbuf[TEXTBUFSIZE];
411 uid_t uid;
412 int fd;
413
414 uid = getuid();
415 snprintf(tmpbuf, sizeof(tmpbuf), "-%d-", (int) uid);
416
417 extra = strlen(tmpbuf);
418 if (len + extra >= buf_size)
419 {
420 goto filename_too_long;
421 }
422
423 memcpy(buf + len, tmpbuf, extra);
424 len += extra;
425
426 if (len + 7 >= buf_size)
427 {
428 goto filename_too_long;
429 }
430
431 memcpy(buf + len, "XXXXXX", 6); /* create unique filename */
432 len += 6;
433 buf[len] = '\0';
434
435 fd = mkstemp(buf); /* create unique filename and opens/creates the file */
436 if (fd == -1)
437 {
438 xsane_back_gtk_error(ERR_CREATE_TEMP_FILE, FALSE);
439 return -1;
440 }
441 close(fd); /* will be opened again later */
442 }
443 else
444 {
445 buf[len++] = '\0';
446 }
447
448 DBG(DBG_proc, "path = \"%s\"\n", buf);
449
450 return 0;
451
452
453 filename_too_long:
454 xsane_back_gtk_error(ERR_FILENAME_TOO_LONG, FALSE);
455 errno = E2BIG;
456 return -1;
457 }
458
459 /* ----------------------------------------------------------------------------------------------------------------- */
460
xsane_back_gtk_set_option(int opt_num,void * val,SANE_Action action)461 void xsane_back_gtk_set_option(int opt_num, void *val, SANE_Action action)
462 {
463 SANE_Status status;
464 SANE_Int info;
465 char buf[TEXTBUFSIZE];
466 int old_channels = xsane.xsane_channels;
467 int update_gamma = FALSE;
468
469 DBG(DBG_proc, "xsane_back_gtk_set_option\n");
470
471 status = xsane_control_option(xsane.dev, opt_num, action, val, &info);
472 if (status != SANE_STATUS_GOOD)
473 {
474 snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_SET_OPTION, xsane_get_option_descriptor(xsane.dev, opt_num)->name,
475 XSANE_STRSTATUS(status));
476 xsane_back_gtk_error(buf, FALSE);
477 return;
478 }
479
480 if (info & SANE_INFO_RELOAD_PARAMS)
481 {
482 xsane_update_param(0);
483 }
484
485 if (info & SANE_INFO_RELOAD_OPTIONS)
486 {
487 xsane_back_gtk_panel_rebuild();
488
489 if (xsane.preview)
490 {
491 preview_update_surface(xsane.preview, 0);
492 }
493
494 update_gamma = TRUE; /* scanner gamma correction may have changed, medium may need update */
495 }
496 else if (info & SANE_INFO_INEXACT)
497 {
498 /* XXXXXXXXXXXXXX this also has to be handled XXXXXXXXXXXXXXX */
499 }
500
501 if (xsane.xsane_channels != old_channels)
502 {
503 /* we have to update gamma tables and histogram because medium settings */
504 /* may have changed */
505 update_gamma = TRUE;
506 }
507
508 if (update_gamma)
509 {
510 xsane_update_gamma_curve(TRUE);
511 }
512 }
513
514 /* ----------------------------------------------------------------------------------------------------------------- */
515
xsane_back_gtk_get_option_double(int option,double * val,SANE_Int * unit)516 int xsane_back_gtk_get_option_double(int option, double *val, SANE_Int *unit)
517 /* return values: */
518 /* 0 = OK */
519 /* -1 = option number < 0 */
520 /* -2 = failed to set option */
521 {
522 const SANE_Option_Descriptor *opt;
523 SANE_Handle dev;
524 SANE_Word word;
525
526 DBG(DBG_proc, "xsane_back_gtk_get_option_double\n");
527
528 if (option <= 0)
529 {
530 return -1;
531 }
532
533 if (xsane_control_option(xsane.dev, option, SANE_ACTION_GET_VALUE, &word, 0) == SANE_STATUS_GOOD)
534 {
535 dev = xsane.dev;
536 opt = xsane_get_option_descriptor(dev, option);
537
538 if (unit)
539 {
540 *unit = opt->unit;
541 }
542
543 if (val)
544 {
545 if (opt->type == SANE_TYPE_FIXED)
546 {
547 *val = (float) word / 65536.0;
548 }
549 else
550 {
551 *val = (float) word;
552 }
553 }
554
555 return 0;
556 }
557 else if (val)
558 {
559 *val = 0;
560 }
561 return -2;
562 }
563
564 /* ----------------------------------------------------------------------------------------------------------------- */
565
xsane_back_gtk_set_option_double(int option,double value)566 int xsane_back_gtk_set_option_double(int option, double value)
567 {
568 const SANE_Option_Descriptor *opt;
569 SANE_Word word;
570
571 DBG(DBG_proc, "xsane_set_option_double\n");
572
573 if (option <= 0 || value <= -INF || value >= INF)
574 {
575 return -1;
576 }
577
578 opt = xsane_get_option_descriptor(xsane.dev, option);
579 if (opt)
580 {
581 if (opt->type == SANE_TYPE_FIXED)
582 {
583 word = SANE_FIX(value);
584 }
585 else
586 {
587 word = value + 0.5;
588 }
589
590 if (xsane_control_option(xsane.dev, option, SANE_ACTION_SET_VALUE, &word, 0))
591 {
592 return -2;
593 }
594 }
595 else
596 {
597 return -1;
598 }
599
600 return 0;
601 }
602
603 /* ----------------------------------------------------------------------------------------------------------------- */
604
xsane_back_gtk_decision_delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)605 static int xsane_back_gtk_decision_delete_event(GtkWidget * widget, GdkEvent *event, gpointer data)
606 {
607 gint *decision_flag = (gint *) data;
608
609 DBG(DBG_proc, "xsane_back_gtk_decision_delete_event\n");
610
611 xsane.back_gtk_message_dialog_active--;
612
613 if (decision_flag)
614 {
615 *decision_flag = -1;
616 }
617
618 return FALSE; /* continue with original delete even routine */
619 }
620
621 /* ----------------------------------------------------------------------------------------------------------------- */
622
xsane_back_gtk_decision_ok_callback(GtkWidget * widget,gpointer data)623 static void xsane_back_gtk_decision_ok_callback(GtkWidget *widget, gpointer data)
624 {
625 gint *decision_flag = (gint *) data;
626
627 DBG(DBG_proc, "xsane_back_gtk_decision_ok_callback\n");
628
629 gtk_widget_destroy(widget->parent->parent->parent->parent);
630 xsane.back_gtk_message_dialog_active--;
631
632 if (decision_flag)
633 {
634 *decision_flag = 1;
635 }
636 }
637
638 /* ----------------------------------------------------------------------------------------------------------------- */
639
xsane_back_gtk_decision_reject_callback(GtkWidget * widget,gpointer data)640 static void xsane_back_gtk_decision_reject_callback(GtkWidget *widget, gpointer data)
641 {
642 gint *decision_flag = (gint *) data;
643
644 DBG(DBG_proc, "xsane_back_gtk_decision_reject_callback\n");
645
646 gtk_widget_destroy(widget->parent->parent->parent->parent);
647 xsane.back_gtk_message_dialog_active--;
648
649 if (decision_flag)
650 {
651 *decision_flag = -1;
652 }
653 }
654
655 /* ----------------------------------------------------------------------------------------------------------------- */
656
xsane_back_gtk_decision(gchar * title,gchar ** xpm_d,gchar * message,gchar * oktext,gchar * rejecttext,int wait)657 gint xsane_back_gtk_decision(gchar *title, gchar **xpm_d, gchar *message, gchar *oktext, gchar *rejecttext, int wait)
658 {
659 GtkWidget *main_vbox, *hbox, *label, *button, *frame;
660 GdkPixmap *pixmap;
661 GdkBitmap *mask;
662 GtkWidget *pixmapwidget;
663 GtkWidget *decision_dialog;
664 GtkAccelGroup *accelerator_group;
665 gint decision_flag;
666 gint *decision_flag_ptr = NULL;
667
668 DBG(DBG_proc, "xsane_back_gtk_decision\n");
669
670 if (wait)
671 {
672 decision_flag_ptr = &decision_flag;
673 }
674
675 xsane.back_gtk_message_dialog_active++;
676 decision_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
677 gtk_window_set_position(GTK_WINDOW(decision_dialog), GTK_WIN_POS_MOUSE);
678 gtk_window_set_title(GTK_WINDOW(decision_dialog), title);
679 g_signal_connect(GTK_OBJECT(decision_dialog), "delete_event", GTK_SIGNAL_FUNC(xsane_back_gtk_decision_delete_event), (void *) decision_flag_ptr);
680
681 xsane_set_window_icon(decision_dialog, 0);
682
683 accelerator_group = gtk_accel_group_new();
684 gtk_window_add_accel_group(GTK_WINDOW(decision_dialog), accelerator_group);
685
686 /* create a frame */
687 frame = gtk_frame_new(NULL);
688 gtk_container_set_border_width(GTK_CONTAINER(frame), 10);
689 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
690 gtk_container_add(GTK_CONTAINER(decision_dialog), frame);
691 gtk_widget_show(frame);
692
693 /* create the main vbox */
694 main_vbox = gtk_vbox_new(FALSE, 5);
695 gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 5);
696 gtk_widget_show(main_vbox);
697 gtk_container_add(GTK_CONTAINER(frame), main_vbox);
698
699 /* create a horizontal box to put the icon and the text insode */
700 hbox = gtk_hbox_new(FALSE, 2);
701 gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
702 gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, FALSE, 0);
703
704 /* the info icon */
705 if (xpm_d)
706 {
707 pixmap = gdk_pixmap_create_from_xpm_d(decision_dialog->window, &mask, xsane.bg_trans, xpm_d);
708 pixmapwidget = gtk_image_new_from_pixmap(pixmap, mask);
709 gtk_box_pack_start(GTK_BOX(hbox), pixmapwidget, FALSE, FALSE, 10);
710 gtk_widget_show(pixmapwidget);
711 gdk_drawable_unref(pixmap);
712 gdk_drawable_unref(mask);
713 }
714
715 /* the message */
716 label = gtk_label_new(message);
717 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
718 gtk_widget_show(label);
719
720 gtk_widget_show(hbox);
721
722
723 hbox = gtk_hbox_new(FALSE, 2);
724 gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
725 gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, FALSE, 0);
726
727 /* the confirmation button */
728 button = gtk_button_new_with_label(oktext);
729 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
730 g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_back_gtk_decision_ok_callback, (void *) decision_flag_ptr);
731 gtk_box_pack_end(GTK_BOX(hbox), button, TRUE, TRUE, 5);
732 gtk_widget_grab_default(button);
733 gtk_widget_show(button);
734
735
736 if (rejecttext) /* the rejection button */
737 {
738 button = gtk_button_new_with_label(rejecttext);
739 g_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc) xsane_back_gtk_decision_reject_callback, (void *) decision_flag_ptr);
740 gtk_box_pack_end(GTK_BOX(hbox), button, TRUE, TRUE, 5);
741 gtk_widget_show(button);
742 }
743
744 /* if rejectbutton is available then the following command is valid for the reject button */
745 /* otherwise it is valid for the ok button */
746 gtk_widget_add_accelerator(button, "clicked", accelerator_group, GDK_Escape, 0, DEF_GTK_ACCEL_LOCKED);
747
748 gtk_widget_show(hbox);
749 gtk_widget_show(decision_dialog);
750
751
752 while (gtk_events_pending())
753 {
754 gtk_main_iteration();
755 }
756
757 if (!wait)
758 {
759 return TRUE;
760 }
761
762 decision_flag = 0;
763
764 while (decision_flag == 0)
765 {
766 gtk_main_iteration();
767 }
768
769 while (gtk_events_pending())
770 {
771 gtk_main_iteration();
772 }
773
774 if (decision_flag == 1)
775 {
776 return TRUE;
777 }
778
779 return FALSE;
780 }
781
782 /* ----------------------------------------------------------------------------------------------------------------- */
783
xsane_back_gtk_ipc_dialog_callback(gpointer data,gint source,GdkInputCondition cond)784 void xsane_back_gtk_ipc_dialog_callback(gpointer data, gint source, GdkInputCondition cond)
785 {
786 char message[TEXTBUFSIZE];
787 size_t bytes;
788
789 DBG(DBG_proc, "xsane_back_gtk_message\n");
790
791 bytes = read(xsane.ipc_pipefd[0], message, sizeof(message)-1);
792 message[bytes] = 0;
793
794 xsane_back_gtk_decision(ERR_HEADER_CHILD_PROCESS_ERROR, (gchar **) error_xpm, message, BUTTON_CLOSE, 0 /* no reject text */, FALSE);
795 }
796
797 /* ----------------------------------------------------------------------------------------------------------------- */
798
xsane_back_gtk_message(gchar * title,gchar ** icon_xpm,gchar * message,int wait)799 void xsane_back_gtk_message(gchar *title, gchar **icon_xpm, gchar *message, int wait)
800 {
801 DBG(DBG_proc, "xsane_back_gtk_message\n");
802
803 xsane_back_gtk_decision(title, icon_xpm, message, BUTTON_CLOSE, 0 /* no reject text */, wait);
804 }
805
806 /* ----------------------------------------------------------------------------------------------------------------- */
807
xsane_back_gtk_error(gchar * error,int wait)808 void xsane_back_gtk_error(gchar *error, int wait)
809 {
810 DBG(DBG_proc, "xsane_back_gtk_error: %s\n", error);
811
812 if (wait)
813 {
814 SANE_Int old_sensitivity = xsane.sensitivity;
815
816 xsane_set_sensitivity(FALSE);
817 xsane_back_gtk_message(ERR_HEADER_ERROR, (gchar**) error_xpm, error, wait);
818 xsane_set_sensitivity(old_sensitivity);
819 }
820 else
821 {
822 xsane_back_gtk_message(ERR_HEADER_ERROR, (gchar **) error_xpm, error, wait);
823 }
824 }
825
826 /* ----------------------------------------------------------------------------------------------------------------- */
827
xsane_back_gtk_warning(gchar * warning,int wait)828 void xsane_back_gtk_warning(gchar *warning, int wait)
829 {
830 DBG(DBG_proc, "xsane_back_gtk_warning: %s\n", warning);
831
832 if (wait)
833 {
834 SANE_Int old_sensitivity = xsane.sensitivity;
835
836 xsane_set_sensitivity(FALSE);
837 xsane_back_gtk_message(ERR_HEADER_WARNING, (gchar**) warning_xpm, warning, wait);
838 xsane_set_sensitivity(old_sensitivity);
839 }
840 else
841 {
842 xsane_back_gtk_message(ERR_HEADER_WARNING, (gchar**) warning_xpm, warning, wait);
843 }
844 }
845
846 /* ----------------------------------------------------------------------------------------------------------------- */
847
xsane_back_gtk_info(gchar * info,int wait)848 void xsane_back_gtk_info(gchar *info, int wait)
849 {
850 DBG(DBG_proc, "xsane_back_gtk_info: %s\n", info);
851
852 if (wait)
853 {
854 SANE_Int old_sensitivity = xsane.sensitivity;
855
856 xsane_set_sensitivity(FALSE);
857 xsane_back_gtk_message(ERR_HEADER_INFO, (gchar**) info_xpm, info, wait);
858 xsane_set_sensitivity(old_sensitivity);
859 }
860 else
861 {
862 xsane_back_gtk_message(ERR_HEADER_INFO, (gchar**) info_xpm, info, wait);
863 }
864 }
865
866 /* ---------------------------------------------------------------------------------------------------------------------- */
867
xsane_back_gtk_filetype_menu_set_history(GtkWidget * xsane_filetype_option_menu,char * filetype)868 void xsane_back_gtk_filetype_menu_set_history(GtkWidget *xsane_filetype_option_menu, char *filetype)
869 {
870 int filetype_nr;
871 int select_item;
872
873 filetype_nr = 0;
874 select_item = 0;
875
876 #ifdef HAVE_LIBJPEG
877 filetype_nr++;
878 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_JPEG)) )
879 {
880 select_item = filetype_nr;
881 }
882 #endif
883
884 filetype_nr++;
885 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PDF)) )
886 {
887 select_item = filetype_nr;
888 }
889
890
891 #ifdef HAVE_LIBPNG
892 #ifdef HAVE_LIBZ
893 filetype_nr++;
894 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PNG)) )
895 {
896 select_item = filetype_nr;
897 }
898 #endif
899 #endif
900
901 filetype_nr++;
902 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PNM)) )
903 {
904 select_item = filetype_nr;
905 }
906
907 filetype_nr++;
908 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PS)) )
909 {
910 select_item = filetype_nr;
911 }
912
913 #ifdef SUPPORT_RGBA
914 filetype_nr++;
915 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_RGBA)) )
916 {
917 select_item = filetype_nr;
918 }
919 #endif
920
921 filetype_nr++;
922 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_TEXT)) )
923 {
924 select_item = filetype_nr;
925 }
926
927 #ifdef HAVE_LIBTIFF
928 filetype_nr++;
929 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_TIFF)) )
930 {
931 select_item = filetype_nr;
932 }
933 #endif
934 gtk_option_menu_set_history(GTK_OPTION_MENU(xsane_filetype_option_menu), select_item);
935 }
936
937 /* ---------------------------------------------------------------------------------------------------------------------- */
938
xsane_back_gtk_filetype_menu_new(char * filetype,GtkSignalFunc filetype_callback)939 GtkWidget *xsane_back_gtk_filetype_menu_new(char *filetype, GtkSignalFunc filetype_callback)
940 {
941 GtkWidget *xsane_filetype_menu, *xsane_filetype_item;
942 GtkWidget *xsane_filetype_option_menu;
943 int filetype_nr;
944 int select_item;
945
946 xsane_filetype_menu = gtk_menu_new();
947
948 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_BY_EXT);
949 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
950 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_BY_EXT);
951 gtk_widget_show(xsane_filetype_item);
952
953 filetype_nr = 0;
954 select_item = 0;
955
956 #ifdef HAVE_LIBJPEG
957 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_JPEG);
958 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
959 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_JPEG);
960 gtk_widget_show(xsane_filetype_item);
961 filetype_nr++;
962 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_JPEG)) )
963 {
964 select_item = filetype_nr;
965 }
966 #endif
967
968 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_PDF);
969 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
970 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_PDF);
971 gtk_widget_show(xsane_filetype_item);
972 filetype_nr++;
973 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PDF)) )
974 {
975 select_item = filetype_nr;
976 }
977
978 #ifdef HAVE_LIBPNG
979 #ifdef HAVE_LIBZ
980 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_PNG);
981 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
982 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_PNG);
983 gtk_widget_show(xsane_filetype_item);
984 filetype_nr++;
985 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PNG)) )
986 {
987 select_item = filetype_nr;
988 }
989 #endif
990 #endif
991
992 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_PNM);
993 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
994 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_PNM);
995 gtk_widget_show(xsane_filetype_item);
996 filetype_nr++;
997 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PNM)) )
998 {
999 select_item = filetype_nr;
1000 }
1001
1002 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_PS);
1003 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
1004 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_PS);
1005 gtk_widget_show(xsane_filetype_item);
1006 filetype_nr++;
1007 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_PS)) )
1008 {
1009 select_item = filetype_nr;
1010 }
1011
1012 #ifdef SUPPORT_RGBA
1013 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_RGBA);
1014 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
1015 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_RGBA);
1016 gtk_widget_show(xsane_filetype_item);
1017 filetype_nr++;
1018 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_RGBA)) )
1019 {
1020 select_item = filetype_nr;
1021 }
1022 #endif
1023
1024 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_TEXT);
1025 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
1026 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_TEXT);
1027 gtk_widget_show(xsane_filetype_item);
1028 filetype_nr++;
1029 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_TEXT)) )
1030 {
1031 select_item = filetype_nr;
1032 }
1033
1034 #ifdef HAVE_LIBTIFF
1035 xsane_filetype_item = gtk_menu_item_new_with_label(MENU_ITEM_FILETYPE_TIFF);
1036 gtk_container_add(GTK_CONTAINER(xsane_filetype_menu), xsane_filetype_item);
1037 g_signal_connect(GTK_OBJECT(xsane_filetype_item), "activate", filetype_callback, (void *) XSANE_FILETYPE_TIFF);
1038 gtk_widget_show(xsane_filetype_item);
1039 filetype_nr++;
1040 if ( (filetype) && (!strcasecmp(filetype, XSANE_FILETYPE_TIFF)) )
1041 {
1042 select_item = filetype_nr;
1043 }
1044 #endif
1045
1046 xsane_filetype_option_menu = gtk_option_menu_new();
1047 xsane_back_gtk_set_tooltip(xsane.tooltips, xsane_filetype_option_menu, DESC_FILETYPE);
1048 gtk_option_menu_set_menu(GTK_OPTION_MENU(xsane_filetype_option_menu), xsane_filetype_menu);
1049 gtk_option_menu_set_history(GTK_OPTION_MENU(xsane_filetype_option_menu), select_item);
1050
1051 return (xsane_filetype_option_menu);
1052 }
1053
1054 /* ----------------------------------------------------------------------------------------------------------------- */
1055
xsane_back_gtk_cms_function_menu_new(int select_cms_function,GtkSignalFunc cms_function_menu_callback)1056 GtkWidget *xsane_back_gtk_cms_function_menu_new(int select_cms_function, GtkSignalFunc cms_function_menu_callback)
1057 {
1058 GtkWidget *xsane_cms_function_menu, *xsane_cms_function_item;
1059 GtkWidget *xsane_cms_function_option_menu;
1060
1061 xsane_cms_function_menu = gtk_menu_new();
1062
1063 xsane_cms_function_item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE);
1064 if (cms_function_menu_callback)
1065 {
1066 g_signal_connect(GTK_OBJECT(xsane_cms_function_item), "activate", (GtkSignalFunc) cms_function_menu_callback, (void *) XSANE_CMS_FUNCTION_EMBED_SCANNER_ICM_PROFILE);
1067 }
1068 gtk_container_add(GTK_CONTAINER(xsane_cms_function_menu), xsane_cms_function_item);
1069 gtk_widget_show(xsane_cms_function_item);
1070
1071 xsane_cms_function_item = gtk_menu_item_new_with_label(MENU_ITEM_CMS_FUNCTION_CONVERT_TO_SRGB);
1072 if (cms_function_menu_callback)
1073 {
1074 g_signal_connect(GTK_OBJECT(xsane_cms_function_item), "activate", (GtkSignalFunc) cms_function_menu_callback, (void *) XSANE_CMS_FUNCTION_CONVERT_TO_SRGB);
1075 }
1076 gtk_container_add(GTK_CONTAINER(xsane_cms_function_menu), xsane_cms_function_item);
1077 gtk_widget_show(xsane_cms_function_item);
1078
1079 xsane_cms_function_item = gtk_menu_item_new_with_label(MENU_ITEM_FUNCTION_CONVERT_TO_WORKING_CS);
1080 if (cms_function_menu_callback)
1081 {
1082 g_signal_connect(GTK_OBJECT(xsane_cms_function_item), "activate", (GtkSignalFunc) cms_function_menu_callback, (void *) XSANE_CMS_FUNCTION_CONVERT_TO_WORKING_CS);
1083 }
1084 gtk_container_add(GTK_CONTAINER(xsane_cms_function_menu), xsane_cms_function_item);
1085 gtk_widget_show(xsane_cms_function_item);
1086
1087 xsane_cms_function_option_menu = gtk_option_menu_new();
1088 xsane_back_gtk_set_tooltip(xsane.tooltips, xsane_cms_function_option_menu, DESC_CMS_FUNCTION);
1089 gtk_option_menu_set_menu(GTK_OPTION_MENU(xsane_cms_function_option_menu), xsane_cms_function_menu);
1090 gtk_option_menu_set_history(GTK_OPTION_MENU(xsane_cms_function_option_menu), select_cms_function);
1091
1092 return (xsane_cms_function_option_menu);
1093 }
1094
1095 /* ----------------------------------------------------------------------------------------------------------------- */
1096
1097 #ifdef __GTK_FILE_CHOOSER_H__
1098
1099 GtkWidget *filechooser;
1100 char *filechooser_filetype = NULL;
1101
xsane_back_gtk_filetype2_callback(GtkWidget * widget,gpointer data)1102 static void xsane_back_gtk_filetype2_callback(GtkWidget *widget, gpointer data)
1103 {
1104 char *extension, *chooser_filename;
1105 char filename[PATH_MAX];
1106 char *basename;
1107 char *new_filetype = (char *) data;
1108 int pos;
1109
1110 DBG(DBG_proc, "xsane_filetype2_callback\n");
1111
1112 chooser_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
1113
1114 if ((new_filetype) && (*new_filetype))
1115 {
1116 extension = strrchr(chooser_filename, '.');
1117
1118 if ((extension) && (extension != chooser_filename))
1119 {
1120 if ( (!strcasecmp(extension, ".pnm")) || (!strcasecmp(extension, ".raw"))
1121 || (!strcasecmp(extension, ".png")) || (!strcasecmp(extension, ".ps"))
1122 || (!strcasecmp(extension, ".pdf")) || (!strcasecmp(extension, ".rgba"))
1123 || (!strcasecmp(extension, ".tiff")) || (!strcasecmp(extension, ".tif"))
1124 || (!strcasecmp(extension, ".text")) || (!strcasecmp(extension, ".txt"))
1125 || (!strcasecmp(extension, ".jpg")) || (!strcasecmp(extension, ".jpeg"))
1126 ) /* remove filetype extension */
1127 {
1128 *extension = 0; /* remove extension */
1129 }
1130 }
1131 snprintf(filename, sizeof(filename), "%s%s", chooser_filename, new_filetype);
1132 }
1133 else
1134 {
1135 snprintf(filename, sizeof(filename), "%s", chooser_filename);
1136 }
1137
1138 if (filechooser_filetype)
1139 {
1140 free(filechooser_filetype);
1141 filechooser_filetype = NULL;
1142 }
1143
1144 if (data)
1145 {
1146 filechooser_filetype = strdup(new_filetype);
1147 }
1148
1149
1150 basename = filename;
1151
1152 for (pos = strlen(filename) - 1; pos > 0; pos--)
1153 {
1154 if (filename[pos] == '/')
1155 {
1156 filename[pos]=0;
1157
1158 basename = filename+pos+1;
1159 break;
1160 }
1161 }
1162
1163 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filechooser), basename);
1164
1165 g_free(chooser_filename);
1166 }
1167
1168 /* ----------------------------------------------------------------------------------------------------------------- */
1169
xsane_back_gtk_get_filename(const char * label,const char * default_name,size_t max_len,char * filename,char ** filetype,int * cms_function,XsaneFileChooserAction action,int show_extra_widgets,int enable_filters,int activate_filter)1170 int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename, char **filetype, int *cms_function,
1171 XsaneFileChooserAction action, int show_extra_widgets, int enable_filters, int activate_filter)
1172 {
1173 int ok = 0;
1174 GtkWidget *xsane_filetype_option_menu;
1175 GtkWidget *xsane_cms_function_option_menu = xsane_cms_function_option_menu;
1176 gint result;
1177 const gchar *accept_text = NULL;
1178 const gchar *reject_text = NULL;
1179 GtkFileChooserAction chooser_action = GTK_FILE_CHOOSER_ACTION_OPEN;
1180 GtkResponseType accept_code;
1181 GtkResponseType reject_code;
1182 char buf[PATH_MAX];
1183
1184
1185 DBG(DBG_proc, "xsane_back_gtk_get_filename\n");
1186
1187 if (filechooser)
1188 {
1189 gdk_beep();
1190 return -1; /* cancel => do not allow to open more than one filechooser dialog */
1191 }
1192
1193 switch (action)
1194 {
1195 default:
1196 case XSANE_FILE_CHOOSER_ACTION_OPEN:
1197 chooser_action = GTK_FILE_CHOOSER_ACTION_OPEN;
1198 accept_text = GTK_STOCK_OPEN;
1199 accept_code = GTK_RESPONSE_ACCEPT;
1200 reject_text = GTK_STOCK_CANCEL;
1201 reject_code = GTK_RESPONSE_CANCEL;
1202 break;
1203
1204 case XSANE_FILE_CHOOSER_ACTION_SELECT_OPEN:
1205 chooser_action = GTK_FILE_CHOOSER_ACTION_OPEN;
1206 accept_text = GTK_STOCK_OK;
1207 accept_code = GTK_RESPONSE_ACCEPT;
1208 reject_text = GTK_STOCK_CANCEL;
1209 reject_code = GTK_RESPONSE_CANCEL;
1210 break;
1211
1212 case XSANE_FILE_CHOOSER_ACTION_SAVE:
1213 chooser_action = GTK_FILE_CHOOSER_ACTION_SAVE;
1214 accept_text = GTK_STOCK_SAVE;
1215 accept_code = GTK_RESPONSE_ACCEPT;
1216 reject_text = GTK_STOCK_CANCEL;
1217 reject_code = GTK_RESPONSE_CANCEL;
1218 break;
1219
1220 case XSANE_FILE_CHOOSER_ACTION_SELECT_SAVE:
1221 chooser_action = GTK_FILE_CHOOSER_ACTION_SAVE;
1222 accept_text = GTK_STOCK_OK;
1223 accept_code = GTK_RESPONSE_ACCEPT;
1224 reject_text = GTK_STOCK_CANCEL;
1225 reject_code = GTK_RESPONSE_CANCEL;
1226 break;
1227
1228 case XSANE_FILE_CHOOSER_ACTION_SELECT_FOLDER:
1229 chooser_action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1230 accept_text = GTK_STOCK_OK;
1231 accept_code = GTK_RESPONSE_ACCEPT;
1232 reject_text = GTK_STOCK_CANCEL;
1233 reject_code = GTK_RESPONSE_CANCEL;
1234 break;
1235
1236 case XSANE_FILE_CHOOSER_ACTION_SELECT_PROJECT:
1237 chooser_action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1238 accept_text = GTK_STOCK_OK;
1239 accept_code = GTK_RESPONSE_NO; /* when we would use ACCEPT, OK, YES or APPLY then the filechooser_dialog would create non existant directories */
1240 reject_text = GTK_STOCK_CANCEL;
1241 reject_code = GTK_RESPONSE_CANCEL;
1242 break;
1243 }
1244
1245 filechooser = gtk_file_chooser_dialog_new (label,
1246 NULL,
1247 chooser_action,
1248 reject_text, reject_code,
1249 accept_text, accept_code,
1250 NULL);
1251
1252 xsane_set_window_icon(filechooser, 0);
1253
1254 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(filechooser), TRUE);
1255
1256
1257 /* add paths to filechooser */
1258 if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL)
1259 {
1260 snprintf(buf, sizeof(buf)-2, "%s", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)));
1261 gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), buf, NULL);
1262 }
1263
1264 if (getcwd(buf, sizeof(buf)))
1265 {
1266 gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), buf, NULL);
1267 }
1268
1269
1270 if (enable_filters & XSANE_FILE_FILTER_ALL) /* filter: all files */
1271 {
1272 GtkFileFilter *filter;
1273
1274 filter = gtk_file_filter_new();
1275 gtk_file_filter_add_pattern(filter, "*");
1276
1277 gtk_file_filter_set_name(filter, FILE_FILTER_ALL_FILES);
1278 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
1279
1280 if (activate_filter == XSANE_FILE_FILTER_ALL)
1281 {
1282 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter);
1283 }
1284 }
1285
1286 if (enable_filters & XSANE_FILE_FILTER_DRC) /* filter: device rc */
1287 {
1288 GtkFileFilter *filter;
1289
1290 filter = gtk_file_filter_new();
1291 gtk_file_filter_add_pattern(filter, "*.[dD][rR][cC]");
1292
1293 gtk_file_filter_set_name(filter, FILE_FILTER_DRC);
1294 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
1295
1296 if (activate_filter == XSANE_FILE_FILTER_DRC)
1297 {
1298 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter);
1299 }
1300
1301 /* add path to filechooser */
1302 if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL)
1303 {
1304 gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), NULL);
1305 }
1306 }
1307
1308 if (enable_filters & XSANE_FILE_FILTER_ICM) /* filter: color management profiles */
1309 {
1310 GtkFileFilter *filter;
1311
1312 filter = gtk_file_filter_new();
1313 gtk_file_filter_add_pattern(filter, "*.[iI][cC][cCmM]");
1314
1315 gtk_file_filter_set_name(filter, FILE_FILTER_ICM);
1316 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
1317
1318 if (activate_filter == XSANE_FILE_FILTER_ICM)
1319 {
1320 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter);
1321 }
1322
1323 /* add path to filechooser */
1324 if (getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)) != NULL)
1325 {
1326 snprintf(buf, sizeof(buf)-2, "%s%c.color%cicc", getenv(STRINGIFY(ENVIRONMENT_HOME_DIR_NAME)), SLASH, SLASH);
1327 gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), buf, NULL);
1328 }
1329 gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(filechooser), "/usr/share/color/icc", NULL);
1330 }
1331
1332 if (enable_filters & XSANE_FILE_FILTER_IMAGES) /* filter: images */
1333 {
1334 GtkFileFilter *filter;
1335
1336 filter = gtk_file_filter_new();
1337 gtk_file_filter_add_pattern(filter, "*.[jJ][pP][gG]");
1338 gtk_file_filter_add_pattern(filter, "*.[jJ][pP][eE][gG]");
1339 gtk_file_filter_add_pattern(filter, "*.[pP][nN][gG]");
1340 gtk_file_filter_add_pattern(filter, "*.[tT][iI][fF]");
1341 gtk_file_filter_add_pattern(filter, "*.[tT][iI][fF][fF]");
1342 gtk_file_filter_add_pattern(filter, "*.[pP][sS]");
1343 gtk_file_filter_add_pattern(filter, "*.[pP][dD][fF]");
1344 gtk_file_filter_add_pattern(filter, "*.[pP][nN][mM]");
1345 gtk_file_filter_add_pattern(filter, "*.[pP][bB][mM]");
1346 gtk_file_filter_add_pattern(filter, "*.[pP][gG][mM]");
1347 gtk_file_filter_add_pattern(filter, "*.[pP][pP][mM]");
1348
1349 gtk_file_filter_set_name(filter, FILE_FILTER_IMAGES);
1350 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
1351
1352 if (activate_filter == XSANE_FILE_FILTER_IMAGES)
1353 {
1354 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter);
1355 }
1356 }
1357
1358 if (enable_filters & XSANE_FILE_FILTER_BATCHLIST) /* filter: color management profiles */
1359 {
1360 GtkFileFilter *filter;
1361
1362 filter = gtk_file_filter_new();
1363 gtk_file_filter_add_pattern(filter, "*.[xX][bV][lL]");
1364
1365 gtk_file_filter_set_name(filter, FILE_FILTER_XBL);
1366 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);
1367
1368 if (activate_filter == XSANE_FILE_FILTER_BATCHLIST)
1369 {
1370 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(filechooser), filter);
1371 }
1372 }
1373
1374 /* set default filename */
1375 if (default_name) /* select file */
1376 {
1377 const char *basename = default_name;
1378 char *path;
1379 int pos;
1380
1381 DBG(DBG_info, "xsane_back_gtk_get_filename: default_name =%s\n", default_name);
1382
1383 path = strdup(default_name);
1384 for (pos = strlen(path)-1; pos > 0; pos--)
1385 {
1386 if (path[pos] == '/')
1387 {
1388 path[pos]=0;
1389
1390 basename = path+pos+1;
1391 break;
1392 }
1393 }
1394
1395 if (pos)
1396 {
1397 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), path);
1398 }
1399
1400 if ((action == XSANE_FILE_CHOOSER_ACTION_SAVE) || (action == XSANE_FILE_CHOOSER_ACTION_SELECT_SAVE))
1401 {
1402 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filechooser), (char *) basename);
1403 }
1404 else
1405 {
1406 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(filechooser), (char *) default_name);
1407 }
1408 }
1409
1410
1411 /* add filetype menu */
1412
1413 if (show_extra_widgets)
1414 {
1415 GtkWidget *vbox;
1416 GtkWidget *hbox;
1417 GtkWidget *label;
1418
1419 vbox = gtk_vbox_new(FALSE, 15);
1420 gtk_widget_show(vbox);
1421
1422 if (show_extra_widgets & XSANE_GET_FILENAME_SHOW_FILETYPE)
1423 {
1424 DBG(DBG_info, "xsane_back_gtk_get_filename: showing filetype menu\n");
1425
1426 if (filechooser_filetype)
1427 {
1428 free(filechooser_filetype);
1429 }
1430
1431 if ((filetype) && (*filetype))
1432 {
1433 filechooser_filetype = strdup(*filetype);
1434 }
1435 else
1436 {
1437 filechooser_filetype = NULL;
1438 }
1439
1440 hbox = gtk_hbox_new(FALSE, 2);
1441 gtk_widget_show(hbox);
1442 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1443
1444 label = gtk_label_new(TEXT_FILETYPE);
1445 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1446 gtk_widget_show(label);
1447
1448 xsane_filetype_option_menu = xsane_back_gtk_filetype_menu_new(filechooser_filetype, (GtkSignalFunc) xsane_back_gtk_filetype2_callback);
1449 gtk_box_pack_start(GTK_BOX(hbox), xsane_filetype_option_menu, TRUE, TRUE, 2);
1450 gtk_widget_show(xsane_filetype_option_menu);
1451 }
1452
1453 #ifdef HAVE_LIBLCMS
1454 if ((cms_function) && (show_extra_widgets & XSANE_GET_FILENAME_SHOW_CMS_FUNCTION))
1455 {
1456 hbox = gtk_hbox_new(FALSE, 2);
1457 gtk_widget_show(hbox);
1458 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1459
1460 label = gtk_label_new(TEXT_CMS_FUNCTION);
1461 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1462 gtk_widget_show(label);
1463
1464 xsane_cms_function_option_menu = xsane_back_gtk_cms_function_menu_new(*cms_function, NULL);
1465 gtk_box_pack_start(GTK_BOX(hbox), xsane_cms_function_option_menu, TRUE, TRUE, 2);
1466 gtk_widget_show(xsane_cms_function_option_menu);
1467 }
1468 #endif
1469
1470 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(filechooser), vbox);
1471 }
1472
1473
1474 gtk_widget_show(filechooser);
1475
1476 result = gtk_dialog_run(GTK_DIALOG(filechooser));
1477
1478 DBG(DBG_info, "xsane_back_gtk_get_filename: gtk_dialog_run() returned with result=%d\n", result);
1479
1480 if (result == accept_code)
1481 {
1482 char *chooser_filename;
1483
1484 if ((filetype) && (*filetype))
1485 {
1486 free(*filetype);
1487 *filetype = NULL;
1488 }
1489
1490 if (filechooser_filetype)
1491 {
1492 if (filetype)
1493 {
1494 *filetype = strdup(filechooser_filetype);
1495 }
1496 }
1497
1498 #ifdef HAVE_LIBLCMS
1499 if ((cms_function) && (show_extra_widgets & XSANE_GET_FILENAME_SHOW_CMS_FUNCTION))
1500 {
1501 *cms_function = gtk_option_menu_get_history(GTK_OPTION_MENU(xsane_cms_function_option_menu));
1502
1503 DBG(DBG_info, "selected cms_function = %d\n", *cms_function);
1504 }
1505 #endif
1506
1507 chooser_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
1508 strncpy(filename, chooser_filename, max_len - 1);
1509 g_free(chooser_filename);
1510
1511 filename[max_len - 1] = '\0';
1512
1513 ok = TRUE;
1514 }
1515
1516 gtk_widget_destroy(filechooser);
1517 filechooser = NULL;
1518
1519 return ok ? 0 : -1;
1520 }
1521
1522 #else
1523
1524 GtkWidget *fileselection;
1525 char *fileselection_filetype = NULL;
1526
1527 /* ----------------------------------------------------------------------------------------------------------------- */
1528
xsane_back_gtk_get_filename_button_clicked(GtkWidget * w,gpointer data)1529 static void xsane_back_gtk_get_filename_button_clicked(GtkWidget *w, gpointer data)
1530 {
1531 int *clicked = data;
1532
1533 DBG(DBG_proc, "xsane_back_gtk_get_filename_button_clicked\n");
1534 *clicked = 1;
1535 }
1536
1537 /* ----------------------------------------------------------------------------------------------------------------- */
1538
xsane_back_gtk_filetype_callback(GtkWidget * widget,gpointer data)1539 static void xsane_back_gtk_filetype_callback(GtkWidget *widget, gpointer data)
1540 {
1541 char *extension, *filename;
1542 char buffer[PATH_MAX];
1543 char *new_filetype = (char *) data;
1544
1545 DBG(DBG_proc, "xsane_filetype_callback\n");
1546
1547 filename = strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection)));
1548
1549 if ((new_filetype) && (*new_filetype))
1550 {
1551 extension = strrchr(filename, '.');
1552
1553 if ((extension) && (extension != filename))
1554 {
1555 if ( (!strcasecmp(extension, ".pnm")) || (!strcasecmp(extension, ".raw"))
1556 || (!strcasecmp(extension, ".png")) || (!strcasecmp(extension, ".ps"))
1557 || (!strcasecmp(extension, ".pdf")) || (!strcasecmp(extension, ".rgba"))
1558 || (!strcasecmp(extension, ".tiff")) || (!strcasecmp(extension, ".tif"))
1559 || (!strcasecmp(extension, ".text")) || (!strcasecmp(extension, ".txt"))
1560 || (!strcasecmp(extension, ".jpg")) || (!strcasecmp(extension, ".jpeg"))
1561 ) /* remove filetype extension */
1562 {
1563 *extension = 0; /* remove extension */
1564 }
1565 }
1566 snprintf(buffer, sizeof(buffer), "%s%s", filename, new_filetype);
1567 free(filename);
1568 filename = strdup(buffer);
1569 }
1570
1571 if (fileselection_filetype)
1572 {
1573 free(fileselection_filetype);
1574 fileselection_filetype = NULL;
1575 }
1576
1577 if (data)
1578 {
1579 fileselection_filetype = strdup(new_filetype);
1580 }
1581
1582 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection), filename);
1583
1584 free(filename);
1585 }
1586
1587 /* ---------------------------------------------------------------------------------------------------------------------- */
1588
xsane_back_gtk_get_filename(const char * label,const char * default_name,size_t max_len,char * filename,char ** filetype,int * cms_function,XsaneFileChooserAction action,int show_filetype_menu,int enable_filters,int activate_filter)1589 int xsane_back_gtk_get_filename(const char *label, const char *default_name, size_t max_len, char *filename, char **filetype, int *cms_function,
1590 XsaneFileChooserAction action, int show_filetype_menu, int enable_filters, int activate_filter)
1591 {
1592 int cancel = 0, ok = 0, destroy = 0;
1593 GtkAccelGroup *accelerator_group;
1594 GtkWidget *xsane_filetype_option_menu;
1595 int show_fileopts = 0;
1596 int select_directory = 0;
1597
1598 if (action == XSANE_FILE_CHOOSER_ACTION_SELECT_FOLDER)
1599 {
1600 select_directory = TRUE;
1601 }
1602 else
1603 {
1604 show_fileopts = TRUE;
1605 }
1606
1607 DBG(DBG_proc, "xsane_back_gtk_get_filename\n");
1608
1609 if (fileselection)
1610 {
1611 gdk_beep();
1612 return -1; /* cancel => do not allow to open more than one fileselection dialog */
1613 }
1614
1615 fileselection = gtk_file_selection_new((char *) label);
1616 accelerator_group = gtk_accel_group_new();
1617 gtk_window_add_accel_group(GTK_WINDOW(fileselection), accelerator_group);
1618
1619 g_signal_connect(GTK_OBJECT(fileselection), "destroy", GTK_SIGNAL_FUNC(xsane_back_gtk_get_filename_button_clicked), &destroy);
1620
1621 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fileselection)->cancel_button), "clicked", (GtkSignalFunc) xsane_back_gtk_get_filename_button_clicked, &cancel);
1622 gtk_widget_add_accelerator(GTK_FILE_SELECTION(fileselection)->cancel_button, "clicked",
1623 accelerator_group, GDK_Escape, 0, DEF_GTK_ACCEL_LOCKED);
1624
1625 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fileselection)->ok_button), "clicked", (GtkSignalFunc) xsane_back_gtk_get_filename_button_clicked, &ok);
1626
1627 if (select_directory)
1628 {
1629 DBG(DBG_info, "xsane_back_gtk_get_filename: select directory\n");
1630 gtk_widget_hide(GTK_FILE_SELECTION(fileselection)->file_list->parent);
1631 gtk_widget_hide(GTK_FILE_SELECTION(fileselection)->fileop_del_file);
1632 gtk_widget_hide(GTK_FILE_SELECTION(fileselection)->fileop_ren_file);
1633 gtk_widget_hide(GTK_FILE_SELECTION(fileselection)->selection_entry);
1634
1635 gtk_widget_set_size_request(GTK_FILE_SELECTION(fileselection)->dir_list, 280, 230);
1636
1637 if (default_name) /* add "/." to end of directory name so that the gtkfilesel* behaves correct */
1638 {
1639 char directory_name[PATH_MAX];
1640
1641 snprintf(directory_name, sizeof(directory_name), "%s%c", default_name, SLASH);
1642 DBG(DBG_info, "xsane_back_gtk_get_filename: directory_name =%s\n", directory_name);
1643 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection), (char *) directory_name);
1644 }
1645 }
1646 else if (default_name) /* select file */
1647 {
1648 DBG(DBG_info, "xsane_back_gtk_get_filename: default_name =%s\n", default_name);
1649 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fileselection), (char *) default_name);
1650 }
1651
1652 if (show_fileopts)
1653 {
1654 DBG(DBG_info, "xsane_back_gtk_get_filename: showing file-options\n");
1655 gtk_file_selection_show_fileop_buttons(GTK_FILE_SELECTION(fileselection));
1656 }
1657 else
1658 {
1659 DBG(DBG_info, "xsane_back_gtk_get_filename: hiding file-options\n");
1660 gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(fileselection));
1661 }
1662
1663 if (show_filetype_menu)
1664 {
1665 GtkWidget *hbox;
1666 GtkWidget *vbox;
1667 GtkWidget *label;
1668
1669 DBG(DBG_info, "xsane_back_gtk_get_filename: showing filetype menu\n");
1670
1671 if (fileselection_filetype)
1672 {
1673 free(fileselection_filetype);
1674 }
1675
1676 if ((filetype) && (*filetype))
1677 {
1678 fileselection_filetype = strdup(*filetype);
1679 }
1680 else
1681 {
1682 fileselection_filetype = NULL;
1683 }
1684
1685 vbox = gtk_vbox_new(FALSE, 2);
1686 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(fileselection)->action_area), vbox, TRUE, TRUE, 0);
1687 gtk_widget_show(vbox);
1688
1689 hbox = gtk_hbox_new(FALSE, 2);
1690 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1691 gtk_widget_show(hbox);
1692
1693 label = gtk_label_new(TEXT_FILETYPE);
1694 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1695 gtk_widget_show(label);
1696
1697 xsane_filetype_option_menu = xsane_back_gtk_filetype_menu_new(fileselection_filetype, (GtkSignalFunc) xsane_back_gtk_filetype_callback);
1698 gtk_box_pack_start(GTK_BOX(hbox), xsane_filetype_option_menu, TRUE, TRUE, 2);
1699 gtk_widget_show(xsane_filetype_option_menu);
1700 }
1701
1702 gtk_widget_show(fileselection);
1703
1704 DBG(DBG_info, "xsane_back_gtk_get_filename: waiting for user action\n");
1705 while (!cancel && !ok && !destroy)
1706 {
1707 gtk_main_iteration();
1708 }
1709
1710 if (ok)
1711 {
1712 size_t len, cwd_len;
1713 char *cwd;
1714
1715 DBG(DBG_info, "ok button pressed\n");
1716
1717 if ((filetype) && (*filetype))
1718 {
1719 free(*filetype);
1720 *filetype = NULL;
1721 }
1722
1723 if (fileselection_filetype)
1724 {
1725 if (filetype)
1726 {
1727 *filetype = strdup(fileselection_filetype);
1728 }
1729
1730 free(fileselection_filetype);
1731 fileselection_filetype = NULL;
1732 }
1733
1734 strncpy(filename, gtk_file_selection_get_filename(GTK_FILE_SELECTION(fileselection)), max_len - 1);
1735
1736 #ifndef HAVE_GTK2
1737 /* in gtk1 we have to remove the text that is defined in the selection entry to get a proper behaviour */
1738 if (select_directory)
1739 {
1740 *(filename+strlen(filename)-strlen(gtk_entry_get_text(GTK_ENTRY(GTK_FILE_SELECTION(fileselection)->selection_entry)))) = '\0';
1741 }
1742 #endif
1743
1744 filename[max_len - 1] = '\0';
1745
1746 len = strlen(filename);
1747
1748 cwd = alloca(len + 2); /* alloca => memory is freed on return */
1749 getcwd(cwd, len + 1);
1750 cwd_len = strlen(cwd);
1751 cwd[cwd_len++] = '/';
1752 cwd[cwd_len] = '\0';
1753
1754 DBG(DBG_info, "xsane_back_gtk_get_filename: full path filename = %s\n", filename);
1755 }
1756
1757 if (!destroy)
1758 {
1759 gtk_widget_destroy(fileselection);
1760 }
1761
1762 fileselection = NULL;
1763
1764 return ok ? 0 : -1;
1765 }
1766 #endif
1767
1768 /* ----------------------------------------------------------------------------------------------------------------- */
1769
xsane_back_gtk_autobutton_update(GtkWidget * widget,DialogElement * elem)1770 static gint xsane_back_gtk_autobutton_update(GtkWidget *widget, DialogElement *elem)
1771 {
1772 int opt_num = elem - xsane.element;
1773 const SANE_Option_Descriptor *opt;
1774 SANE_Status status;
1775 SANE_Word val;
1776 char buf[TEXTBUFSIZE];
1777
1778 DBG(DBG_proc, "xsane_back_gtk_autobutton_update\n");
1779
1780 opt = xsane_get_option_descriptor(xsane.dev, opt_num);
1781 if (GTK_TOGGLE_BUTTON(widget)->active)
1782 {
1783 xsane_back_gtk_set_option(opt_num, 0, SANE_ACTION_SET_AUTO);
1784
1785 gtk_widget_set_sensitive(elem->widget, FALSE);
1786
1787 if (elem->widget2)
1788 {
1789 gtk_widget_set_sensitive(elem->widget2, FALSE);
1790 }
1791 }
1792 else
1793 {
1794 gtk_widget_set_sensitive(elem->widget, TRUE);
1795
1796 if (elem->widget2)
1797 {
1798 gtk_widget_set_sensitive(elem->widget2, TRUE);
1799 }
1800
1801 status = xsane_control_option(xsane.dev, opt_num, SANE_ACTION_GET_VALUE, &val, 0);
1802 if (status != SANE_STATUS_GOOD)
1803 {
1804 snprintf(buf, sizeof(buf), "%s %s: %s.", ERR_GET_OPTION, opt->name, XSANE_STRSTATUS(status));
1805 xsane_back_gtk_error(buf, FALSE);
1806 }
1807 xsane_back_gtk_set_option(opt_num, &val, SANE_ACTION_SET_VALUE);
1808 }
1809 return FALSE;
1810 }
1811
1812 /* ----------------------------------------------------------------------------------------------------------------- */
1813
xsane_back_gtk_autobutton_new(GtkWidget * parent,DialogElement * elem,GtkTooltips * tooltips)1814 static void xsane_back_gtk_autobutton_new(GtkWidget *parent, DialogElement *elem,
1815 GtkTooltips *tooltips)
1816 {
1817 GtkWidget *button;
1818
1819 DBG(DBG_proc, "xsane_back_gtk_autobutton_new\n");
1820
1821 button = gtk_check_button_new();
1822 gtk_container_set_border_width(GTK_CONTAINER(button), 0);
1823 gtk_widget_set_size_request(button, 20, 20);
1824 g_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_back_gtk_autobutton_update, elem);
1825 xsane_back_gtk_set_tooltip(tooltips, button, DESC_AUTOMATIC);
1826
1827 gtk_box_pack_end(GTK_BOX(parent), button, FALSE, FALSE, 2);
1828 gtk_widget_show(button);
1829 }
1830
1831 /* ----------------------------------------------------------------------------------------------------------------- */
1832
xsane_back_gtk_button_update(GtkWidget * widget,DialogElement * elem)1833 static gint xsane_back_gtk_button_update(GtkWidget * widget, DialogElement * elem)
1834 {
1835 int opt_num = elem - xsane.element;
1836 const SANE_Option_Descriptor *opt;
1837 SANE_Word val = SANE_FALSE;
1838
1839 DBG(DBG_proc, "xsane_back_gtk_button_update\n");
1840
1841 opt = xsane_get_option_descriptor(xsane.dev, opt_num);
1842 if (GTK_TOGGLE_BUTTON(widget)->active)
1843 {
1844 val = SANE_TRUE;
1845 }
1846 xsane_back_gtk_set_option(opt_num, &val, SANE_ACTION_SET_VALUE);
1847
1848 return FALSE;
1849 }
1850
1851 /* ----------------------------------------------------------------------------------------------------------------- */
1852
xsane_back_gtk_button_new(GtkWidget * parent,const char * name,SANE_Word val,DialogElement * elem,GtkTooltips * tooltips,const char * desc,SANE_Int settable)1853 void xsane_back_gtk_button_new(GtkWidget * parent, const char *name, SANE_Word val,
1854 DialogElement * elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable)
1855 {
1856 GtkWidget *button;
1857
1858 DBG(DBG_proc, "xsane_back_gtk_button_new\n");
1859
1860 button = gtk_check_button_new_with_label((char *) name);
1861 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), val);
1862 g_signal_connect(GTK_OBJECT(button), "toggled", (GtkSignalFunc) xsane_back_gtk_button_update, elem);
1863 gtk_box_pack_start(GTK_BOX(parent), button, FALSE, TRUE, 0);
1864 gtk_widget_show(button);
1865 xsane_back_gtk_set_tooltip(tooltips, button, desc);
1866
1867 gtk_widget_set_sensitive(button, settable);
1868
1869 elem->widget = button;
1870 }
1871
1872 /* ----------------------------------------------------------------------------------------------------------------- */
1873
1874 /* called from xsane_back_gtk_value_new and xsane_back_gtk_range_new */
xsane_back_gtk_value_update(GtkAdjustment * adj_data,DialogElement * elem)1875 static void xsane_back_gtk_value_update(GtkAdjustment *adj_data, DialogElement *elem)
1876 {
1877 const SANE_Option_Descriptor *opt;
1878 SANE_Word val, new_val;
1879 int opt_num;
1880 double d;
1881
1882 DBG(DBG_proc, "xsane_back_gtk_value_update\n");
1883
1884 opt_num = elem - xsane.element;
1885 opt = xsane_get_option_descriptor(xsane.dev, opt_num);
1886 switch(opt->type)
1887 {
1888 case SANE_TYPE_INT:
1889 val = adj_data->value; /* OLD: + 0.5 but this mad problems with negative values */
1890 break;
1891
1892 case SANE_TYPE_FIXED:
1893 d = adj_data->value;
1894 if (opt->unit == SANE_UNIT_MM)
1895 {
1896 d *= preferences.length_unit;
1897 }
1898 val = SANE_FIX(d);
1899 break;
1900
1901 default:
1902 DBG(DBG_error, "xsane_back_gtk_value_update: %s %d\n", ERR_UNKNOWN_TYPE, opt->type);
1903 return;
1904 }
1905
1906 xsane_back_gtk_set_option(opt_num, &val, SANE_ACTION_SET_VALUE);
1907 xsane_control_option(xsane.dev, opt_num, SANE_ACTION_GET_VALUE, &new_val, 0);
1908 #if 1
1909 val = new_val;
1910 switch(opt->type)
1911 {
1912 case SANE_TYPE_INT:
1913 if (new_val != val)
1914 {
1915 adj_data->value = val;
1916 g_signal_emit_by_name(GTK_OBJECT(adj_data), "value_changed");
1917 }
1918 break;
1919
1920 case SANE_TYPE_FIXED:
1921 if (abs(new_val - val) > 1) /* tolarate 1/65536 error, instead of: if (new_val != val) */
1922 {
1923 d = SANE_UNFIX(val);
1924 if (opt->unit == SANE_UNIT_MM)
1925 {
1926 d /= preferences.length_unit;
1927 }
1928 adj_data->value = d;
1929 g_signal_emit_by_name(GTK_OBJECT(adj_data), "value_changed");
1930 }
1931 break;
1932
1933 default:
1934 break;
1935 }
1936 #endif
1937 #if 0
1938 if (abs(new_val - val) > 1) /* tolarate 1/65536 error, instead of: if (new_val != val) */
1939 {
1940 val = new_val;
1941 switch(opt->type)
1942 {
1943 case SANE_TYPE_INT:
1944 adj_data->value = val;
1945 break;
1946
1947 case SANE_TYPE_FIXED:
1948 d = SANE_UNFIX(val);
1949 if (opt->unit == SANE_UNIT_MM)
1950 {
1951 d /= preferences.length_unit;
1952 }
1953 adj_data->value = d;
1954 break;
1955
1956 default:
1957 break;
1958 }
1959 g_signal_emit_by_name(GTK_OBJECT(adj_data), "value_changed");
1960 }
1961 #endif
1962
1963 return; /* value didn't change */
1964 }
1965
1966 /* ----------------------------------------------------------------------------------------------------------------- */
1967
xsane_back_gtk_range_display_value_right_callback(GtkAdjustment * adjust,gpointer data)1968 static void xsane_back_gtk_range_display_value_right_callback(GtkAdjustment *adjust, gpointer data)
1969 {
1970 gchar buf[TEXTBUFSIZE];
1971 int digits = (int) data;
1972 GtkLabel *label;
1973
1974 snprintf(buf, sizeof(buf), "%1.*f", digits, adjust->value);
1975 label = (GtkLabel *) gtk_object_get_data(GTK_OBJECT(adjust), "value-label");
1976 gtk_label_set_text(label, buf);
1977 }
1978 /* ----------------------------------------------------------------------------------------------------------------- */
1979
xsane_back_gtk_range_new(GtkWidget * parent,const char * name,gfloat val,gfloat min,gfloat max,gfloat quant,int automatic,DialogElement * elem,GtkTooltips * tooltips,const char * desc,SANE_Int settable)1980 void xsane_back_gtk_range_new(GtkWidget *parent, const char *name, gfloat val,
1981 gfloat min, gfloat max, gfloat quant, int automatic,
1982 DialogElement *elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable)
1983 {
1984 GtkWidget *hbox, *label, *slider = NULL, *spinbutton, *value_label;
1985 int digits;
1986
1987 DBG(DBG_proc, "xsane_back_gtk_range_new(%s)\n", name);
1988
1989 if (quant - (int) quant == 0.0)
1990 {
1991 digits = 0;
1992 }
1993 else
1994 {
1995 digits = (int) (log10(1/quant)+0.8); /* set number of digits in dependance of quantization */
1996 }
1997
1998 if (digits < 0)
1999 {
2000 digits = 0;
2001 }
2002
2003 hbox = gtk_hbox_new(FALSE, 2);
2004 gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
2005 gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
2006
2007 label = gtk_label_new((char *) name);
2008 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
2009
2010 elem->data = gtk_adjustment_new(val, min, max, quant, quant*10, 0);
2011
2012 /* value label */
2013 if (preferences.show_range_mode & 8)
2014 {
2015 value_label = gtk_label_new("");
2016 gtk_widget_set_size_request(value_label, 45, -1);
2017 gtk_box_pack_end(GTK_BOX(hbox), value_label, FALSE, FALSE, 1);
2018
2019 g_signal_connect(elem->data, "value_changed", (GtkSignalFunc) xsane_back_gtk_range_display_value_right_callback, (void *) digits);
2020 gtk_object_set_data(GTK_OBJECT(elem->data), "value-label", value_label);
2021 g_signal_emit_by_name(GTK_OBJECT(elem->data), "value_changed"); /* update value */
2022 gtk_widget_show(value_label);
2023 gtk_widget_set_sensitive(value_label, settable);
2024 }
2025
2026 /* spinbutton */
2027 if (preferences.show_range_mode & 4)
2028 {
2029 #ifndef HAVE_GTK2
2030 if (digits > 5)
2031 {
2032 digits = 5;
2033 }
2034 #endif
2035 spinbutton = gtk_spin_button_new(GTK_ADJUSTMENT(elem->data), 0, digits);
2036
2037 if (preferences.show_range_mode & 3) /* slider also visible */
2038 {
2039 gtk_widget_set_size_request(spinbutton, 70, -1);
2040 }
2041 else /* slider not visible */
2042 {
2043 gtk_widget_set_size_request(spinbutton, 100, -1);
2044 }
2045
2046 xsane_back_gtk_set_tooltip(xsane.tooltips, spinbutton, desc);
2047 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), FALSE);
2048 gtk_box_pack_end(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 5); /* make spinbutton not sizeable */
2049 gtk_widget_show(spinbutton);
2050 gtk_widget_set_sensitive(spinbutton, settable);
2051 elem->widget = spinbutton;
2052 }
2053
2054 /* slider */
2055 if (preferences.show_range_mode & 3)
2056 {
2057 if (preferences.show_range_mode & 1) /* bit 0 (val 1) : scale */
2058 {
2059 slider = gtk_hscale_new(GTK_ADJUSTMENT(elem->data));
2060 gtk_scale_set_draw_value(GTK_SCALE(slider), FALSE);
2061 }
2062 else /* bit 1 (val 2) : scrollbar */
2063 {
2064 slider = gtk_hscrollbar_new(GTK_ADJUSTMENT(elem->data));
2065 }
2066 xsane_back_gtk_set_tooltip(xsane.tooltips, slider, desc);
2067 gtk_widget_set_size_request(slider, 140, -1);
2068 /* GTK_UPDATE_CONTINUOUS, GTK_UPDATE_DISCONTINUOUS, GTK_UPDATE_DELAYED */
2069 gtk_range_set_update_policy(GTK_RANGE(slider), preferences.gtk_update_policy);
2070 gtk_box_pack_end(GTK_BOX(hbox), slider, FALSE, FALSE, 5); /* make slider not sizeable */
2071 gtk_widget_show(slider);
2072 gtk_widget_set_sensitive(slider, settable);
2073 }
2074
2075 if (automatic)
2076 {
2077 xsane_back_gtk_autobutton_new(hbox, elem, tooltips);
2078 }
2079
2080 g_signal_connect(elem->data, "value_changed", (GtkSignalFunc) xsane_back_gtk_value_update, elem);
2081
2082 gtk_widget_show(label);
2083 gtk_widget_show(hbox);
2084
2085 if (elem->widget)
2086 {
2087 elem->widget2 = slider; /* widget is used by spinbutton */
2088 }
2089 else
2090 {
2091 elem->widget = slider; /* we do not have a spinbutton */
2092 }
2093 }
2094
2095 /* ----------------------------------------------------------------------------------------------------------------- */
2096
xsane_back_gtk_value_new(GtkWidget * parent,const char * name,gfloat val,gfloat quant,int automatic,DialogElement * elem,GtkTooltips * tooltips,const char * desc,SANE_Int settable)2097 void xsane_back_gtk_value_new(GtkWidget *parent, const char *name, gfloat val,
2098 gfloat quant, int automatic,
2099 DialogElement *elem, GtkTooltips *tooltips, const char *desc, SANE_Int settable)
2100 {
2101 GtkWidget *hbox, *label, *spinbutton;
2102 int digits;
2103
2104 DBG(DBG_proc, "xsane_back_gtk_value_new(%s)\n", name);
2105
2106 if (quant - (int) quant == 0.0)
2107 {
2108 digits = 0;
2109 }
2110 else
2111 {
2112 digits = (int) (log10(1/quant)+0.8); /* set number of digits in dependance of quantization */
2113 }
2114
2115 if (digits < 0)
2116 {
2117 digits = 0;
2118 }
2119
2120 hbox = gtk_hbox_new(FALSE, 2);
2121 gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
2122 gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
2123
2124 label = gtk_label_new((char *) name);
2125 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
2126
2127 elem->data = gtk_adjustment_new(val, -1e29, 1e29, 1, 10, 0);
2128
2129 /* spinbutton */
2130 #ifndef HAVE_GTK2
2131 if (digits > 5)
2132 {
2133 digits = 5;
2134 }
2135 #endif
2136 spinbutton = gtk_spin_button_new(GTK_ADJUSTMENT(elem->data), 0, digits);
2137
2138 if (preferences.show_range_mode & 3) /* sliders are visible */
2139 {
2140 gtk_widget_set_size_request(spinbutton, 70, -1);
2141 }
2142 else /* sliders not visible */
2143 {
2144 gtk_widget_set_size_request(spinbutton, 100, -1);
2145 }
2146
2147 xsane_back_gtk_set_tooltip(xsane.tooltips, spinbutton, desc);
2148 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton), FALSE);
2149 gtk_box_pack_end(GTK_BOX(hbox), spinbutton, FALSE, FALSE, 5); /* make spinbutton not sizeable */
2150 gtk_widget_show(spinbutton);
2151 gtk_widget_set_sensitive(spinbutton, settable);
2152 elem->widget = spinbutton;
2153
2154 if (automatic)
2155 {
2156 xsane_back_gtk_autobutton_new(hbox, elem, tooltips);
2157 }
2158
2159 g_signal_connect(elem->data, "value_changed", (GtkSignalFunc) xsane_back_gtk_value_update, elem);
2160
2161 gtk_widget_show(label);
2162 gtk_widget_show(hbox);
2163 }
2164
2165 /* ----------------------------------------------------------------------------------------------------------------- */
2166
xsane_back_gtk_push_button_callback(GtkWidget * widget,gpointer data)2167 void xsane_back_gtk_push_button_callback(GtkWidget * widget, gpointer data)
2168 {
2169 DialogElement *elem = data;
2170 int opt_num;
2171
2172 DBG(DBG_proc, "xsane_back_gtk_push_button_callback\n");
2173
2174 opt_num = elem - xsane.element;
2175 xsane_back_gtk_set_option(opt_num, 0, SANE_ACTION_SET_VALUE);
2176 }
2177
2178 /* ----------------------------------------------------------------------------------------------------------------- */
2179
xsane_back_gtk_option_menu_lookup(MenuItem menu_items[],const char * string)2180 static int xsane_back_gtk_option_menu_lookup(MenuItem menu_items[], const char *string)
2181 {
2182 int i;
2183
2184 DBG(DBG_proc, "xsane_back_gtk_option_menu_lookup\n");
2185
2186 for (i = 0; (menu_items[i].label) && strcmp(menu_items[i].label, string) != 0; ++i);
2187
2188 return i;
2189 }
2190
2191 /* ----------------------------------------------------------------------------------------------------------------- */
2192
xsane_back_gtk_option_menu_callback(GtkWidget * widget,gpointer data)2193 static void xsane_back_gtk_option_menu_callback(GtkWidget * widget, gpointer data)
2194 {
2195 MenuItem *menu_item = data;
2196 DialogElement *elem = menu_item->elem;
2197 const SANE_Option_Descriptor *opt;
2198 int opt_num;
2199 double dval;
2200 SANE_Word val;
2201 void *valp = &val;
2202
2203 DBG(DBG_proc, "xsane_back_gtk_option_menu_callback\n");
2204
2205 opt_num = elem - xsane.element;
2206 opt = xsane_get_option_descriptor(xsane.dev, opt_num);
2207 switch(opt->type)
2208 {
2209 case SANE_TYPE_INT:
2210 sscanf(menu_item->label, "%d", &val);
2211 break;
2212
2213 case SANE_TYPE_FIXED:
2214 sscanf(menu_item->label, "%lg", &dval);
2215 val = SANE_FIX(dval);
2216 break;
2217
2218 case SANE_TYPE_STRING:
2219 valp = menu_item->label;
2220 break;
2221
2222 default:
2223 DBG(DBG_error, "xsane_back_gtk_option_menu_callback: %s %d\n", ERR_UNKNOWN_TYPE, opt->type);
2224 break;
2225 }
2226 xsane_back_gtk_set_option(opt_num, valp, SANE_ACTION_SET_VALUE);
2227 }
2228
2229 /* ----------------------------------------------------------------------------------------------------------------- */
2230
xsane_back_gtk_option_menu_new(GtkWidget * parent,const char * name,char * str_list[],const char * val,DialogElement * elem,GtkTooltips * tooltips,const char * desc,SANE_Int settable)2231 void xsane_back_gtk_option_menu_new(GtkWidget *parent, const char *name, char *str_list[],
2232 const char *val, DialogElement *elem,
2233 GtkTooltips *tooltips, const char *desc, SANE_Int settable)
2234 {
2235 GtkWidget *hbox, *label, *option_menu, *menu, *item;
2236 MenuItem *menu_items;
2237 int i, num_items;
2238
2239 DBG(DBG_proc, "xsane_back_gtk_option_menu_new(%s)\n", name);
2240
2241 hbox = gtk_hbox_new(FALSE, 2);
2242 gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
2243 gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
2244
2245 label = gtk_label_new((char *) name);
2246 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
2247
2248 for (num_items = 0; str_list[num_items]; ++num_items)
2249 {
2250 }
2251
2252 menu_items = malloc((num_items + 1) * sizeof(menu_items[0]));
2253
2254 menu = gtk_menu_new();
2255 for (i = 0; i < num_items; ++i)
2256 {
2257 item = gtk_menu_item_new_with_label(_BGT(str_list[i]));
2258 gtk_container_add(GTK_CONTAINER(menu), item);
2259 g_signal_connect(GTK_OBJECT(item), "activate", (GtkSignalFunc) xsane_back_gtk_option_menu_callback, menu_items + i);
2260
2261 gtk_widget_show(item);
2262
2263 menu_items[i].label = str_list[i];
2264 menu_items[i].elem = elem;
2265 menu_items[i].index = i;
2266 }
2267
2268 /* add empty element as end of list marker */
2269 menu_items[i].label = NULL;
2270 menu_items[i].elem = NULL;
2271 menu_items[i].index = 0;
2272
2273 option_menu = gtk_option_menu_new();
2274 gtk_box_pack_end(GTK_BOX(hbox), option_menu, FALSE, FALSE, 2);
2275 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
2276 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), xsane_back_gtk_option_menu_lookup(menu_items, val));
2277 xsane_back_gtk_set_tooltip(tooltips, option_menu, desc);
2278
2279 gtk_widget_show(label);
2280 gtk_widget_show(option_menu);
2281 gtk_widget_show(hbox);
2282
2283 gtk_widget_set_sensitive(option_menu, settable);
2284
2285 elem->widget = option_menu;
2286 elem->menu_size = num_items;
2287 elem->menu = menu_items;
2288 }
2289
2290 /* ----------------------------------------------------------------------------------------------------------------- */
2291
xsane_back_gtk_text_entry_callback(GtkWidget * w,gpointer data)2292 static void xsane_back_gtk_text_entry_callback(GtkWidget *w, gpointer data)
2293 {
2294 DialogElement *elem = data;
2295 const SANE_Option_Descriptor *opt;
2296 const gchar *text;
2297 int opt_num;
2298 char *buf;
2299
2300 DBG(DBG_proc, "xsane_back_gtk_text_entry_callback\n");
2301
2302 opt_num = elem - xsane.element;
2303 opt = xsane_get_option_descriptor(xsane.dev, opt_num);
2304
2305 buf = alloca(opt->size);
2306 buf[0] = '\0';
2307
2308 text = gtk_entry_get_text(GTK_ENTRY(elem->widget));
2309 if (text)
2310 {
2311 strncpy(buf, text, opt->size);
2312 }
2313 buf[opt->size - 1] = '\0';
2314
2315 xsane_back_gtk_set_option(opt_num, buf, SANE_ACTION_SET_VALUE);
2316
2317 if (strcmp(buf, text) != 0) /* the backend modified the option value; update widget: */
2318 {
2319 gtk_entry_set_text(GTK_ENTRY(elem->widget), buf);
2320 }
2321 }
2322
2323 /* ----------------------------------------------------------------------------------------------------------------- */
2324
xsane_back_gtk_text_entry_new(GtkWidget * parent,const char * name,const char * val,DialogElement * elem,GtkTooltips * tooltips,const char * desc,SANE_Int settable)2325 void xsane_back_gtk_text_entry_new(GtkWidget * parent, const char *name, const char *val, DialogElement *elem,
2326 GtkTooltips *tooltips, const char *desc, SANE_Int settable)
2327 {
2328 GtkWidget *hbox, *text, *label;
2329
2330 DBG(DBG_proc, "xsane_back_gtk_text_entry_new\n");
2331
2332 hbox = gtk_hbox_new(FALSE, 2);
2333 gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
2334 gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
2335
2336 label = gtk_label_new((char *) name);
2337 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
2338
2339 text = gtk_entry_new();
2340 gtk_entry_set_text(GTK_ENTRY(text), (char *) val);
2341 /* gtk_box_pack_start(GTK_BOX(hbox), text, FALSE, TRUE, 0); */ /* text entry fixed */
2342 gtk_box_pack_start(GTK_BOX(hbox), text, TRUE, TRUE, 0); /* text entry sizeable */
2343 g_signal_connect(GTK_OBJECT(text), "changed", (GtkSignalFunc) xsane_back_gtk_text_entry_callback, elem);
2344 xsane_back_gtk_set_tooltip(tooltips, text, desc);
2345
2346 gtk_widget_show(hbox);
2347 gtk_widget_show(label);
2348 gtk_widget_show(text);
2349
2350 gtk_widget_set_sensitive(text, settable);
2351
2352 elem->widget = text;
2353 }
2354
2355 /* ----------------------------------------------------------------------------------------------------------------- */
2356
xsane_back_gtk_group_new(GtkWidget * parent,const char * title)2357 GtkWidget *xsane_back_gtk_group_new(GtkWidget *parent, const char *title)
2358 {
2359 GtkWidget * frame, * vbox;
2360
2361 DBG(DBG_proc, "xsane_back_gtk_group_new(%s)\n", title);
2362
2363 frame = gtk_frame_new((char *) title);
2364 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
2365 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
2366 gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
2367
2368 vbox = gtk_vbox_new(FALSE, 4);
2369 gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
2370 gtk_container_add(GTK_CONTAINER(frame), vbox);
2371 gtk_widget_show(vbox);
2372 return vbox;
2373 }
2374
2375 /* ----------------------------------------------------------------------------------------------------------------- */
2376 #if 0
2377 static void tooltips_destroy(void)
2378 {
2379 DBG(DBG_proc, "tooltips_destroy\n");
2380
2381 gtk_object_unref(GTK_OBJECT(xsane.tooltips));
2382 xsane.tooltips = 0;
2383 }
2384 #endif
2385 /* ----------------------------------------------------------------------------------------------------------------- */
2386
xsane_back_gtk_panel_destroy(void)2387 static void xsane_back_gtk_panel_destroy(void)
2388 {
2389 const SANE_Option_Descriptor *opt;
2390 DialogElement *elem;
2391 int i, j;
2392
2393 DBG(DBG_proc, "xsane_back_gtk_panel_destroy\n");
2394
2395 if (!xsane.xsane_hbox)
2396 {
2397 DBG(DBG_proc, "xsane_back_gtk_panel_destroy: panel does not exist\n");
2398 return;
2399 }
2400
2401 gtk_widget_destroy(xsane.xsane_hbox);
2402 gtk_widget_destroy(xsane.standard_hbox);
2403 gtk_widget_destroy(xsane.advanced_hbox);
2404
2405 xsane.xsane_hbox = NULL;
2406 xsane.standard_hbox = NULL;
2407 xsane.advanced_hbox = NULL;
2408
2409 /* free the menu labels of integer/fix-point word-lists: */
2410 for (i = 0; i < xsane.num_elements; ++i)
2411 {
2412 if (xsane.element[i].menu)
2413 {
2414 opt = xsane_get_option_descriptor(xsane.dev, i);
2415 elem = xsane.element + i;
2416 if (opt->type != SANE_TYPE_STRING)
2417 {
2418 for (j = 0; j < elem->menu_size; ++j)
2419 {
2420 if (elem->menu[j].label)
2421 {
2422 free(elem->menu[j].label);
2423 elem->menu[j].label = 0;
2424 }
2425 }
2426 free(elem->menu);
2427 elem->menu = 0;
2428 }
2429 }
2430 }
2431 memset(xsane.element, 0, xsane.num_elements * sizeof(xsane.element[0]));
2432 }
2433
2434 /* ----------------------------------------------------------------------------------------------------------------- */
2435
xsane_back_gtk_panel_rebuild(void)2436 static void xsane_back_gtk_panel_rebuild(void)
2437 {
2438 DBG(DBG_proc, "xsane_back_gtk_panel_rebuild\n");
2439
2440 xsane_back_gtk_panel_destroy();
2441 xsane_panel_build();
2442 }
2443
2444 /* ----------------------------------------------------------------------------------------------------------------- */
2445
xsane_back_gtk_refresh_dialog(void)2446 void xsane_back_gtk_refresh_dialog(void)
2447 {
2448 DBG(DBG_proc, "xsane_back_gtk_refresh_dialog\n");
2449
2450 xsane_back_gtk_panel_rebuild();
2451 xsane_update_param(0);
2452 }
2453
2454 /* ----------------------------------------------------------------------------------------------------------------- */
2455
xsane_back_gtk_update_scan_window(void)2456 void xsane_back_gtk_update_scan_window(void)
2457 {
2458 const SANE_Option_Descriptor *opt;
2459 double old_val, new_val;
2460 DialogElement *elem;
2461 SANE_Status status;
2462 SANE_Word word;
2463 int i, optnum;
2464 char str[64];
2465
2466 DBG(DBG_proc, "xsane_back_gtk_update_scan_window\n");
2467
2468 for (i = 0; i < 4; ++i)
2469 {
2470 if (xsane.well_known.coord[i] > 0)
2471 {
2472 optnum = xsane.well_known.coord[i];
2473 elem = xsane.element + optnum;
2474 opt = xsane_get_option_descriptor(xsane.dev, optnum);
2475
2476 status = xsane_control_option(xsane.dev, optnum, SANE_ACTION_GET_VALUE, &word, 0);
2477 if (status != SANE_STATUS_GOOD)
2478 {
2479 continue; /* sliently ignore errors */
2480 }
2481
2482 switch(opt->constraint_type)
2483 {
2484 case SANE_CONSTRAINT_RANGE:
2485 if (opt->type == SANE_TYPE_INT)
2486 {
2487 old_val = GTK_ADJUSTMENT(elem->data)->value;
2488 new_val = word;
2489 GTK_ADJUSTMENT(elem->data)->value = new_val;
2490 }
2491 else
2492 {
2493 old_val = GTK_ADJUSTMENT(elem->data)->value;
2494 new_val = SANE_UNFIX(word);
2495 if (opt->unit == SANE_UNIT_MM)
2496 {
2497 new_val /= preferences.length_unit;
2498 }
2499 GTK_ADJUSTMENT(elem->data)->value = new_val;
2500 }
2501
2502 if (old_val != new_val) /* XXX dangerous comparison of doubles, we should allow tiny differences */
2503 {
2504 g_signal_emit_by_name(GTK_OBJECT(elem->data), "value_changed");
2505 }
2506 break;
2507
2508 case SANE_CONSTRAINT_WORD_LIST:
2509 if (opt->type == SANE_TYPE_INT)
2510 {
2511 sprintf(str, "%d", word);
2512 }
2513 else
2514 {
2515 sprintf(str, "%g", SANE_UNFIX(word));
2516 }
2517 /* XXX maybe we should call this only when the value changes... */
2518 gtk_option_menu_set_history(GTK_OPTION_MENU(elem->widget), xsane_back_gtk_option_menu_lookup(elem->menu, str));
2519 break;
2520
2521 default:
2522 break;
2523 }
2524 }
2525 }
2526 }
2527
2528 /* ----------------------------------------------------------------------------------------------------------------- */
2529
xsane_back_gtk_update_vector(int opt_num,SANE_Int * vector)2530 void xsane_back_gtk_update_vector(int opt_num, SANE_Int *vector)
2531 {
2532 const SANE_Option_Descriptor *opt;
2533 gfloat val;
2534 SANE_Word *optval;
2535 int j, optlen;
2536
2537 DBG(DBG_proc, "xsane_back_gtk_update_vector\n");
2538
2539 if (opt_num < 1)
2540 return; /* not defined */
2541
2542 opt = xsane_get_option_descriptor(xsane.dev, opt_num);
2543 if (!SANE_OPTION_IS_ACTIVE(opt->cap))
2544 {
2545 return; /* inactive */
2546 }
2547
2548 if (opt->type != SANE_TYPE_INT && opt->type != SANE_TYPE_FIXED)
2549 {
2550 return;
2551 }
2552
2553 if (opt->size == sizeof(SANE_Word))
2554 {
2555 return;
2556 }
2557
2558 /* ok, we're dealing with an active vector */
2559
2560 optlen = opt->size / sizeof(SANE_Word);
2561 optval = alloca(optlen * sizeof(optval[0]));
2562 for (j = 0; j < optlen; ++j)
2563 {
2564 val = vector[j];
2565 if (opt->type == SANE_TYPE_FIXED)
2566 {
2567 optval[j] = SANE_FIX(val);
2568 }
2569 else
2570 {
2571 optval[j] = val + 0.5;
2572 }
2573 }
2574
2575 xsane_back_gtk_set_option(opt_num, optval, SANE_ACTION_SET_VALUE);
2576 }
2577
2578 /* ----------------------------------------------------------------------------------------------------------------- */
2579
xsane_back_gtk_set_tooltips(int enable)2580 void xsane_back_gtk_set_tooltips(int enable)
2581 {
2582 DBG(DBG_proc, "xsane_back_gtk_set_tooltips\n");
2583
2584 if (!xsane.tooltips)
2585 {
2586 return;
2587 }
2588
2589 if (enable)
2590 {
2591 gtk_tooltips_enable(xsane.tooltips);
2592 }
2593 else
2594 {
2595 gtk_tooltips_disable(xsane.tooltips);
2596 }
2597 }
2598
2599 /* ----------------------------------------------------------------------------------------------------------------- */
2600
xsane_back_gtk_set_sensitivity(int sensitive)2601 void xsane_back_gtk_set_sensitivity(int sensitive)
2602 {
2603 const SANE_Option_Descriptor *opt;
2604 int i;
2605
2606 DBG(DBG_proc, "xsane_back_gtk_set_sensitivity\n");
2607
2608 for (i = 0; i < xsane.num_elements; ++i)
2609 {
2610 opt = xsane_get_option_descriptor(xsane.dev, i);
2611
2612 if (!SANE_OPTION_IS_ACTIVE(opt->cap) || !SANE_OPTION_IS_SETTABLE(opt->cap) ||
2613 opt->type == SANE_TYPE_GROUP || !xsane.element[i].widget)
2614 {
2615 continue;
2616 }
2617
2618 // if (!(opt->cap & SANE_CAP_ALWAYS_SETTABLE))
2619 {
2620 gtk_widget_set_sensitive(xsane.element[i].widget, sensitive);
2621 }
2622 }
2623
2624 if (xsane.xsanemode_widget)
2625 {
2626 gtk_widget_set_sensitive(xsane.xsanemode_widget, sensitive);
2627 }
2628
2629 while (gtk_events_pending())
2630 {
2631 gtk_main_iteration();
2632 }
2633 }
2634 /* ---------------------------------------------------------------------------------------------------------------------- */
2635
xsane_set_sensitivity(SANE_Int sensitivity)2636 void xsane_set_sensitivity(SANE_Int sensitivity)
2637 {
2638 DBG(DBG_proc, "xsane_set_sensitivity(%d)\n", sensitivity);
2639
2640 if (xsane.dialog)
2641 {
2642 /* clear or rebuild histogram */
2643 if (sensitivity)
2644 {
2645 xsane_update_histogram(TRUE /* update raw */);
2646 }
2647 else
2648 {
2649 xsane_clear_histogram(&xsane.histogram_raw);
2650 xsane_clear_histogram(&xsane.histogram_enh);
2651 }
2652
2653 gtk_widget_set_sensitive(xsane.menubar, sensitivity);
2654 gtk_widget_set_sensitive(xsane.xsane_window, sensitivity);
2655 gtk_widget_set_sensitive(GTK_WIDGET(xsane.start_button), sensitivity);
2656 gtk_widget_set_sensitive(xsane.standard_options_dialog, sensitivity);
2657 gtk_widget_set_sensitive(xsane.advanced_options_dialog, sensitivity);
2658 gtk_widget_set_sensitive(xsane.histogram_dialog, sensitivity);
2659 #ifdef HAVE_WORKING_GTK_GAMMACURVE
2660 gtk_widget_set_sensitive(xsane.gamma_dialog, sensitivity);
2661 #endif
2662 }
2663
2664 if (xsane.preview)
2665 {
2666 gtk_widget_set_sensitive(xsane.preview->button_box, sensitivity); /* button box at top of window */
2667 gtk_widget_set_sensitive(xsane.preview->menu_box, sensitivity); /* menu box at top of window */
2668 #if 1
2669 gtk_widget_set_sensitive(xsane.preview->viewport, sensitivity); /* Preview image selection */
2670 #endif
2671 gtk_widget_set_sensitive(xsane.preview->start, sensitivity); /* Acquire preview button */
2672 }
2673
2674 if (xsane.project_dialog)
2675 {
2676 /* do not change sensitivity of project_dialog, we want the progress bar */
2677 /* to be sensitive */
2678 gtk_widget_set_sensitive(xsane.project_box, sensitivity);
2679 gtk_widget_set_sensitive(xsane.project_exists, sensitivity);
2680 gtk_widget_set_sensitive(xsane.project_entry_box, sensitivity);
2681 }
2682
2683 if (xsane.batch_scan_dialog)
2684 {
2685 gtk_widget_set_sensitive(xsane.batch_scan_button_box, sensitivity);
2686 gtk_widget_set_sensitive(xsane.batch_scan_action_box, sensitivity);
2687 }
2688
2689 xsane.sensitivity = sensitivity;
2690 }
2691
2692 /* ----------------------------------------------------------------------------------------------------------------- */
2693
xsane_back_gtk_destroy_dialog(void)2694 void xsane_back_gtk_destroy_dialog(void)
2695 {
2696 SANE_Handle dev = xsane.dev;
2697
2698 DBG(DBG_proc, "xsane_back_gtk_destroy_dialog\n");
2699
2700 xsane_back_gtk_panel_destroy();
2701 free((void *) xsane.dev_name);
2702 free(xsane.element);
2703
2704 sane_close(dev);
2705 }
2706 /* ---------------------------------------------------------------------------------------------------------------------- */
2707
xsane_set_window_icon(GtkWidget * gtk_window,gchar ** xpm_d)2708 void xsane_set_window_icon(GtkWidget *gtk_window, gchar **xpm_d)
2709 {
2710 GdkPixmap *pixmap;
2711 GdkBitmap *mask;
2712
2713 DBG(DBG_proc, "xsane_set_window_icon\n");
2714
2715 gtk_widget_realize(gtk_window);
2716 if (xpm_d)
2717 {
2718 pixmap = gdk_pixmap_create_from_xpm_d(gtk_window->window, &mask, xsane.bg_trans, xpm_d);
2719 }
2720 else
2721 {
2722 if (xsane.window_icon_pixmap)
2723 {
2724 pixmap = xsane.window_icon_pixmap;
2725 mask = xsane.window_icon_mask;
2726 }
2727 else
2728 {
2729 pixmap = gdk_pixmap_create_from_xpm_d(gtk_window->window, &mask, xsane.bg_trans, (gchar **) xsane_window_icon_xpm);
2730 }
2731 }
2732
2733 gdk_window_set_icon(gtk_window->window, 0, pixmap, mask);
2734 }
2735
2736 /* ---------------------------------------------------------------------------------------------------------------------- */
2737