diff options
| author | Jörg Frings-Fürst <debian@jff.email> | 2020-09-12 11:16:14 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff.email> | 2020-09-12 11:16:14 +0200 | 
| commit | 7ab8c8e0307a0d58438619693c53d9844763f1e8 (patch) | |
| tree | 50f52c0c05e184dc61f702a853b3e3eee97b3654 /src | |
| parent | 0bb0910e8e7dfbc3a55ae89fc2544ce65e62a1d5 (diff) | |
New upstream version 3.38.0upstream/3.38.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/app-window.ui | 1 | ||||
| -rw-r--r-- | src/app-window.vala | 178 | ||||
| -rw-r--r-- | src/book.vala | 26 | ||||
| -rw-r--r-- | src/help-overlay.ui | 9 | ||||
| -rw-r--r-- | src/page-view.vala | 106 | ||||
| -rw-r--r-- | src/scanner.vala | 80 | ||||
| -rw-r--r-- | src/simple-scan.vala | 294 | 
7 files changed, 579 insertions, 115 deletions
| diff --git a/src/app-window.ui b/src/app-window.ui index e0e16c0..6f42a51 100644 --- a/src/app-window.ui +++ b/src/app-window.ui @@ -670,6 +670,7 @@              <property name="can_focus">False</property>              <property name="receives_default">False</property>              <property name="use_underline">True</property> +            <accelerator key="F10" signal="activate"/>              <child>                <object class="GtkImage">                  <property name="visible">True</property> diff --git a/src/app-window.vala b/src/app-window.vala index 30adac9..67f10a8 100644 --- a/src/app-window.vala +++ b/src/app-window.vala @@ -188,6 +188,7 @@ public class AppWindow : Gtk.ApplicationWindow      public signal void start_scan (string? device, ScanOptions options);      public signal void stop_scan (); +    public signal void redetect ();      public AppWindow ()      { @@ -224,7 +225,7 @@ public class AppWindow : Gtk.ApplicationWindow                                              Gtk.ButtonsType.NONE,                                              "%s", error_title);          dialog.add_button (_("_Close"), 0); -        dialog.format_secondary_text ("%s", error_text); +        dialog.format_secondary_markup  ("%s", error_text);          dialog.run ();          dialog.destroy ();      } @@ -245,7 +246,7 @@ public class AppWindow : Gtk.ApplicationWindow      private void update_scan_status ()      { -        scan_button.set_sensitive(false); +        scan_button.sensitive = false;          if (!have_devices)          {              status_primary_label.set_text (/* Label shown when searching for scanners */ @@ -255,12 +256,13 @@ public class AppWindow : Gtk.ApplicationWindow          }          else if (get_selected_device () != null)          { -            scan_button.set_sensitive(true); +            scan_button.sensitive = true;              status_primary_label.set_text (/* Label shown when detected a scanner */                                             _("Ready to Scan"));              status_secondary_label.set_text (get_selected_device_label ());              status_secondary_label.visible = false;              device_combo.visible = true; +            device_combo.sensitive = true;          }          else if (this.missing_driver != null)          { @@ -449,7 +451,7 @@ public class AppWindow : Gtk.ApplicationWindow          directory = settings.get_string ("save-directory");          if (directory == null || directory == "") -            directory = Environment.get_user_special_dir (UserDirectory.DOCUMENTS); +            directory = GLib.Filename.to_uri(Environment.get_user_special_dir (UserDirectory.DOCUMENTS));          var save_dialog = new Gtk.FileChooserNative (/* Save dialog: Dialog title */                                                       _("Save As…"), @@ -458,12 +460,15 @@ public class AppWindow : Gtk.ApplicationWindow                                                       _("_Save"),                                                       _("_Cancel"));          save_dialog.local_only = false; + +        var save_format = settings.get_string ("save-format");          if (book_uri != null)              save_dialog.set_uri (book_uri);          else { -            save_dialog.set_current_folder (directory); -            /* Default filename to use when saving document */ -            save_dialog.set_current_name (_("Scanned Document.pdf")); +            save_dialog.set_current_folder_uri (directory); +            /* Default filename to use when saving document. */ +            /* To that filename the extension will be added, eg. "Scanned Document.pdf" */ +            save_dialog.set_current_name (_("Scanned Document") + "." + mime_type_to_extension (save_format));          }          /* Filter to only show images by default */ @@ -489,31 +494,32 @@ public class AppWindow : Gtk.ApplicationWindow          file_type_store.set (iter,                               /* Save dialog: Label for saving in PDF format */                               0, _("PDF (multi-page document)"), -                             1, ".pdf", +                             1, "application/pdf",                               -1);          file_type_store.append (out iter);          file_type_store.set (iter,                               /* Save dialog: Label for saving in JPEG format */                               0, _("JPEG (compressed)"), -                             1, ".jpg", +                             1, "image/jpeg",                               -1);          file_type_store.append (out iter);          file_type_store.set (iter,                               /* Save dialog: Label for saving in PNG format */                               0, _("PNG (lossless)"), -                             1, ".png", +                             1, "image/png",                               -1);  #if HAVE_WEBP          file_type_store.append (out iter);          file_type_store.set (iter,                               /* Save dialog: Label for sabing in WEBP format */                               0, _("WebP (compressed)"), -                             1, ".webp", +                             1, "image/webp",                               -1);  #endif          var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);          box.visible = true; +        box.spacing = 10;          save_dialog.set_extra_widget (box);          /* Label in save dialog beside combo box to choose file format (PDF, JPEG, PNG, WEBP) */ @@ -528,29 +534,47 @@ public class AppWindow : Gtk.ApplicationWindow          file_type_combo.add_attribute (renderer, "text", 0);          box.add (file_type_combo); +        if (file_type_store.get_iter_first (out iter)) +        { +            do +            { +                string mime_type; +                file_type_store.get (iter, 1, out mime_type, -1); +                if (mime_type == save_format) +                    file_type_combo.set_active_iter (iter); +            } while (file_type_store.iter_next (ref iter)); +        } +          /* Label in save dialog beside compression slider */          var quality_label = new Gtk.Label (_("Compression:"));          box.add (quality_label);          var quality_adjustment = new Gtk.Adjustment (75, 0, 100, 1, 10, 0);          var quality_scale = new Gtk.Scale (Gtk.Orientation.HORIZONTAL, quality_adjustment); -        quality_scale.width_request = 200; +        quality_scale.width_request = 250;          quality_scale.draw_value = false; -        quality_scale.add_mark (0, Gtk.PositionType.BOTTOM, null); +        var minimum_size_label = "<small>%s</small>".printf (_("Minimum size")); +        quality_scale.add_mark (quality_adjustment.lower, Gtk.PositionType.BOTTOM, minimum_size_label);          quality_scale.add_mark (75, Gtk.PositionType.BOTTOM, null);          quality_scale.add_mark (90, Gtk.PositionType.BOTTOM, null); -        quality_scale.add_mark (100, Gtk.PositionType.BOTTOM, null); +        var full_detail_label = "<small>%s</small>".printf (_("Full detail")); +        quality_scale.add_mark (quality_adjustment.upper, Gtk.PositionType.BOTTOM, full_detail_label);          quality_adjustment.value = settings.get_int ("jpeg-quality");          quality_adjustment.value_changed.connect (() => { settings.set_int ("jpeg-quality", (int) quality_adjustment.value); });          box.add (quality_scale); -        file_type_combo.set_active (0); +        /* Quality not applicable to PNG */ +        quality_scale.visible = quality_label.visible = (save_format != "image/png"); +          file_type_combo.changed.connect (() =>          { -            var extension = ""; +            var mime_type = "";              Gtk.TreeIter i;              if (file_type_combo.get_active_iter (out i)) -                file_type_store.get (i, 1, out extension, -1); +            { +                file_type_store.get (i, 1, out mime_type, -1); +                settings.set_string ("save-format", mime_type); +            }              var filename = save_dialog.get_current_name (); @@ -558,11 +582,11 @@ public class AppWindow : Gtk.ApplicationWindow              var extension_index = filename.last_index_of_char ('.');              if (extension_index >= 0)                  filename = filename.slice (0, extension_index); -            filename = filename + extension; +            filename = filename + "." + mime_type_to_extension (mime_type);              save_dialog.set_current_name (filename);              /* Quality not applicable to PNG */ -            quality_scale.visible = quality_label.visible = (extension != ".png"); +            quality_scale.visible = quality_label.visible = (mime_type != "image/png");          });          while (true) @@ -574,25 +598,20 @@ public class AppWindow : Gtk.ApplicationWindow                  return null;              } -            var extension = ""; +            var mime_type = "";              Gtk.TreeIter i;              if (file_type_combo.get_active_iter (out i)) -                file_type_store.get (i, 1, out extension, -1); +                file_type_store.get (i, 1, out mime_type, -1);              var uri = save_dialog.get_uri ();              var extension_index = uri.last_index_of_char ('.');              if (extension_index < 0) -                uri += extension; +                uri += "." + mime_type_to_extension (mime_type);              /* Check the file(s) don't already exist */              var files = new List<File> (); -            var format = uri_to_format (uri); -#if HAVE_WEBP -            if (format == "jpeg" || format == "png" || format == "webp") -#else -            if (format == "jpeg" || format == "png") -#endif +            if (mime_type == "image/jpeg" || mime_type == "image/png" || mime_type == "image/webp")              {                  for (var j = 0; j < book.n_pages; j++)                      files.append (make_indexed_file (uri, j, book.n_pages)); @@ -602,7 +621,8 @@ public class AppWindow : Gtk.ApplicationWindow              if (check_overwrite (save_dialog.transient_for, files))              { -                settings.set_string ("save-directory", save_dialog.get_current_folder ()); +                var directory_uri = uri.substring (0, uri.last_index_of ("/") + 1); +                settings.set_string ("save-directory", directory_uri);                  save_dialog.destroy ();                  return uri;              } @@ -633,19 +653,47 @@ public class AppWindow : Gtk.ApplicationWindow          return true;      } -    private string uri_to_format (string uri) +    private string? mime_type_to_extension (string mime_type)      { -        var uri_lower = uri.down (); -        if (uri_lower.has_suffix (".pdf")) +        if (mime_type == "application/pdf")              return "pdf"; -        else if (uri_lower.has_suffix (".png")) +        else if (mime_type == "image/jpeg") +            return "jpg"; +        else if (mime_type == "image/png")              return "png"; -#if HAVE_WEBP -        else if (uri_lower.has_suffix (".webp")) +        else if (mime_type == "image/webp")              return "webp"; -#endif          else -            return "jpeg"; +            return null; +    } + +    private string? extension_to_mime_type (string extension) +    { +        var extension_lower = extension.down (); +        if (extension_lower == "pdf") +            return "application/pdf"; +        else if (extension_lower == "jpg") +            return "image/jpeg"; +        else if (extension_lower == "png") +            return "image/png"; +        else if (extension_lower == "webp") +            return "image/webp"; +        else +            return null; +    } + +    private string uri_to_mime_type (string uri) +    { +        var extension_index = uri.last_index_of_char ('.'); +        if (extension_index < 0) +            return "image/jpeg"; +        var extension = uri.substring (extension_index + 1); + +        var mime_type = extension_to_mime_type (extension); +        if (mime_type == null) +            return "image/jpeg"; + +        return mime_type;      }      private async bool save_document_async () @@ -658,7 +706,7 @@ public class AppWindow : Gtk.ApplicationWindow          debug ("Saving to '%s'", uri); -        var format = uri_to_format (uri); +        var mime_type = uri_to_mime_type (uri);          var cancellable = new Cancellable ();          var progress_bar =  new CancellableProgressBar (_("Saving"), cancellable); @@ -667,7 +715,7 @@ public class AppWindow : Gtk.ApplicationWindow          save_button.sensitive = false;          try          { -            yield book.save_async (format, settings.get_int ("jpeg-quality"), file, (fraction) => +            yield book.save_async (mime_type, settings.get_int ("jpeg-quality"), file, (fraction) =>              {                  progress_bar.set_fraction (fraction);              }, cancellable); @@ -748,6 +796,9 @@ public class AppWindow : Gtk.ApplicationWindow              if (scanning)                  stop_scan (); +            have_devices = false; +            /* Refresh list of devices to detect network scanners, and fix issues with disconnected scanners */ +            redetect ();              clear_document ();          });      } @@ -773,6 +824,7 @@ public class AppWindow : Gtk.ApplicationWindow      {          status_primary_label.set_text (/* Label shown when scan started */                                         _("Contacting scanner…")); +        device_combo.sensitive = false;          start_scan (get_selected_device (), options);      } @@ -1428,11 +1480,21 @@ public class AppWindow : Gtk.ApplicationWindow          try          {              var dir = DirUtils.make_tmp ("simple-scan-XXXXXX"); -            var type = document_hint == "text" ? "pdf" : "jpeg"; -            var file = File.new_for_path (Path.build_filename (dir, "scan." + type)); -            yield book.save_async (type, settings.get_int ("jpeg-quality"), file, null, null); +            string mime_type, filename; +            if (document_hint == "text") +            { +                mime_type = "application/pdf"; +                filename = "scan.pdf"; +            } +            else +            { +                mime_type = "image/jpeg"; +                filename = "scan.jpg"; +            } +            var file = File.new_for_path (Path.build_filename (dir, filename)); +            yield book.save_async (mime_type, settings.get_int ("jpeg-quality"), file, null, null);              var command_line = "xdg-email"; -            if (type == "pdf") +            if (mime_type == "application/pdf")                  command_line += " --attach %s".printf (file.get_path ());              else              { @@ -1574,16 +1636,31 @@ public class AppWindow : Gtk.ApplicationWindow              /* Instructions on how to install Brother scanner drivers */              instructions = _("Drivers for this are available on the <a href=\"http://support.brother.com\">Brother website</a>.");              break; +        case "pixma": +            /* Message to indicate a Canon Pixma scanner has been detected */ +            message = _("You appear to have a Canon scanner, which is supported by the <a href=\"http://www.sane-project.org/man/sane-pixma.5.html\">Pixma SANE backend</a>."); +            /* Instructions on how to resolve issue with SANE scanner drivers */ +            instructions = _("Please check if your <a href=\"http://www.sane-project.org/sane-supported-devices.html\">scanner is supported by SANE</a>, otherwise report the issue to the <a href=\"https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/sane-devel\">SANE mailing list</a>."); +            break;          case "samsung":              /* Message to indicate a Samsung scanner has been detected */              message = _("You appear to have a Samsung scanner."); -            /* Instructions on how to install Samsung scanner drivers */ -            instructions = _("Drivers for this are available on the <a href=\"http://samsung.com/support\">Samsung website</a>."); +            /* Instructions on how to install Samsung scanner drivers. +               Because HP acquired Samsung's global printing business in 2017, the support is made on HP site. */ +            instructions = _("Drivers for this are available on the <a href=\"https://support.hp.com\">HP website</a> (HP acquired Samsung's printing business).");              break;          case "hpaio": +        case "smfp":              /* Message to indicate a HP scanner has been detected */              message = _("You appear to have an HP scanner."); -            packages_to_install = { "libsane-hpaio" }; +            if (missing_driver == "hpaio") +                packages_to_install = { "libsane-hpaio" }; +            else +                /* Instructions on how to install HP scanner drivers. +                   smfp is rebranded and slightly modified Samsung devices, +                   for example: HP Laser MFP 135a is rebranded Samsung Xpress SL-M2070. +                   It require custom drivers, not available in hpaio package */ +                instructions = _("Drivers for this are available on the <a href=\"https://support.hp.com\">HP website</a>.");              break;          case "epkowa":              /* Message to indicate an Epson scanner has been detected */ @@ -1591,6 +1668,12 @@ public class AppWindow : Gtk.ApplicationWindow              /* Instructions on how to install Epson scanner drivers */              instructions = _("Drivers for this are available on the <a href=\"http://support.epson.com\">Epson website</a>.");              break; +        case "lexmark_nscan": +            /* Message to indicate an Lexmark scanner has been detected */ +            message = _("You appear to have an Lexmark scanner."); +            /* Instructions on how to install Lexmark scanner drivers */ +            instructions = _("Drivers for this are available on the <a href=\"http://support.lexmark.com\">Lexmark website</a>."); +            break;          }          var dialog = new Gtk.Dialog.with_buttons (/* Title of dialog giving instructions on how to install drivers */                                                    _("Install drivers"), this, Gtk.DialogFlags.MODAL, _("_Close"), Gtk.ResponseType.CLOSE); @@ -1601,6 +1684,7 @@ public class AppWindow : Gtk.ApplicationWindow          label.visible = true;          label.xalign = 0f;          label.vexpand = true; +        label.use_markup = true;          dialog.get_content_area ().add (label);          var instructions_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6); @@ -1780,7 +1864,7 @@ public class AppWindow : Gtk.ApplicationWindow          app.set_accels_for_action ("app.print", { "<Ctrl>P" });          app.set_accels_for_action ("app.help", { "F1" });          app.set_accels_for_action ("app.quit", { "<Ctrl>Q" }); -        app.set_accels_for_action ("win.show-help-overlay", { "<Ctrl>F1" }); +        app.set_accels_for_action ("win.show-help-overlay", { "<Ctrl>question" });          var gear_menu = new Menu ();          var section = new Menu (); diff --git a/src/book.vala b/src/book.vala index 6db2952..798fe98 100644 --- a/src/book.vala +++ b/src/book.vala @@ -136,10 +136,10 @@ public class Book : Object          return pages.index (page);      } -    public async void save_async (string t, int q, File f, ProgressionCallback? p, Cancellable? c) throws Error +    public async void save_async (string mime_type, int quality, File file, ProgressionCallback? progress_cb, Cancellable? cancellable = null) throws Error      {          var book_saver = new BookSaver (); -        yield book_saver.save_async (this, t, q, f, p, c); +        yield book_saver.save_async (this, mime_type, quality, file, progress_cb, cancellable);      }  } @@ -160,7 +160,7 @@ private class BookSaver       * distributes all encode tasks to other threads then yield so       * the ui can continue operating. The method then return once saving       * is completed, cancelled, or failed */ -    public async void save_async (Book book, string type, int quality, File file, ProgressionCallback? progression_callback, Cancellable? cancellable) throws Error +    public async void save_async (Book book, string mime_type, int quality, File file, ProgressionCallback? progression_callback, Cancellable? cancellable) throws Error      {          var timer = new Timer (); @@ -184,20 +184,20 @@ private class BookSaver          /* Configure an encoder */          ThreadPoolFunc<EncodeTask>? encode_delegate = null; -        switch (type) +        switch (mime_type)          { -        case "jpeg": +        case "image/jpeg":              encode_delegate = encode_jpeg;              break; -        case "png": +        case "image/png":              encode_delegate = encode_png;              break;  #if HAVE_WEBP -        case "webp": +        case "image/webp":              encode_delegate = encode_webp;              break;  #endif -        case "pdf": +        case "application/pdf":              encode_delegate = encode_pdf;              break;          } @@ -205,16 +205,16 @@ private class BookSaver          /* Configure a writer */          ThreadFunc<Error?>? write_delegate = null; -        switch (type) +        switch (mime_type)          { -        case "jpeg": -        case "png": +        case "image/jpeg": +        case "image/png":  #if HAVE_WEBP -        case "webp": +        case "image/webp":  #endif              write_delegate = write_multifile;              break; -        case "pdf": +        case "application/pdf":              write_delegate = write_pdf;              break;          } diff --git a/src/help-overlay.ui b/src/help-overlay.ui index b1a0127..105d876 100644 --- a/src/help-overlay.ui +++ b/src/help-overlay.ui @@ -136,7 +136,14 @@              <child>                <object class="GtkShortcutsShortcut">                  <property name="visible">1</property> -                <property name="accelerator"><ctrl>F1</property> +                <property name="accelerator">F10</property> +                <property name="title" translatable="yes" context="shortcut window">Open menu</property> +              </object> +            </child> +            <child> +              <object class="GtkShortcutsShortcut"> +                <property name="visible">1</property> +                <property name="accelerator"><ctrl>question</property>                  <property name="title" translatable="yes" context="shortcut window">Keyboard shortcuts</property>                </object>              </child> diff --git a/src/page-view.vala b/src/page-view.vala index 91a2c82..90a8071 100644 --- a/src/page-view.vala +++ b/src/page-view.vala @@ -45,7 +45,9 @@ public class PageView : Object          }      } -    private int border_width = 1; +    private int ruler_width = 8; + +    private int border_width = 2;      /* True if image needs to be regenerated */      private bool update_image = true; @@ -508,12 +510,12 @@ public class PageView : Object      private int get_preview_width ()      { -        return width_ - border_width * 2; +        return width_ - (border_width + ruler_width) * 2;      }      private int get_preview_height ()      { -        return height_ - border_width * 2; +        return height_ - (border_width + ruler_width) * 2;      }      private void update_page_view () @@ -569,10 +571,10 @@ public class PageView : Object          var cy = page.crop_y;          var cw = page.crop_width;          var ch = page.crop_height; -        var dx = page_to_screen_x (cx); -        var dy = page_to_screen_y (cy); -        var dw = page_to_screen_x (cw); -        var dh = page_to_screen_y (ch); +        var dx = page_to_screen_x (cx) + border_width + ruler_width; +        var dy = page_to_screen_y (cy) + border_width + ruler_width; +        var dw = page_to_screen_x (cw) + border_width + ruler_width; +        var dh = page_to_screen_y (ch) + border_width + ruler_width;          var ix = x - dx;          var iy = y - dy; @@ -633,7 +635,7 @@ public class PageView : Object              selected_crop_x = page.crop_x;              selected_crop_y = page.crop_y;              selected_crop_w = page.crop_width; -            selected_crop_h = page.crop_height;; +            selected_crop_h = page.crop_height;          }      } @@ -831,19 +833,79 @@ public class PageView : Object          context.set_line_width (1);          context.translate (x_offset, y_offset); +        /* Draw image */ +        context.translate (border_width + ruler_width, border_width + ruler_width); +        Gdk.cairo_set_source_pixbuf (context, image, 0, 0); +        context.paint (); +          /* Draw page border */          context.set_source_rgb (0, 0, 0);          context.set_line_width (border_width); -        context.rectangle ((double)border_width / 2, -                           (double)border_width / 2, -                           width_ - border_width, -                           height_ - border_width); + +        context.rectangle (0, +                           0.0, +                           w, +                           h);          context.stroke (); -        /* Draw image */ -        context.translate (border_width, border_width); -        Gdk.cairo_set_source_pixbuf (context, image, 0, 0); -        context.paint (); +        /* Draw horizontal ruler */ +        context.set_line_width (1); +        var ruler_tick = 0; +        var line = 0.0; +        var big_ruler_tick = 5; + +        while (ruler_tick <= page.width) +        { +            line = page_to_screen_x (ruler_tick) + 0.5; +            if (big_ruler_tick == 5) +            { +                context.move_to (line, 0); +                context.line_to (line, -ruler_width); +                context.move_to (line, h); +                context.line_to (line, h + ruler_width); +                big_ruler_tick = 0; +            } +            else +            { +                context.move_to (line, -2); +                context.line_to (line, -5); +                context.move_to (line, h + 2); +                context.line_to (line, h + 5); +            } +            ruler_tick = ruler_tick + page.dpi/5; +            big_ruler_tick = big_ruler_tick + 1; +        } +        context.stroke (); + +        /* Draw vertical ruler */ +        ruler_tick = 0; +        line = 0.0; +        big_ruler_tick = 5; +        while (ruler_tick <= page.height) +        { +            line = page_to_screen_y (ruler_tick) + 0.5; + +            if (big_ruler_tick == 5) +            { +                context.move_to (0, line); +                context.line_to (-ruler_width, line); + +                context.move_to (w, line); +                context.line_to (w + ruler_width, line); +                big_ruler_tick = 0; +            } +            else +            { +                context.move_to (-2, line); +                context.line_to (-5, line); + +                context.move_to (w + 2, line); +                context.line_to (w + 5, line); +            } +            ruler_tick = ruler_tick + page.dpi/5; +            big_ruler_tick = big_ruler_tick + 1; +        } +        context.stroke ();          /* Draw scan line */          if (page.is_scanning && page.scan_line > 0) @@ -907,9 +969,19 @@ public class PageView : Object              context.fill ();              /* Show new edge */ -            context.rectangle (dx - 1.5, dy - 1.5, dw + 3, dh + 3);              context.set_source_rgb (1.0, 1.0, 1.0); +            context.move_to (-border_width, dy - 1.5); +            context.line_to (border_width + w, dy - 1.5); +            context.move_to (-border_width, dy + dh + 1.5); +            context.line_to (border_width + w, dy + dh + 1.5); +            context.stroke (); + +            context.move_to (dx - 1.5, -border_width); +            context.line_to (dx - 1.5, border_width + h); +            context.move_to (dx + dw + 1.5, -border_width); +            context.line_to (dx + dw + 1.5, border_width + h);              context.stroke (); +              context.rectangle (dx - 0.5, dy - 0.5, dw + 1, dh + 1);              context.set_source_rgb (0.0, 0.0, 0.0);              context.stroke (); diff --git a/src/scanner.vala b/src/scanner.vala index dc58f14..becb9fa 100644 --- a/src/scanner.vala +++ b/src/scanner.vala @@ -429,7 +429,7 @@ public class Scanner : Object              return false;          var status = Sane.control_option (handle, option_index, Sane.Action.SET_AUTO, null, null); -        debug ("sane_control_option (%d, SANE_ACTION_SET_AUTO) -> %s", (int) option_index, Sane.status_to_string (status)); +        debug ("sane_control_option (%d, SANE_ACTION_SET_AUTO, %s=auto) -> %s", (int) option_index, option.name, Sane.status_to_string (status));          if (status != Sane.Status.GOOD)              warning ("Error setting default option %s: %s", option.name, Sane.strstatus(status)); @@ -443,7 +443,7 @@ public class Scanner : Object          Sane.Bool v = (Sane.Bool) value;          var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, &v, null);          result = (bool) v; -        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %s) -> (%s, %s)", (int) option_index, value ? "SANE_TRUE" : "SANE_FALSE", Sane.status_to_string (status), result ? "SANE_TRUE" : "SANE_FALSE"); +        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %s=%s) -> (%s, %s)", (int) option_index, option.name, value ? "SANE_TRUE" : "SANE_FALSE", Sane.status_to_string (status), result ? "SANE_TRUE" : "SANE_FALSE");      }      private void set_int_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index, int value, out int result) @@ -480,7 +480,7 @@ public class Scanner : Object          }          var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, &v, null); -        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %d) -> (%s, %d)", (int) option_index, value, Sane.status_to_string (status), (int) v); +        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %s=%d) -> (%s, %d)", (int) option_index, option.name, value, Sane.status_to_string (status), (int) v);          result = (int) v;      } @@ -520,7 +520,7 @@ public class Scanner : Object          v_fixed = Sane.FIX (v);          var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, &v_fixed, null); -        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %f) -> (%s, %f)", (int) option_index, value, Sane.status_to_string (status), Sane.UNFIX (v_fixed)); +        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %s=%f) -> (%s, %f)", (int) option_index, option.name, value, Sane.status_to_string (status), Sane.UNFIX (v_fixed));          result = Sane.UNFIX (v_fixed);      } @@ -550,9 +550,9 @@ public class Scanner : Object          var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, &option.range.max, null);          if (option.type == Sane.ValueType.FIXED) -            debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, option.range.max=%f) -> (%s)", (int) option_index, Sane.UNFIX (option.range.max), Sane.status_to_string (status)); +            debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %s=option.range.max=%f) -> (%s)", (int) option_index, option.name, Sane.UNFIX (option.range.max), Sane.status_to_string (status));          else -            debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, option.range.max=%d) -> (%s)", (int) option_index, (int) option.range.max, Sane.status_to_string (status)); +            debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %s=option.range.max=%d) -> (%s)", (int) option_index, option.name, (int) option.range.max, Sane.status_to_string (status));      }      private bool set_string_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index, string value, out string result) @@ -568,7 +568,7 @@ public class Scanner : Object          s[i] = '\0';          var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, s, null);          result = (string) s; -        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, \"%s\") -> (%s, \"%s\")", (int) option_index, value, Sane.status_to_string (status), result); +        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, %s=\"%s\") -> (%s, \"%s\")", (int) option_index, option.name, value, Sane.status_to_string (status), result);          return status == Sane.Status.GOOD;      } @@ -918,7 +918,6 @@ public class Scanner : Object              option = get_option_by_name (handle, Sane.NAME_SCAN_SOURCE, out index);              if (option == null)              { -                 debug ("SCAN_SOURCE not available, trying alternative \"doc-source\"");                   option = get_option_by_name (handle, "doc-source", out index); /* Samsung unified driver. LP: #892915 */              }              if (option != null) @@ -932,7 +931,7 @@ public class Scanner : Object                      "FlatBed",                      "Normal",                      Sane.I18N ("Normal"), -                    "Document Table" /* Epson scanners, eg. ET-3760 */  +                    "Document Table" /* Epson scanners, eg. ET-3760 */                  };                  string[] adf_sources = @@ -1135,7 +1134,12 @@ public class Scanner : Object                  else                      set_option_to_max (handle, option, index);              } - +            if (job.page_width == 0) /* #90 Fix automatic mode for Epson scanners */ +            { +                option = get_option_by_name (handle, "scan-area", out index); +                if (option != null) +                    set_string_option (handle, option, index, "Maximum", null); +            }              /* Set page size */              option = get_option_by_name (handle, Sane.NAME_PAGE_WIDTH, out index);              if (option != null && job.page_width > 0.0) @@ -1147,40 +1151,34 @@ public class Scanner : Object              option = get_option_by_name (handle, Sane.NAME_BRIGHTNESS, out index);              if (option != null)              { -                if (job.brightness != 0) +                if (option.type == Sane.ValueType.FIXED)                  { -                    if (option.type == Sane.ValueType.FIXED) -                    { -                        var brightness = scale_fixed (-100, 100, option, job.brightness); -                        set_fixed_option (handle, option, index, brightness, null); -                    } -                    else if (option.type == Sane.ValueType.INT) -                    { -                        var brightness = scale_int (-100, 100, option, job.brightness); -                        set_int_option (handle, option, index, brightness, null); -                    } -                    else -                        warning ("Unable to set brightness, please file a bug"); +                    var brightness = scale_fixed (-100, 100, option, job.brightness); +                    set_fixed_option (handle, option, index, brightness, null);                  } +                else if (option.type == Sane.ValueType.INT) +                { +                    var brightness = scale_int (-100, 100, option, job.brightness); +                    set_int_option (handle, option, index, brightness, null); +                } +                else +                    warning ("Unable to set brightness, please file a bug");              }              option = get_option_by_name (handle, Sane.NAME_CONTRAST, out index);              if (option != null)              { -                if (job.contrast != 0) +                if (option.type == Sane.ValueType.FIXED)                  { -                    if (option.type == Sane.ValueType.FIXED) -                    { -                        var contrast = scale_fixed (-100, 100, option, job.contrast); -                        set_fixed_option (handle, option, index, contrast, null); -                    } -                    else if (option.type == Sane.ValueType.INT) -                    { -                        var contrast = scale_int (-100, 100, option, job.contrast); -                        set_int_option (handle, option, index, contrast, null); -                    } -                    else -                        warning ("Unable to set contrast, please file a bug"); +                    var contrast = scale_fixed (-100, 100, option, job.contrast); +                    set_fixed_option (handle, option, index, contrast, null); +                } +                else if (option.type == Sane.ValueType.INT) +                { +                    var contrast = scale_int (-100, 100, option, job.contrast); +                    set_int_option (handle, option, index, contrast, null);                  } +                else +                    warning ("Unable to set contrast, please file a bug");              }              /* Test scanner options (hoping will not effect other scanners...) */ @@ -1294,6 +1292,16 @@ public class Scanner : Object                      /* Error displayed when no documents at the start of scanning */                      _("Document feeder empty"));          } +        else if (status == Sane.Status.NO_MEM) +        { +            fail_scan (status, +                /* Out of memory error message with help instruction. +                   Message written in Pango text markup language, +                   A carriage return makes a line break, <tt> tag makes a monospace font */ +                _("Insufficient memory to perform scan.\n" + +                  "Try to decrease <tt>Resolution</tt> or <tt>Page Size</tt> in <tt>Preferences</tt> menu. " + +                  "For some scanners when scanning in high resolution, the scan size is restricted.")); +        }          else if (status == Sane.Status.DEVICE_BUSY)          {              /* If device is busy don't interrupt, but keep waiting for scanner */ diff --git a/src/simple-scan.vala b/src/simple-scan.vala index 771dc82..3f495e5 100644 --- a/src/simple-scan.vala +++ b/src/simple-scan.vala @@ -54,6 +54,7 @@ public class SimpleScan : Gtk.Application          book = app.book;          app.start_scan.connect (scan_cb);          app.stop_scan.connect (cancel_cb); +        app.redetect.connect (redetect_cb);          scanner = Scanner.get_instance ();          scanner.update_devices.connect (update_scan_devices_cb); @@ -542,6 +543,217 @@ public class SimpleScan : Gtk.Application        0x04f960a9, /* ADS-1600W */      }; +    /* Taken from backend/pixma/pixma_mp150.c pixma_mp730.c pixma_mp750.c pixma_mp800.c in the pixma SANE backend repository */ +    /* Canon Pixma IDs extracted using the following Python script +      import sys +      for f in sys.argv: +        for l in open(f, "r").readlines(): +          tokens=l.split () +          if len (tokens) >= 3 and tokens[0].startswith("#define") and tokens[1].endswith("_PID") and tokens[2].startswith("0x") and not tokens[2].endswith("ffff"): +            print ( "0x04a9" + tokens[2][2:] + ", /* " +  tokens[1][:-4] + " * /") +    */ +    private const uint32 pixma_devices[] = { +      0x04a91709, /* MP150 */ +      0x04a9170a, /* MP170 */ +      0x04a9170b, /* MP450 */ +      0x04a9170c, /* MP500 */ +      0x04a91712, /* MP530 */ +      0x04a91714, /* MP160 */ +      0x04a91715, /* MP180 */ +      0x04a91716, /* MP460 */ +      0x04a91717, /* MP510 */ +      0x04a91718, /* MP600 */ +      0x04a91719, /* MP600R */ +      0x04a9172b, /* MP140 */ +      0x04a9171c, /* MX7600 */ +      0x04a91721, /* MP210 */ +      0x04a91722, /* MP220 */ +      0x04a91723, /* MP470 */ +      0x04a91724, /* MP520 */ +      0x04a91725, /* MP610 */ +      0x04a91727, /* MX300 */ +      0x04a91728, /* MX310 */ +      0x04a91729, /* MX700 */ +      0x04a9172c, /* MX850 */ +      0x04a9172e, /* MP630 */ +      0x04a9172f, /* MP620 */ +      0x04a91730, /* MP540 */ +      0x04a91731, /* MP480 */ +      0x04a91732, /* MP240 */ +      0x04a91733, /* MP260 */ +      0x04a91734, /* MP190 */ +      0x04a91735, /* MX860 */ +      0x04a91736, /* MX320 */ +      0x04a91737, /* MX330 */ +      0x04a9173a, /* MP250 */ +      0x04a9173b, /* MP270 */ +      0x04a9173c, /* MP490 */ +      0x04a9173d, /* MP550 */ +      0x04a9173e, /* MP560 */ +      0x04a9173f, /* MP640 */ +      0x04a91741, /* MX340 */ +      0x04a91742, /* MX350 */ +      0x04a91743, /* MX870 */ +      0x04a91746, /* MP280 */ +      0x04a91747, /* MP495 */ +      0x04a91748, /* MG5100 */ +      0x04a91749, /* MG5200 */ +      0x04a9174a, /* MG6100 */ +      0x04a9174d, /* MX360 */ +      0x04a9174e, /* MX410 */ +      0x04a9174f, /* MX420 */ +      0x04a91750, /* MX880 */ +      0x04a91751, /* MG2100 */ +      0x04a91752, /* MG3100 */ +      0x04a91753, /* MG4100 */ +      0x04a91754, /* MG5300 */ +      0x04a91755, /* MG6200 */ +      0x04a91757, /* MP493 */ +      0x04a91758, /* E500 */ +      0x04a91759, /* MX370 */ +      0x04a9175B, /* MX430 */ +      0x04a9175C, /* MX510 */ +      0x04a9175D, /* MX710 */ +      0x04a9175E, /* MX890 */ +      0x04a9175A, /* E600 */ +      0x04a91763, /* MG4200 */ +      0x04a9175F, /* MP230 */ +      0x04a91765, /* MG6300 */ +      0x04a91760, /* MG2200 */ +      0x04a91761, /* E510 */ +      0x04a91762, /* MG3200 */ +      0x04a91764, /* MG5400 */ +      0x04a91766, /* MX390 */ +      0x04a91767, /* E610 */ +      0x04a91768, /* MX450 */ +      0x04a91769, /* MX520 */ +      0x04a9176a, /* MX720 */ +      0x04a9176b, /* MX920 */ +      0x04a9176c, /* MG2400 */ +      0x04a9176d, /* MG2500 */ +      0x04a9176e, /* MG3500 */ +      0x04a9176f, /* MG6500 */ +      0x04a91770, /* MG6400 */ +      0x04a91771, /* MG5500 */ +      0x04a91772, /* MG7100 */ +      0x04a91774, /* MX470 */ +      0x04a91775, /* MX530 */ +      0x04a91776, /* MB5000 */ +      0x04a91777, /* MB5300 */ +      0x04a91778, /* MB2000 */ +      0x04a91779, /* MB2300 */ +      0x04a9177a, /* E400 */ +      0x04a9177b, /* E560 */ +      0x04a9177c, /* MG7500 */ +      0x04a9177e, /* MG6600 */ +      0x04a9177f, /* MG5600 */ +      0x04a91780, /* MG2900 */ +      0x04a91788, /* E460 */ +      0x04a91787, /* MX490 */ +      0x04a91789, /* E480 */ +      0x04a9178a, /* MG3600 */ +      0x04a9178b, /* MG7700 */ +      0x04a9178c, /* MG6900 */ +      0x04a9178d, /* MG6800 */ +      0x04a9178e, /* MG5700 */ +      0x04a91792, /* MB2700 */ +      0x04a91793, /* MB2100 */ +      0x04a91794, /* G3000 */ +      0x04a91795, /* G2000 */ +      0x04a9179f, /* TS9000 */ +      0x04a91800, /* TS8000 */ +      0x04a91801, /* TS6000 */ +      0x04a91802, /* TS5000 */ +      0x04a9180b, /* MG3000 */ +      0x04a9180c, /* E470 */ +      0x04a9181e, /* E410 */ +      0x04a9181d, /* G4000 */ +      0x04a91822, /* TS6100 */ +      0x04a91825, /* TS5100 */ +      0x04a91827, /* TS3100 */ +      0x04a91828, /* E3100 */ +      0x04a9178f, /* MB5400 */ +      0x04a91790, /* MB5100 */ +      0x04a91820, /* TS9100 */ +      0x04a91823, /* TR8500 */ +      0x04a91824, /* TR7500 */ +      0x04a9185c, /* TS9500 */ +      0x04a91912, /* LIDE400 */ +      0x04a91913, /* LIDE300 */ +      0x04a91821, /* TS8100 */ +      0x04a9183a, /* G2010 */ +      0x04a9183b, /* G3010 */ +      0x04a9183d, /* G4010 */ +      0x04a9183e, /* TS9180 */ +      0x04a9183f, /* TS8180 */ +      0x04a91840, /* TS6180 */ +      0x04a91841, /* TR8580 */ +      0x04a91842, /* TS8130 */ +      0x04a91843, /* TS6130 */ +      0x04a91844, /* TR8530 */ +      0x04a91845, /* TR7530 */ +      0x04a91846, /* XK50 */ +      0x04a91847, /* XK70 */ +      0x04a91854, /* TR4500 */ +      0x04a91855, /* E4200 */ +      0x04a91856, /* TS6200 */ +      0x04a91857, /* TS6280 */ +      0x04a91858, /* TS6230 */ +      0x04a91859, /* TS8200 */ +      0x04a9185a, /* TS8280 */ +      0x04a9185b, /* TS8230 */ +      0x04a9185d, /* TS9580 */ +      0x04a9185e, /* TR9530 */ +      0x04a91863, /* G7000 */ +      0x04a91865, /* G6000 */ +      0x04a91866, /* G6080 */ +      0x04a91869, /* GM4000 */ +      0x04a91873, /* XK80 */ +      0x04a9188b, /* TS5300 */ +      0x04a9188c, /* TS5380 */ +      0x04a9188d, /* TS6300 */ +      0x04a9188e, /* TS6380 */ +      0x04a9188f, /* TS7330 */ +      0x04a91890, /* TS8300 */ +      0x04a91891, /* TS8380 */ +      0x04a91892, /* TS8330 */ +      0x04a91893, /* XK60 */ +      0x04a91894, /* TS6330 */ +      0x04a918a2, /* TS3300 */ +      0x04a918a3, /* E3300 */ +      0x04a9261f, /* MP10 */ +      0x04a9262f, /* MP730 */ +      0x04a92630, /* MP700 */ +      0x04a92635, /* MP5 */ +      0x04a9263c, /* MP360 */ +      0x04a9263d, /* MP370 */ +      0x04a9263e, /* MP390 */ +      0x04a9263f, /* MP375R */ +      0x04a9264c, /* MP740 */ +      0x04a9264d, /* MP710 */ +      0x04a9265d, /* MF5730 */ +      0x04a9265e, /* MF5750 */ +      0x04a9265f, /* MF5770 */ +      0x04a92660, /* MF3110 */ +      0x04a926e6, /* IR1020 */ +      0x04a91706, /* MP750 */ +      0x04a91708, /* MP760 */ +      0x04a91707, /* MP780 */ +      0x04a9170d, /* MP800 */ +      0x04a9170e, /* MP800R */ +      0x04a91713, /* MP830 */ +      0x04a9171a, /* MP810 */ +      0x04a9171b, /* MP960 */ +      0x04a91726, /* MP970 */ +      0x04a91901, /* CS8800F */ +      0x04a9172d, /* MP980 */ +      0x04a91740, /* MP990 */ +      0x04a91908, /* CS9000F */ +      0x04a9174b, /* MG8100 */ +      0x04a91756, /* MG8200 */ +      0x04a9190d, /* CS9000F_MII */ +    }; +      /* Taken from uld/noarch/oem.conf in the Samsung SANE driver */      private const uint32 samsung_devices[] = { 0x04e83425, 0x04e8341c, 0x04e8342a, 0x04e8343d, 0x04e83456, 0x04e8345a, 0x04e83427, 0x04e8343a, 0x04e83428, 0x04e8343b, 0x04e83455, 0x04e83421, 0x04e83439, 0x04e83444, 0x04e8343f, 0x04e8344e, 0x04e83431, 0x04e8345c, 0x04e8344d, 0x04e83462, 0x04e83464, 0x04e83461, 0x04e83460, 0x04e8340e, 0x04e83435,                                                 0x04e8340f, 0x04e83441, 0x04e8344f, 0x04e83413, 0x04e8341b, 0x04e8342e, 0x04e83426, 0x04e8342b, 0x04e83433, 0x04e83440, 0x04e83434, 0x04e8345b, 0x04e83457, 0x04e8341f, 0x04e83453, 0x04e8344b, 0x04e83409, 0x04e83412, 0x04e83419, 0x04e8342c, 0x04e8343c, 0x04e83432, 0x04e8342d, 0x04e83430, 0x04e8342f, @@ -549,6 +761,10 @@ public class SimpleScan : Gtk.Application                                                 0x04e8347c, 0x04e8347e, 0x04e83481, 0x04e83482, 0x04e83331, 0x04e83332, 0x04e83483, 0x04e83484, 0x04e83485, 0x04e83478, 0x04e83325, 0x04e83327, 0x04e8346f, 0x04e83477, 0x04e83324, 0x04e83326, 0x04e83486, 0x04e83487, 0x04e83489      }; +    /* Taken from uld/noarch/oem.conf in the HP/Samsung SANE driver +       These devices are rebranded Samsung Multifunction Printers. */ +    private const uint32 smfp_devices[] = { 0x03F0AA2A, 0x03F0CE2A, 0x03F0C02A, 0x03F0EB2A, 0x03F0F22A }; +      /* Taken from /usr/share/hplip/data/models/models.dat in the HPAIO driver */      private const uint32 hpaio_devices[] = {        0x04f92311, /* HP Officejet d125xi All-in-One Printer */ @@ -1236,6 +1452,68 @@ public class SimpleScan : Gtk.Application      /* Taken from epkowa.desc from iscan-data package for Epson driver */      private const uint32 epkowa_devices[] = { 0x04b80101, 0x04b80102, 0x04b80103, 0x04b80104, 0x04b80105, 0x04b80106, 0x04b80107, 0x04b80108, 0x04b80109, 0x04b8010a, 0x04b8010b, 0x04b8010c, 0x04b8010d, 0x04b8010e, 0x04b8010f, 0x04b80110, 0x04b80112, 0x04b80114, 0x04b80116, 0x04b80118, 0x04b80119, 0x04b8011a, 0x04b8011b, 0x04b8011c, 0x04b8011d, 0x04b8011e, 0x04b8011f, 0x04b80120, 0x04b80121, 0x04b80122, 0x04b80126, 0x04b80128, 0x04b80129, 0x04b8012a, 0x04b8012b, 0x04b8012c, 0x04b8012d, 0x04b8012e, 0x04b8012f, 0x04b80130, 0x04b80131, 0x04b80133, 0x04b80135, 0x04b80136, 0x04b80137, 0x04b80138, 0x04b8013a, 0x04b8013b, 0x04b8013c, 0x04b8013d, 0x04b80142, 0x04b80143, 0x04b80144, 0x04b80147, 0x04b8014a, 0x04b8014b, 0x04b80151, 0x04b80153, 0x04b80801, 0x04b80802, 0x04b80805, 0x04b80806, 0x04b80807, 0x04b80808, 0x04b8080a, 0x04b8080c, 0x04b8080d, 0x04b8080e, 0x04b8080f, 0x04b80810, 0x04b80811, 0x04b80813, 0x04b80814, 0x04b80815, 0x04b80817, 0x04b80818, 0x04b80819, 0x04b8081a, 0x04b8081c, 0x04b8081d, 0x04b8081f, 0x04b80820, 0x04b80821, 0x04b80827, 0x04b80828, 0x04b80829, 0x04b8082a, 0x04b8082b, 0x04b8082e, 0x04b8082f, 0x04b80830, 0x04b80831, 0x04b80833, 0x04b80834, 0x04b80835, 0x04b80836, 0x04b80837, 0x04b80838, 0x04b80839, 0x04b8083a, 0x04b8083c, 0x04b8083f, 0x04b80841, 0x04b80843, 0x04b80844, 0x04b80846, 0x04b80847, 0x04b80848, 0x04b80849, 0x04b8084a, 0x04b8084c, 0x04b8084d, 0x04b8084f, 0x04b80850, 0x04b80851, 0x04b80852, 0x04b80853, 0x04b80854, 0x04b80855, 0x04b80856, 0x04b8085c, 0x04b8085d, 0x04b8085e, 0x04b8085f, 0x04b80860, 0x04b80861, 0x04b80862, 0x04b80863, 0x04b80864, 0x04b80865, 0x04b80866, 0x04b80869, 0x04b8086a, 0x04b80870, 0x04b80871, 0x04b80872, 0x04b80873, 0x04b80878, 0x04b80879, 0x04b8087b, 0x04b8087c, 0x04b8087d, 0x04b8087e, 0x04b8087f, 0x04b80880, 0x04b80881, 0x04b80883, 0x04b80884, 0x04b80885, 0x04b8088f, 0x04b80890, 0x04b80891, 0x04b80892, 0x04b80893, 0x04b80894, 0x04b80895, 0x04b80896, 0x04b80897, 0x04b80898, 0x04b80899, 0x04b8089a, 0x04b8089b, 0x04b8089c, 0x04b8089d, 0x04b8089e, 0x04b8089f, 0x04b808a0, 0x04b808a1, 0x04b808a5, 0x04b808a6, 0x04b808a8, 0x04b808a9, 0x04b808aa, 0x04b808ab, 0x04b808ac, 0x04b808ad, 0x04b808ae, 0x04b808af, 0x04b808b0, 0x04b808b3, 0x04b808b4, 0x04b808b5, 0x04b808b6, 0x04b808b7, 0x04b808b8, 0x04b808b9, 0x04b808bd, 0x04b808be, 0x04b808bf, 0x04b808c0, 0x04b808c1, 0x04b808c3, 0x04b808c4, 0x04b808c5, 0x04b808c6, 0x04b808c7, 0x04b808c8, 0x04b808c9, 0x04b808ca, 0x04b808cd, 0x04b808d0 }; + +    /* Taken from /usr/local/lexmark/unix_scan_drivers/etc/lexmark_nscan.conf */ +    /* Lexmark IDs extracted using command: +     * grep -r "usb .* /usr" --no-filename --only-matching | sed 's/usb //' | sed 's/ 0x//' | sed 's/ \/usr/,/' +     */ +    private const uint32 lexmark_nscan_devices[] = { +    0x043d0279, +    0x043d027a, +    0x043d01D6, +    0x043d01D7, +    0x043d01D8, +    0x043d01DC, +    0x043d01DE, +    0x043d01E0, +    0x043d01FA, +    0x043d01FB, +    0x043d01FC, +    0x043d01FD, +    0x043d01FE, +    0x043d01FF, +    0x043d01F4, +    0x043d0120, +    0x043d0121, +    0x043d0128, +    0x043d014F, +    0x043d0149, +    0x043d0152, +    0x043d0168, +    0x043d0169, +    0x043d016A, +    0x043d012D, +    0x043d01C4, +    0x043d01C5, +    0x043d01C6, +    0x043d01CF, +    0x043d01D0, +    0x043d01D1, +    0x043d01DB, +    0x043d01ED, +    0x043d01F1, +    0x043d01F5, +    0x043d0222, +    0x043d0223, +    0x043d0227, +    0x043d0228, +    0x043d022A, +    0x043d022B, +    0x043d022F, +    0x043d0230, +    0x043d0231, +    0x043d0234, +    0x043d0235, +    0x043d0244, +    0x043d0245, +    0x043d0246, +    0x043d0247, +    0x043d0248, +    0x043d024A, +    0x043d024E, +    0x043d024F +    }; +      /* Brother IDs extracted using the following Python       *       *  import sys @@ -1273,9 +1551,12 @@ public class SimpleScan : Gtk.Application          add_devices (driver_map, brscan2_devices, "brscan2");          add_devices (driver_map, brscan3_devices, "brscan3");          add_devices (driver_map, brscan4_devices, "brscan4"); +        add_devices (driver_map, pixma_devices, "pixma");          add_devices (driver_map, samsung_devices, "samsung"); +        add_devices (driver_map, smfp_devices, "smfp");          add_devices (driver_map, hpaio_devices, "hpaio");          add_devices (driver_map, epkowa_devices, "epkowa"); +        add_devices (driver_map, lexmark_nscan_devices, "lexmark_nscan");          var devices = usb_context.get_devices ();          for (var i = 0; i < devices.length; i++)          { @@ -1547,6 +1828,12 @@ public class SimpleScan : Gtk.Application          scanner.cancel ();      } +    private void redetect_cb (AppWindow ui) +    { +        scanner.redetect (); +    } + +      private static void log_cb (string? log_domain, LogLevelFlags log_level, string message)      {          string prefix; @@ -1695,7 +1982,7 @@ public class SimpleScan : Gtk.Application              }              catch (Error e)              { -                stderr.printf ("Error fixing PDF file: %s", e.message); +                stderr.printf ("Error fixing PDF file: %s\n", e.message);                  return Posix.EXIT_FAILURE;              }              return Posix.EXIT_SUCCESS; @@ -1715,6 +2002,11 @@ public class SimpleScan : Gtk.Application          DirUtils.create_with_parents (path, 0700);          path = Path.build_filename (Environment.get_user_cache_dir (), "simple-scan", "simple-scan.log", null);          log_file = FileStream.open (path, "w"); +        if (log_file == null ) +        { +            stderr.printf ("Error: Unable to open %s file for writing\n", path); +            return Posix.EXIT_FAILURE; +        }          Log.set_default_handler (log_cb);          debug ("Starting %s %s, PID=%i", args[0], VERSION, Posix.getpid ()); | 
