3
#include <gconf/gconf-client.h>
16
static guint signals[LAST_SIGNAL] = { 0, };
19
struct SimpleScanPrivate
24
GtkWidget *scan_label;
25
GtkWidget *actions_box;
26
GtkWidget *device_combo, *mode_combo;
27
GtkWidget *preview_area;
30
Orientation orientation;
33
G_DEFINE_TYPE (SimpleScan, ui, G_TYPE_OBJECT);
37
find_scan_device (SimpleScan *ui, const char *device, GtkTreeIter *iter)
40
gboolean have_iter = FALSE;
42
model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->device_combo));
43
if (gtk_tree_model_get_iter_first (model, iter)) {
46
gtk_tree_model_get (model, iter, 0, &d, -1);
47
if (strcmp (d, device) == 0)
50
} while (!have_iter && gtk_tree_model_iter_next (model, iter));
58
get_selected_device (SimpleScan *ui)
62
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter)) {
66
model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->device_combo));
67
gtk_tree_model_get (model, &iter, 0, &device, -1);
76
ui_mark_devices_undetected (SimpleScan *ui)
81
model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->device_combo));
82
if (gtk_tree_model_get_iter_first (model, &iter)) {
84
gtk_list_store_set (GTK_LIST_STORE (model), &iter, 2, FALSE, -1);
85
} while (gtk_tree_model_iter_next (model, &iter));
91
ui_add_scan_device (SimpleScan *ui, const gchar *device, const gchar *label)
96
model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->device_combo));
98
if (!find_scan_device (ui, device, &iter)) {
99
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
100
gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, device, -1);
103
gtk_list_store_set (GTK_LIST_STORE (model), &iter, 1, label, 2, TRUE, -1);
105
/* Select this device if none selected */
106
if (gtk_combo_box_get_active (GTK_COMBO_BOX (ui->priv->device_combo)) == -1)
107
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter);
112
get_document_hint (SimpleScan *ui)
116
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->mode_combo), &iter)) {
120
model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->mode_combo));
121
gtk_tree_model_get (model, &iter, 0, &mode, -1);
129
preview_area_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, SimpleScan *ui)
132
double width, height;
134
context = gdk_cairo_create (widget->window);
136
width = widget->allocation.width;
137
height = widget->allocation.height;
138
g_signal_emit (G_OBJECT (ui), signals[RENDER_PREVIEW], 0, context, width, height);
140
cairo_destroy (context);
148
scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
150
if (ui->priv->scanning) {
151
g_signal_emit (G_OBJECT (ui), signals[STOP_SCAN], 0);
154
device = get_selected_device (ui);
156
g_signal_emit (G_OBJECT (ui), signals[START_SCAN], 0, device);
165
rotate_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
167
ui->priv->orientation++;
168
if (ui->priv->orientation > RIGHT_TO_LEFT)
169
ui->priv->orientation = TOP_TO_BOTTOM;
170
ui_redraw_preview (ui);
176
save_file_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
181
dialog = gtk_file_chooser_dialog_new ("Save As...", GTK_WINDOW (ui->priv->window),
182
GTK_FILE_CHOOSER_ACTION_SAVE,
183
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
184
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
186
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
187
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
188
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "Scanned Document.pdf");
190
response = gtk_dialog_run (GTK_DIALOG (dialog));
191
if (response == GTK_RESPONSE_ACCEPT) {
194
uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
195
g_signal_emit (G_OBJECT (ui), signals[SAVE], 0, uri);
199
gtk_widget_destroy (dialog);
204
draw_page (GtkPrintOperation *operation,
205
GtkPrintContext *print_context,
211
context = gtk_print_context_get_cairo_context (print_context);
213
g_signal_emit (G_OBJECT (ui), signals[PRINT], 0, context);
215
//For some reason can't destroy until job complete
216
//cairo_destroy (context);
222
print_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
224
GtkPrintOperation *print;
225
GtkPrintOperationResult result;
226
GError *error = NULL;
228
print = gtk_print_operation_new ();
229
gtk_print_operation_set_n_pages (print, 1);
230
gtk_print_operation_set_use_full_page (print, TRUE);
231
// FIXME: Auto portrait, landscape
232
g_signal_connect (print, "draw-page", G_CALLBACK (draw_page), ui);
234
result = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
235
GTK_WINDOW (ui->priv->window), &error);
237
g_object_unref (print);
242
load_device_cache (SimpleScan *ui)
247
GError *error = NULL;
249
filename = g_build_filename (g_get_user_cache_dir (), "simple-scan", "device_cache", NULL);
251
key_file = g_key_file_new ();
252
result = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &error);
254
g_warning ("Error loading device cache file: %s", error->message);
255
g_error_free (error);
259
gchar **groups, **group_iter;
261
groups = g_key_file_get_groups (key_file, NULL);
262
for (group_iter = groups; *group_iter; group_iter++) {
263
gchar *label, *device;
266
device = g_key_file_get_value (key_file, label, "device", &error);
268
g_warning ("Error getting device name for label '%s': %s", label, error->message);
269
g_error_free (error);
274
ui_add_scan_device (ui, device, label);
283
g_key_file_free (key_file);
288
save_device_cache (SimpleScan *ui)
293
g_debug ("Saving device cache");
295
model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->device_combo));
296
if (gtk_tree_model_get_iter_first (model, &iter)) {
300
GError *error = NULL;
302
key_file = g_key_file_new ();
307
gtk_tree_model_get (model, &iter, 0, &name, 1, &label, 2, &detected, -1);
310
g_debug ("Storing device '%s' in cache", name);
311
g_key_file_set_value (key_file, label, "device", name);
316
} while (gtk_tree_model_iter_next (model, &iter));
318
data = g_key_file_to_data (key_file, &data_length, &error);
320
gchar *dir, *filename;
322
GFileOutputStream *stream;
323
GError *error = NULL;
325
dir = g_build_filename (g_get_user_cache_dir (), "simple-scan", NULL);
326
g_mkdir_with_parents (dir, 0700);
327
filename = g_build_filename (dir, "device_cache", NULL);
329
file = g_file_new_for_path (filename);
330
stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error);
332
g_warning ("Error writing device cache: %s", error->message);
333
g_error_free (error);
337
g_output_stream_write_all (G_OUTPUT_STREAM (stream), data, data_length, NULL, NULL, &error);
339
g_warning ("Error writing device cache: %s", error->message);
340
g_error_free (error);
343
g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
351
g_key_file_free (key_file);
358
window_delete_event_cb (GtkWidget *widget, GdkEvent *event, SimpleScan *ui)
361
save_device_cache (ui);
362
device = get_selected_device (ui);
364
gconf_client_set_string(ui->priv->client, "/apps/simple-scan/selected_device", device, NULL);
373
ui_load (SimpleScan *ui)
376
GError *error = NULL;
377
GtkCellRenderer *renderer;
381
builder = gtk_builder_new ();
382
gtk_builder_add_from_file (builder, UI_DIR "simple-scan.ui", &error);
384
g_critical ("Unable to load UI: %s\n", error->message);
387
gtk_builder_connect_signals (builder, ui);
389
ui->priv->window = GTK_WIDGET (gtk_builder_get_object (builder, "simple_scan_window"));
390
ui->priv->scan_label = GTK_WIDGET (gtk_builder_get_object (builder, "scan_label"));
391
ui->priv->actions_box = GTK_WIDGET (gtk_builder_get_object (builder, "actions_box"));
392
ui->priv->device_combo = GTK_WIDGET (gtk_builder_get_object (builder, "device_combo"));
393
ui->priv->mode_combo = GTK_WIDGET (gtk_builder_get_object (builder, "mode_combo"));
394
ui->priv->preview_area = GTK_WIDGET (gtk_builder_get_object (builder, "preview_area"));
396
renderer = gtk_cell_renderer_text_new();
397
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->priv->device_combo), renderer, TRUE);
398
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->priv->device_combo), renderer, "text", 1);
400
renderer = gtk_cell_renderer_text_new();
401
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->priv->mode_combo), renderer, TRUE);
402
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->priv->mode_combo), renderer, "text", 1);
403
gtk_combo_box_set_active (GTK_COMBO_BOX (ui->priv->mode_combo), 0);
405
/* Load previously detected scanners and select the last used one */
406
load_device_cache (ui);
407
device = gconf_client_get_string(ui->priv->client, "/apps/simple-scan/selected_device", NULL);
408
if (device && find_scan_device (ui, device, &iter)) {
409
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter);
419
return g_object_new (SIMPLE_SCAN_TYPE, NULL);
424
ui_set_scanning (SimpleScan *ui, gboolean scanning)
426
ui->priv->scanning = scanning;
427
if (ui->priv->scanning)
428
gtk_label_set_label (GTK_LABEL (ui->priv->scan_label), "_Cancel");
430
gtk_label_set_label (GTK_LABEL (ui->priv->scan_label), "_Scan");
435
ui_set_have_scan (SimpleScan *ui, gboolean have_scan)
437
gtk_widget_set_sensitive (ui->priv->actions_box, have_scan);
441
Orientation ui_get_orientation (SimpleScan *ui)
443
return ui->priv->orientation;
448
ui_redraw_preview (SimpleScan *ui)
450
gtk_widget_queue_draw (ui->priv->preview_area);
455
g_cclosure_user_marshal_VOID__POINTER_DOUBLE_DOUBLE (GClosure *closure,
456
GValue *return_value G_GNUC_UNUSED,
457
guint n_param_values,
458
const GValue *param_values,
459
gpointer invocation_hint G_GNUC_UNUSED,
460
gpointer marshal_data)
462
typedef void (*GMarshalFunc_VOID__POINTER_DOUBLE_DOUBLE) (gpointer data1,
467
register GMarshalFunc_VOID__POINTER_DOUBLE_DOUBLE callback;
468
register GCClosure *cc = (GCClosure*) closure;
469
register gpointer data1, data2;
471
g_return_if_fail (n_param_values == 4);
473
if (G_CCLOSURE_SWAP_DATA (closure))
475
data1 = closure->data;
476
data2 = g_value_peek_pointer (param_values + 0);
480
data1 = g_value_peek_pointer (param_values + 0);
481
data2 = closure->data;
483
callback = (GMarshalFunc_VOID__POINTER_DOUBLE_DOUBLE) (marshal_data ? marshal_data : cc->callback);
486
g_value_get_pointer (param_values + 1),
487
g_value_get_double (param_values + 2),
488
g_value_get_double (param_values + 3),
494
ui_class_init (SimpleScanClass *klass)
496
signals[RENDER_PREVIEW] =
497
g_signal_new ("render-preview",
498
G_TYPE_FROM_CLASS (klass),
500
G_STRUCT_OFFSET (SimpleScanClass, render_preview),
502
g_cclosure_user_marshal_VOID__POINTER_DOUBLE_DOUBLE,
503
G_TYPE_NONE, 3, G_TYPE_POINTER, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
504
signals[START_SCAN] =
505
g_signal_new ("start-scan",
506
G_TYPE_FROM_CLASS (klass),
508
G_STRUCT_OFFSET (SimpleScanClass, start_scan),
510
g_cclosure_marshal_VOID__INT,
511
G_TYPE_NONE, 1, G_TYPE_INT);
513
g_signal_new ("stop-scan",
514
G_TYPE_FROM_CLASS (klass),
516
G_STRUCT_OFFSET (SimpleScanClass, stop_scan),
518
g_cclosure_marshal_VOID__VOID,
521
g_signal_new ("save",
522
G_TYPE_FROM_CLASS (klass),
524
G_STRUCT_OFFSET (SimpleScanClass, save),
526
g_cclosure_marshal_VOID__POINTER,
527
G_TYPE_NONE, 1, G_TYPE_POINTER);
529
g_signal_new ("print",
530
G_TYPE_FROM_CLASS (klass),
532
G_STRUCT_OFFSET (SimpleScanClass, print),
534
g_cclosure_marshal_VOID__POINTER,
535
G_TYPE_NONE, 1, G_TYPE_POINTER);
537
g_type_class_add_private (klass, sizeof (SimpleScanPrivate));
542
ui_init (SimpleScan *ui)
544
ui->priv = G_TYPE_INSTANCE_GET_PRIVATE (ui, SIMPLE_SCAN_TYPE, SimpleScanPrivate);
546
ui->priv->client = gconf_client_get_default();
547
gconf_client_add_dir(ui->priv->client, "/apps/simple-scan", GCONF_CLIENT_PRELOAD_NONE, NULL);
549
ui->priv->scanning = FALSE;
550
ui->priv->orientation = TOP_TO_BOTTOM;