diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/app-window.ui | 697 | ||||
| -rw-r--r-- | src/app-window.vala | 257 | ||||
| -rw-r--r-- | src/autosave-manager.vala | 8 | ||||
| -rw-r--r-- | src/book-view.vala | 2 | ||||
| -rw-r--r-- | src/help-overlay.ui | 27 | ||||
| -rw-r--r-- | src/meson.build | 1 | ||||
| -rw-r--r-- | src/page-icon.vala | 76 | ||||
| -rw-r--r-- | src/page-view.vala | 35 | ||||
| -rw-r--r-- | src/page.vala | 4 | ||||
| -rw-r--r-- | src/preferences-dialog.ui | 73 | ||||
| -rw-r--r-- | src/preferences-dialog.vala | 229 | ||||
| -rw-r--r-- | src/sane-backends.vapi | 10 | ||||
| -rw-r--r-- | src/scanner.vala | 114 | ||||
| -rw-r--r-- | src/simple-scan.vala | 12 | 
14 files changed, 974 insertions, 571 deletions
| diff --git a/src/app-window.ui b/src/app-window.ui index b34c07e..e0e16c0 100644 --- a/src/app-window.ui +++ b/src/app-window.ui @@ -1,12 +1,14 @@  <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.20.0 --> +<!-- Generated with glade 3.22.1 -->  <interface>    <requires lib="gtk+" version="3.12"/>    <object class="GtkMenu" id="page_menu">      <property name="visible">True</property> +    <property name="can_focus">False</property>      <child>        <object class="GtkMenuItem" id="rotate_left_menuitem">          <property name="visible">True</property> +        <property name="can_focus">False</property>          <property name="label" translatable="yes" comments="Menu item to rotate page to left (anti-clockwise)">Rotate _Left</property>          <property name="use_underline">True</property>          <signal name="activate" handler="rotate_left_button_clicked_cb" swapped="no"/> @@ -16,6 +18,7 @@      <child>        <object class="GtkMenuItem" id="rotate_right_menuitem">          <property name="visible">True</property> +        <property name="can_focus">False</property>          <property name="label" translatable="yes" comments="Menu item to rotate page to right (clockwise)">Rotate _Right</property>          <property name="use_underline">True</property>          <signal name="activate" handler="rotate_right_button_clicked_cb" swapped="no"/> @@ -25,14 +28,17 @@      <child>        <object class="GtkMenuItem" id="crop_menuitem">          <property name="visible">True</property> +        <property name="can_focus">False</property>          <property name="label" translatable="yes" comments="Label for page crop submenu">_Crop</property>          <property name="use_underline">True</property>          <child type="submenu">            <object class="GtkMenu" id="crop_menu">              <property name="visible">True</property> +            <property name="can_focus">False</property>              <child>                <object class="GtkRadioMenuItem" id="no_crop_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for no crop">_None</property>                  <property name="use_underline">True</property>                  <property name="active">True</property> @@ -43,6 +49,7 @@              <child>                <object class="GtkRadioMenuItem" id="a4_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for cropping page to A4 size">A_4</property>                  <property name="use_underline">True</property>                  <property name="draw_as_radio">True</property> @@ -53,6 +60,7 @@              <child>                <object class="GtkRadioMenuItem" id="a5_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for cropping page to A5 size">A_5</property>                  <property name="use_underline">True</property>                  <property name="draw_as_radio">True</property> @@ -63,6 +71,7 @@              <child>                <object class="GtkRadioMenuItem" id="a6_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for cropping page to A6 size">A_6</property>                  <property name="use_underline">True</property>                  <property name="draw_as_radio">True</property> @@ -73,6 +82,7 @@              <child>                <object class="GtkRadioMenuItem" id="letter_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for cropping page to US letter size">_Letter</property>                  <property name="use_underline">True</property>                  <property name="draw_as_radio">True</property> @@ -83,6 +93,7 @@              <child>                <object class="GtkRadioMenuItem" id="legal_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for cropping to page to US legal size">Le_gal</property>                  <property name="use_underline">True</property>                  <property name="draw_as_radio">True</property> @@ -93,6 +104,7 @@              <child>                <object class="GtkRadioMenuItem" id="four_by_six_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for cropping page to 4x6 inch">4×6</property>                  <property name="use_underline">True</property>                  <property name="draw_as_radio">True</property> @@ -103,6 +115,7 @@              <child>                <object class="GtkRadioMenuItem" id="a3_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for cropping page to A3">A_3</property>                  <property name="use_underline">True</property>                  <property name="draw_as_radio">True</property> @@ -113,6 +126,7 @@              <child>                <object class="GtkRadioMenuItem" id="custom_crop_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Radio button for cropping to custom page size">_Custom</property>                  <property name="use_underline">True</property>                  <property name="draw_as_radio">True</property> @@ -123,12 +137,14 @@              <child>                <object class="GtkSeparatorMenuItem" id="crop_sep_menuitem">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                </object>              </child>              <child>                <object class="GtkMenuItem" id="crop_rotate_menuitem">                  <property name="visible">True</property>                  <property name="sensitive">False</property> +                <property name="can_focus">False</property>                  <property name="label" translatable="yes" comments="Menu item to rotate the crop area">_Rotate Crop</property>                  <property name="use_underline">True</property>                  <signal name="activate" handler="crop_rotate_menuitem_activate_cb" swapped="no"/> @@ -141,6 +157,7 @@      <child>        <object class="GtkMenuItem" id="page_move_left_menuitem">          <property name="visible">True</property> +        <property name="can_focus">False</property>          <property name="label" translatable="yes" comments="Menu item to move the selected page to the left">Move Left</property>          <signal name="activate" handler="page_move_left_menuitem_activate_cb" swapped="no"/>          <accelerator key="less" signal="activate"/> @@ -149,6 +166,7 @@      <child>        <object class="GtkMenuItem" id="page_move_right_menuitem">          <property name="visible">True</property> +        <property name="can_focus">False</property>          <property name="label" translatable="yes" comments="Menu item to move the selected page to the right">Move Right</property>          <property name="use_underline">True</property>          <signal name="activate" handler="page_move_right_menuitem_activate_cb" swapped="no"/> @@ -160,6 +178,7 @@          <property name="label">gtk-copy</property>          <property name="visible">True</property>          <property name="sensitive">False</property> +        <property name="can_focus">False</property>          <property name="use_underline">True</property>          <property name="use_stock">True</property>          <signal name="activate" handler="copy_to_clipboard_button_clicked_cb" swapped="no"/> @@ -170,6 +189,7 @@        <object class="GtkImageMenuItem" id="page_delete_menuitem">          <property name="label">gtk-delete</property>          <property name="visible">True</property> +        <property name="can_focus">False</property>          <property name="use_underline">True</property>          <property name="use_stock">True</property>          <signal name="activate" handler="page_delete_menuitem_activate_cb" swapped="no"/> @@ -177,147 +197,467 @@        </object>      </child>    </object> -  <template class="AppWindow" parent="GtkApplicationWindow"> -    <property name="title" translatable="yes" comments="Title of scan window">Document Scanner</property> -    <property name="icon_name">org.gnome.SimpleScan</property> -    <signal name="delete-event" handler="window_delete_event_cb" swapped="no"/> +  <object class="GtkListStore" id="device_model"> +    <columns> +      <!-- column-name device_name --> +      <column type="gchararray"/> +      <!-- column-name label --> +      <column type="gchararray"/> +    </columns> +  </object> +  <object class="GtkPopover" id="scan_options_popover"> +    <property name="can_focus">False</property>      <child>        <object class="GtkBox">          <property name="visible">True</property> +        <property name="can_focus">False</property> +        <property name="margin_left">12</property> +        <property name="margin_right">12</property> +        <property name="margin_top">12</property> +        <property name="margin_bottom">12</property>          <property name="orientation">vertical</property> +        <property name="spacing">6</property>          <child> -          <object class="GtkStack" id="stack"> +          <object class="GtkRadioButton" id="scan_single_radio">              <property name="visible">True</property> -            <property name="vexpand">True</property> +            <property name="can_focus">False</property> +            <property name="receives_default">False</property> +            <property name="draw_indicator">False</property> +            <signal name="toggled" handler="scan_single_radio_toggled_cb" swapped="no"/>              <child> -              <object class="GtkAlignment"> +              <object class="GtkBox">                  <property name="visible">True</property> -                <property name="xscale">0</property> -                <property name="yscale">0</property> +                <property name="can_focus">False</property> +                <property name="margin_start">12</property> +                <property name="margin_end">12</property> +                <property name="margin_top">6</property> +                <property name="margin_bottom">6</property> +                <property name="spacing">12</property>                  <child> -                  <object class="GtkBox"> +                  <object class="GtkImage">                      <property name="visible">True</property> -                    <property name="orientation">vertical</property> -                    <property name="spacing">10</property> -                    <child> -                      <object class="GtkImage"> -                        <property name="visible">True</property> -                        <property name="opacity">0.5</property> -                        <property name="pixel_size">120</property> -                        <property name="icon_name">org.gnome.SimpleScan-symbolic</property> -                        <property name="icon_size">6</property> -                      </object> -                    </child> -                    <child> -                      <object class="GtkLabel" id="status_primary_label"> -                        <property name="visible">True</property> -                        <attributes> -                          <attribute name="weight" value="bold"/> -                          <attribute name="scale" value="1.5"/> -                        </attributes> -                        <style> -                          <class name="dim-label"/> -                        </style> -                      </object> -                    </child> -                    <child> -                      <object class="GtkLabel" id="status_secondary_label"> -                        <property name="visible">False</property> -                        <property name="track_visited_links">False</property> -                        <signal name="activate_link" handler="status_label_activate_link_cb" swapped="no"/> -                        <style> -                          <class name="dim-label"/> -                        </style> -                      </object> -                    </child> +                    <property name="can_focus">False</property> +                    <property name="icon_name">scanner-symbolic</property>                    </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">0</property> +                  </packing> +                </child> +                <child> +                  <object class="GtkLabel"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="label" translatable="yes">_Single Page</property> +                    <property name="use_underline">True</property> +                  </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">1</property> +                  </packing>                  </child>                </object> -              <packing> -                <property name="name">startup</property> -              </packing>              </child> +          </object> +          <packing> +            <property name="expand">False</property> +            <property name="fill">True</property> +            <property name="position">0</property> +          </packing> +        </child> +        <child> +          <object class="GtkRadioButton" id="scan_adf_radio"> +            <property name="visible">True</property> +            <property name="can_focus">False</property> +            <property name="receives_default">False</property> +            <property name="draw_indicator">False</property> +            <property name="group">scan_single_radio</property> +            <signal name="toggled" handler="scan_adf_radio_toggled_cb" swapped="no"/>              <child> -              <object class="GtkBox" id="main_vbox"> +              <object class="GtkBox">                  <property name="visible">True</property> -                <property name="orientation">vertical</property> +                <property name="can_focus">False</property> +                <property name="margin_start">12</property> +                <property name="margin_end">12</property> +                <property name="margin_top">6</property> +                <property name="margin_bottom">6</property> +                <property name="spacing">12</property>                  <child> -                  <object class="GtkActionBar" id="action_bar"> +                  <object class="GtkImage">                      <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="icon_name">scan-type-adf-symbolic</property>                    </object>                    <packing> -                    <property name="pack_type">end</property> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">0</property> +                  </packing> +                </child> +                <child> +                  <object class="GtkLabel"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="label" translatable="yes">All Pages From _Feeder</property> +                    <property name="use_underline">True</property> +                  </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">1</property>                    </packing>                  </child>                </object> -              <packing> -                <property name="name">document</property> -              </packing>              </child>            </object> +          <packing> +            <property name="expand">False</property> +            <property name="fill">True</property> +            <property name="position">1</property> +          </packing> +        </child> +        <child> +          <object class="GtkRadioButton" id="scan_batch_radio"> +            <property name="visible">True</property> +            <property name="can_focus">False</property> +            <property name="receives_default">False</property> +            <property name="draw_indicator">False</property> +            <property name="group">scan_single_radio</property> +            <signal name="toggled" handler="scan_batch_radio_toggled_cb" swapped="no"/> +            <child> +              <object class="GtkBox"> +                <property name="visible">True</property> +                <property name="can_focus">False</property> +                <property name="margin_start">12</property> +                <property name="margin_end">12</property> +                <property name="margin_top">6</property> +                <property name="margin_bottom">6</property> +                <property name="spacing">12</property> +                <child> +                  <object class="GtkImage"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="icon_name">scan-type-batch-symbolic</property> +                  </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">0</property> +                  </packing> +                </child> +                <child> +                  <object class="GtkLabel"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="label" translatable="yes">_Multiple Pages From Flatbed</property> +                    <property name="use_underline">True</property> +                  </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">1</property> +                  </packing> +                </child> +              </object> +            </child> +          </object> +          <packing> +            <property name="expand">False</property> +            <property name="fill">True</property> +            <property name="position">2</property> +          </packing> +        </child> +        <child> +          <object class="GtkRadioButton" id="text_radio"> +            <property name="visible">True</property> +            <property name="can_focus">False</property> +            <property name="receives_default">False</property> +            <property name="margin_top">12</property> +            <property name="draw_indicator">False</property> +            <signal name="toggled" handler="text_radio_toggled_cb" swapped="no"/> +            <child> +              <object class="GtkBox"> +                <property name="visible">True</property> +                <property name="can_focus">False</property> +                <property name="margin_start">12</property> +                <property name="margin_end">12</property> +                <property name="margin_top">6</property> +                <property name="margin_bottom">6</property> +                <property name="spacing">12</property> +                <child> +                  <object class="GtkImage"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="icon_name">x-office-document-symbolic</property> +                  </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">0</property> +                  </packing> +                </child> +                <child> +                  <object class="GtkLabel"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="label" translatable="yes">_Text</property> +                    <property name="use_underline">True</property> +                  </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">1</property> +                  </packing> +                </child> +              </object> +            </child> +          </object> +          <packing> +            <property name="expand">False</property> +            <property name="fill">True</property> +            <property name="position">3</property> +          </packing> +        </child> +        <child> +          <object class="GtkRadioButton" id="photo_radio"> +            <property name="visible">True</property> +            <property name="can_focus">False</property> +            <property name="receives_default">False</property> +            <property name="draw_indicator">False</property> +            <property name="group">text_radio</property> +            <signal name="toggled" handler="photo_radio_toggled_cb" swapped="no"/> +            <child> +              <object class="GtkBox"> +                <property name="visible">True</property> +                <property name="can_focus">False</property> +                <property name="margin_start">12</property> +                <property name="margin_end">12</property> +                <property name="margin_top">6</property> +                <property name="margin_bottom">6</property> +                <property name="spacing">12</property> +                <child> +                  <object class="GtkImage"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="icon_name">image-x-generic-symbolic</property> +                  </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">0</property> +                  </packing> +                </child> +                <child> +                  <object class="GtkLabel"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="label" translatable="yes">_Image</property> +                    <property name="use_underline">True</property> +                  </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="position">1</property> +                  </packing> +                </child> +              </object> +            </child> +          </object> +          <packing> +            <property name="expand">False</property> +            <property name="fill">True</property> +            <property name="position">4</property> +          </packing> +        </child> +        <child> +          <object class="GtkButton" id="preferences_button"> +            <property name="label" translatable="yes">_Preferences</property> +            <property name="height_request">40</property> +            <property name="visible">True</property> +            <property name="can_focus">True</property> +            <property name="receives_default">True</property> +            <property name="margin_top">12</property> +            <property name="use_underline">True</property> +            <signal name="clicked" handler="preferences_button_clicked_cb" swapped="no"/> +          </object> +          <packing> +            <property name="expand">False</property> +            <property name="fill">True</property> +            <property name="position">5</property> +          </packing>          </child>        </object>      </child> +  </object> +  <template class="AppWindow" parent="GtkApplicationWindow"> +    <property name="width_request">320</property> +    <property name="height_request">480</property> +    <property name="can_focus">False</property> +    <property name="title" translatable="yes" comments="Title of scan window">Document Scanner</property> +    <property name="icon_name">org.gnome.SimpleScan</property> +    <signal name="delete-event" handler="window_delete_event_cb" swapped="no"/>      <child type="titlebar">        <object class="GtkHeaderBar" id="header_bar">          <property name="visible">True</property> +        <property name="can_focus">False</property>          <property name="vexpand">True</property>          <property name="show_close_button">True</property>          <child>            <object class="GtkBox" id="open_box">              <property name="visible">True</property> +            <property name="can_focus">False</property>              <property name="valign">center</property>              <child>                <object class="GtkButton" id="stop_button"> -                <property name="label" translatable="yes">Stop</property> +                <property name="can_focus">False</property>                  <property name="receives_default">False</property>                  <property name="tooltip_text" translatable="yes" comments="Tooltip for stop button">Stop the current scan</property>                  <property name="use_underline">True</property>                  <signal name="clicked" handler="stop_scan_button_clicked_cb" swapped="no"/> +                <child> +                  <object class="GtkBox"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="spacing">6</property> +                    <child> +                      <object class="GtkSpinner" id="stop_button_spinner"> +                        <property name="visible">True</property> +                        <property name="can_focus">False</property> +                        <property name="active">True</property> +                      </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">0</property> +                      </packing> +                    </child> +                    <child> +                      <object class="GtkLabel"> +                        <property name="visible">True</property> +                        <property name="can_focus">False</property> +                        <property name="label" translatable="yes">S_top</property> +                        <property name="use_underline">True</property> +                        <property name="width_chars">6</property> +                        <property name="xalign">0.33</property> +                      </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">1</property> +                      </packing> +                    </child> +                  </object> +                </child>                  <style>                    <class name="text-button"/>                    <class name="destructive-action"/>                  </style>                </object> +              <packing> +                <property name="expand">False</property> +                <property name="fill">True</property> +                <property name="position">0</property> +              </packing>              </child>              <child>                <object class="GtkButton" id="scan_button"> -                <property name="label" translatable="yes" comments="Label on scan toolbar item">Scan</property>                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="receives_default">False</property>                  <property name="tooltip_text" translatable="yes" comments="Tooltip for scan toolbar button">Scan a single page from the scanner</property>                  <property name="use_underline">True</property>                  <signal name="clicked" handler="scan_button_clicked_cb" swapped="no"/> +                <child> +                  <object class="GtkBox"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="spacing">6</property> +                    <child> +                      <object class="GtkImage" id="scan_options_image"> +                        <property name="visible">True</property> +                        <property name="can_focus">False</property> +                        <property name="icon_name">scanner-symbolic</property> +                      </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">0</property> +                      </packing> +                    </child> +                    <child> +                      <object class="GtkLabel"> +                        <property name="visible">True</property> +                        <property name="can_focus">False</property> +                        <property name="margin_right">1</property> +                        <property name="label" translatable="yes">_Scan</property> +                        <property name="use_underline">True</property> +                        <property name="width_chars">6</property> +                        <property name="xalign">0.33</property> +                      </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">1</property> +                      </packing> +                    </child> +                  </object> +                </child>                  <style>                    <class name="text-button"/>                    <class name="suggested-action"/>                  </style>                </object> +              <packing> +                <property name="expand">False</property> +                <property name="fill">True</property> +                <property name="position">1</property> +              </packing>              </child>              <child>                <object class="GtkMenuButton">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="receives_default">False</property>                  <property name="popover">scan_options_popover</property>                  <child>                    <object class="GtkBox">                      <property name="visible">True</property> +                    <property name="can_focus">False</property>                      <property name="spacing">6</property>                      <child> -                      <object class="GtkImage" id="scan_options_image"> +                      <object class="GtkImage" id="scan_hint_image">                          <property name="visible">True</property> -                        <property name="icon_name">scanner-symbolic</property> +                        <property name="can_focus">False</property> +                        <property name="icon_name">x-office-document-symbolic</property>                        </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">0</property> +                      </packing>                      </child>                      <child>                        <object class="GtkImage">                          <property name="visible">True</property> +                        <property name="can_focus">False</property>                          <property name="icon_name">pan-down-symbolic</property>                        </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">1</property> +                      </packing>                      </child>                    </object>                  </child>                </object> +              <packing> +                <property name="expand">False</property> +                <property name="fill">True</property> +                <property name="position">2</property> +              </packing>              </child>              <style>                <class name="linked"/> @@ -327,11 +667,13 @@          <child>            <object class="GtkMenuButton" id="menu_button">              <property name="visible">True</property> +            <property name="can_focus">False</property>              <property name="receives_default">False</property>              <property name="use_underline">True</property>              <child>                <object class="GtkImage">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="icon_name">open-menu-symbolic</property>                  <property name="icon_size">1</property>                </object> @@ -342,12 +684,14 @@            </object>            <packing>              <property name="pack_type">end</property> +            <property name="position">1</property>            </packing>          </child>          <child>            <object class="GtkButton" id="save_button">              <property name="visible">True</property>              <property name="sensitive">False</property> +            <property name="can_focus">False</property>              <property name="receives_default">False</property>              <property name="tooltip_text" translatable="yes" comments="Tooltip for save toolbar button">Save document to a file</property>              <property name="use_underline">True</property> @@ -355,6 +699,7 @@              <child>                <object class="GtkImage" id="save_image">                  <property name="visible">True</property> +                <property name="can_focus">False</property>                  <property name="icon_name">document-save-symbolic</property>                  <property name="icon_size">1</property>                </object> @@ -365,6 +710,7 @@            </object>            <packing>              <property name="pack_type">end</property> +            <property name="position">2</property>            </packing>          </child>          <style> @@ -372,170 +718,125 @@          </style>        </object>      </child> -  </template> -  <object class="GtkPopover" id="scan_options_popover">      <child>        <object class="GtkBox">          <property name="visible">True</property> +        <property name="can_focus">False</property>          <property name="orientation">vertical</property> -        <property name="margin">12</property> -        <property name="spacing">6</property> -        <child> -          <object class="GtkRadioButton" id="scan_single_radio"> -            <property name="visible">True</property> -            <property name="draw_indicator">False</property> -            <signal name="toggled" handler="scan_single_radio_toggled_cb" swapped="no"/> -            <child> -              <object class="GtkBox"> -                <property name="visible">True</property> -                <property name="spacing">12</property> -                <property name="margin_start">12</property> -                <property name="margin_end">12</property> -                <property name="margin_top">6</property> -                <property name="margin_bottom">6</property> -                <child> -                  <object class="GtkImage"> -                    <property name="visible">True</property> -                    <property name="icon_name">scanner-symbolic</property> -                  </object> -                </child> -                <child> -                  <object class="GtkLabel"> -                    <property name="visible">True</property> -                    <property name="label" translatable="yes">_Single Page</property> -                    <property name="use_underline">True</property> -                  </object> -                </child> -              </object> -            </child> -          </object> -        </child> -        <child> -          <object class="GtkRadioButton" id="scan_adf_radio"> -            <property name="visible">True</property> -            <property name="draw_indicator">False</property> -            <property name="group">scan_single_radio</property> -            <signal name="toggled" handler="scan_adf_radio_toggled_cb" swapped="no"/> -            <child> -              <object class="GtkBox"> -                <property name="visible">True</property> -                <property name="spacing">12</property> -                <property name="margin_start">12</property> -                <property name="margin_end">12</property> -                <property name="margin_top">6</property> -                <property name="margin_bottom">6</property> -                <child> -                  <object class="GtkImage"> -                    <property name="visible">True</property> -                    <property name="icon_name">scan-type-adf-symbolic</property> -                  </object> -                </child> -                <child> -                  <object class="GtkLabel"> -                    <property name="visible">True</property> -                    <property name="label" translatable="yes">All Pages From _Feeder</property> -                    <property name="use_underline">True</property> -                  </object> -                </child> -              </object> -            </child> -          </object> -        </child> -        <child> -          <object class="GtkRadioButton" id="scan_batch_radio"> -            <property name="visible">True</property> -            <property name="draw_indicator">False</property> -            <property name="group">scan_single_radio</property> -            <signal name="toggled" handler="scan_batch_radio_toggled_cb" swapped="no"/> -            <child> -              <object class="GtkBox"> -                <property name="visible">True</property> -                <property name="spacing">12</property> -                <property name="margin_start">12</property> -                <property name="margin_end">12</property> -                <property name="margin_top">6</property> -                <property name="margin_bottom">6</property> -                <child> -                  <object class="GtkImage"> -                    <property name="visible">True</property> -                    <property name="icon_name">scan-type-batch-symbolic</property> -                  </object> -                </child> -                <child> -                  <object class="GtkLabel"> -                    <property name="visible">True</property> -                    <property name="label" translatable="yes">_Multiple Pages From Flatbed</property> -                    <property name="use_underline">True</property> -                  </object> -                </child> -              </object> -            </child> -          </object> -        </child>          <child> -          <object class="GtkRadioButton" id="text_radio"> +          <object class="GtkStack" id="stack">              <property name="visible">True</property> -            <property name="draw_indicator">False</property> -            <property name="margin_top">12</property> -            <signal name="toggled" handler="text_radio_toggled_cb" swapped="no"/> +            <property name="can_focus">False</property> +            <property name="vexpand">True</property>              <child> -              <object class="GtkBox"> +              <object class="GtkAlignment">                  <property name="visible">True</property> -                <property name="spacing">12</property> -                <property name="margin_start">12</property> -                <property name="margin_end">12</property> -                <property name="margin_top">6</property> -                <property name="margin_bottom">6</property> -                <child> -                  <object class="GtkImage"> -                    <property name="visible">True</property> -                    <property name="icon_name">text-x-generic-symbolic</property> -                  </object> -                </child> +                <property name="can_focus">False</property> +                <property name="xscale">0</property> +                <property name="yscale">0</property>                  <child> -                  <object class="GtkLabel"> +                  <object class="GtkBox">                      <property name="visible">True</property> -                    <property name="label" translatable="yes">_Text</property> -                    <property name="use_underline">True</property> +                    <property name="can_focus">False</property> +                    <property name="orientation">vertical</property> +                    <property name="spacing">10</property> +                    <child> +                      <object class="GtkImage"> +                        <property name="visible">True</property> +                        <property name="can_focus">True</property> +                        <property name="has_focus">True</property> +                        <property name="is_focus">True</property> +                        <property name="can_default">True</property> +                        <property name="has_default">True</property> +                        <property name="opacity">0.5</property> +                        <property name="pixel_size">120</property> +                        <property name="icon_name">org.gnome.SimpleScan-symbolic</property> +                        <property name="icon_size">6</property> +                      </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">0</property> +                      </packing> +                    </child> +                    <child> +                      <object class="GtkLabel" id="status_primary_label"> +                        <property name="visible">True</property> +                        <property name="can_focus">False</property> +                        <attributes> +                          <attribute name="weight" value="bold"/> +                          <attribute name="scale" value="1.5"/> +                        </attributes> +                        <style> +                          <class name="dim-label"/> +                        </style> +                      </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">1</property> +                      </packing> +                    </child> +                    <child> +                      <object class="GtkLabel" id="status_secondary_label"> +                        <property name="can_focus">False</property> +                        <property name="track_visited_links">False</property> +                        <signal name="activate-link" handler="status_label_activate_link_cb" swapped="no"/> +                        <style> +                          <class name="dim-label"/> +                        </style> +                      </object> +                      <packing> +                        <property name="expand">False</property> +                        <property name="fill">True</property> +                        <property name="position">2</property> +                      </packing> +                    </child> +                    <child> +                      <object class="GtkComboBox" id="device_combo"> +                        <property name="visible">False</property> +                        <property name="model">device_model</property> +                        <signal name="changed" handler="device_combo_changed_cb" swapped="no"/> +                      </object> +                    </child>                    </object>                  </child>                </object> +              <packing> +                <property name="name">startup</property> +              </packing>              </child> -          </object> -        </child> -        <child> -          <object class="GtkRadioButton" id="photo_radio"> -            <property name="visible">True</property> -            <property name="draw_indicator">False</property> -            <property name="group">text_radio</property> -            <signal name="toggled" handler="photo_radio_toggled_cb" swapped="no"/>              <child> -              <object class="GtkBox"> +              <object class="GtkBox" id="main_vbox">                  <property name="visible">True</property> -                <property name="spacing">12</property> -                <property name="margin_start">12</property> -                <property name="margin_end">12</property> -                <property name="margin_top">6</property> -                <property name="margin_bottom">6</property> -                <child> -                  <object class="GtkImage"> -                    <property name="visible">True</property> -                    <property name="icon_name">image-x-generic-symbolic</property> -                  </object> -                </child> +                <property name="can_focus">False</property> +                <property name="orientation">vertical</property>                  <child> -                  <object class="GtkLabel"> +                  <object class="GtkActionBar" id="action_bar">                      <property name="visible">True</property> -                    <property name="label" translatable="yes">_Image</property> -                    <property name="use_underline">True</property> +                    <property name="can_focus">False</property>                    </object> +                  <packing> +                    <property name="expand">False</property> +                    <property name="fill">True</property> +                    <property name="pack_type">end</property> +                    <property name="position">0</property> +                  </packing>                  </child>                </object> +              <packing> +                <property name="name">document</property> +                <property name="position">1</property> +              </packing>              </child>            </object> +          <packing> +            <property name="expand">False</property> +            <property name="fill">True</property> +            <property name="position">0</property> +          </packing>          </child>        </object>      </child> -  </object> +  </template>  </interface> - diff --git a/src/app-window.vala b/src/app-window.vala index 02f2072..6f2d353 100644 --- a/src/app-window.vala +++ b/src/app-window.vala @@ -44,6 +44,9 @@ public class AppWindow : Gtk.ApplicationWindow      private PreferencesDialog preferences_dialog; +    private bool setting_devices; +    private bool user_selected_device; +      [GtkChild]      private Gtk.HeaderBar header_bar;      [GtkChild] @@ -53,6 +56,10 @@ public class AppWindow : Gtk.ApplicationWindow      [GtkChild]      private Gtk.Label status_primary_label;      [GtkChild] +    private Gtk.ListStore device_model; +    [GtkChild] +    private Gtk.ComboBox device_combo; +    [GtkChild]      private Gtk.Label status_secondary_label;      [GtkChild]      private Gtk.Box main_vbox; @@ -98,6 +105,8 @@ public class AppWindow : Gtk.ApplicationWindow      [GtkChild]      private Gtk.Image scan_options_image;      [GtkChild] +    private Gtk.Image scan_hint_image; +    [GtkChild]      private Gtk.RadioButton scan_single_radio;      [GtkChild]      private Gtk.RadioButton scan_adf_radio; @@ -177,12 +186,6 @@ public class AppWindow : Gtk.ApplicationWindow          set { preferences_dialog.set_page_delay (value); }      } -    public string? selected_device -    { -        owned get { return preferences_dialog.get_selected_device (); } -        set { preferences_dialog.set_selected_device (value); } -    } -      public signal void start_scan (string? device, ScanOptions options);      public signal void stop_scan (); @@ -190,6 +193,11 @@ public class AppWindow : Gtk.ApplicationWindow      {          settings = new Settings ("org.gnome.SimpleScan"); +        var renderer = new Gtk.CellRendererText (); +        renderer.set_property ("xalign", 0.5); +        device_combo.pack_start (renderer, true); +        device_combo.add_attribute (renderer, "text", 1); +          book = new Book ();          book.page_added.connect (page_added_cb);          book.reordered.connect (reordered_cb); @@ -199,19 +207,6 @@ public class AppWindow : Gtk.ApplicationWindow          load ();          clear_document (); -        autosave_manager = new AutosaveManager (); -        autosave_manager.book = book; -        autosave_manager.load (); - -        if (book.n_pages == 0) -            book_needs_saving = false; -        else -        { -            stack.set_visible_child_name ("document"); -            book_view.selected_page = book.get_page (0); -            book_needs_saving = true; -            book_changed_cb (book); -        }      }      ~AppWindow () @@ -255,13 +250,15 @@ public class AppWindow : Gtk.ApplicationWindow              status_primary_label.set_text (/* Label shown when searching for scanners */                                             _("Searching for Scanners…"));              status_secondary_label.visible = false; +            device_combo.visible = false;          } -        else if (selected_device != null) +        else if (get_selected_device () != null)          {              status_primary_label.set_text (/* Label shown when detected a scanner */                                             _("Ready to Scan")); -            status_secondary_label.set_text (preferences_dialog.get_selected_device_label ()); -            status_secondary_label.visible = true; +            status_secondary_label.set_text (get_selected_device_label ()); +            status_secondary_label.visible = false; +            device_combo.visible = true;          }          else if (this.missing_driver != null)          { @@ -270,6 +267,7 @@ public class AppWindow : Gtk.ApplicationWindow              /* Instructions to install driver software */              status_secondary_label.set_markup (_("You need to <a href=\"install-firmware\">install driver software</a> for your scanner."));              status_secondary_label.visible = true; +            device_combo.visible = false;          }          else          { @@ -278,6 +276,7 @@ public class AppWindow : Gtk.ApplicationWindow              /* Hint to user on why there are no scanners detected */              status_secondary_label.set_text (_("Please check your scanner is connected and powered on"));              status_secondary_label.visible = true; +            device_combo.visible = false;          }      } @@ -285,10 +284,162 @@ public class AppWindow : Gtk.ApplicationWindow      {          have_devices = true;          this.missing_driver = missing_driver; -        preferences_dialog.set_scan_devices (devices); + +        setting_devices = true; + +        /* If the user hasn't chosen a scanner choose the best available one */ +        var have_selection = false; +        if (user_selected_device) +            have_selection = device_combo.active >= 0; + +        /* Add new devices */ +        int index = 0; +        Gtk.TreeIter iter; +        foreach (var device in devices) +        { +            int n_delete = -1; + +            /* Find if already exists */ +            if (device_model.iter_nth_child (out iter, null, index)) +            { +                int i = 0; +                do +                { +                    string name; +                    bool matched; + +                    device_model.get (iter, 0, out name, -1); +                    matched = name == device.name; + +                    if (matched) +                    { +                        n_delete = i; +                        break; +                    } +                    i++; +                } while (device_model.iter_next (ref iter)); +            } + +            /* If exists, remove elements up to this one */ +            if (n_delete >= 0) +            { +                int i; + +                /* Update label */ +                device_model.set (iter, 1, device.label, -1); + +                for (i = 0; i < n_delete; i++) +                { +                    device_model.iter_nth_child (out iter, null, index); +#if VALA_0_36 +                    device_model.remove (ref iter); +#else +                    device_model.remove (iter); +#endif +                } +            } +            else +            { +                device_model.insert (out iter, index); +                device_model.set (iter, 0, device.name, 1, device.label, -1); +            } +            index++; +        } + +        /* Remove any remaining devices */ +        while (device_model.iter_nth_child (out iter, null, index)) +#if VALA_0_36 +            device_model.remove (ref iter); +#else +            device_model.remove (iter); +#endif + +        /* Select the previously selected device or the first available device */ +        if (!have_selection) +        { +            var device = settings.get_string ("selected-device"); +            if (device != null && find_scan_device (device, out iter)) +                device_combo.set_active_iter (iter); +            else +                device_combo.set_active (0); +        } + +        setting_devices = false; +          update_scan_status ();      } +    private bool prompt_to_load_autosaved_book () +    { +        var dialog = new Gtk.MessageDialog (this, +                                            Gtk.DialogFlags.MODAL, +                                            Gtk.MessageType.QUESTION, +                                            Gtk.ButtonsType.YES_NO, +                                            /* Contents of dialog that shows if autosaved book should be loaded. */ +                                            _("An autosaved book exists. Do you want to open it?")); +        dialog.set_default_response(Gtk.ResponseType.YES); +        var response = dialog.run (); +        dialog.destroy (); +        return response == Gtk.ResponseType.YES; +    } + +    private string? get_selected_device () +    { +        Gtk.TreeIter iter; + +        if (device_combo.get_active_iter (out iter)) +        { +            string device; +            device_model.get (iter, 0, out device, -1); +            return device; +        } + +        return null; +    } + +    private string? get_selected_device_label () +    { +        Gtk.TreeIter iter; + +        if (device_combo.get_active_iter (out iter)) +        { +            string label; +            device_model.get (iter, 1, out label, -1); +            return label; +        } + +        return null; +    } + +    public void set_selected_device (string device) +    { +        user_selected_device = true; + +        Gtk.TreeIter iter; +        if (!find_scan_device (device, out iter)) +            return; + +        device_combo.set_active_iter (iter); +    } + +    private bool find_scan_device (string device, out Gtk.TreeIter iter) +    { +        bool have_iter = false; + +        if (device_model.get_iter_first (out iter)) +        { +            do +            { +                string d; +                device_model.get (iter, 0, out d, -1); +                if (d == device) +                    have_iter = true; +            } while (!have_iter && device_model.iter_next (ref iter)); +        } + +        return have_iter; +    } +      private string? choose_file_location ()      {          /* Get directory to save to */ @@ -543,7 +694,7 @@ public class AppWindow : Gtk.ApplicationWindow      private async bool prompt_to_save_async (string title, string discard_label)      { -        if (!book_needs_saving) +        if (!book_needs_saving || (book.n_pages == 0))              return true;          var dialog = new Gtk.MessageDialog (this, @@ -624,7 +775,7 @@ public class AppWindow : Gtk.ApplicationWindow      {          status_primary_label.set_text (/* Label shown when scan started */                                         _("Contacting scanner…")); -        start_scan (selected_device, options); +        start_scan (get_selected_device (), options);      }      private void scan_single_cb () @@ -733,10 +884,12 @@ public class AppWindow : Gtk.ApplicationWindow          if (document_hint == "text")          {              text_radio.active = true; +            scan_hint_image.icon_name = "x-office-document-symbolic";          }          else if (document_hint == "photo")          {              photo_radio.active = true; +            scan_hint_image.icon_name = "image-x-generic-symbolic";          }          if (save) @@ -757,6 +910,12 @@ public class AppWindow : Gtk.ApplicationWindow              set_document_hint ("photo", true);      } +    [GtkCallback] +    private void preferences_button_clicked_cb (Gtk.Button button) +    { +        preferences_dialog.present (); +    } +      private ScanOptions make_scan_options ()      {          var options = new ScanOptions (); @@ -781,8 +940,20 @@ public class AppWindow : Gtk.ApplicationWindow      }      [GtkCallback] +    private void device_combo_changed_cb (Gtk.Widget widget) +    { +        if (setting_devices) +            return; +        user_selected_device = true; +        if (get_selected_device () != null) +            settings.set_string ("selected-device", get_selected_device ()); +    } + +    [GtkCallback]      private void scan_button_clicked_cb (Gtk.Widget widget)      { +        scan_button.visible = false; +        stop_button.visible = true;          var options = make_scan_options ();          options.type = scan_type;          if (options.type == ScanType.ADF_BOTH) @@ -793,6 +964,8 @@ public class AppWindow : Gtk.ApplicationWindow      [GtkCallback]      private void stop_scan_button_clicked_cb (Gtk.Widget widget)      { +        scan_button.visible = true; +        stop_button.visible = false;          stop_scan ();      } @@ -1609,15 +1782,17 @@ 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" });          var gear_menu = new Menu ();          var section = new Menu ();          gear_menu.append_section (null, section);          section.append (_("Email"), "app.email"); +        section.append (_("Print"), "app.print");          section.append (C_("menu", "Reorder Pages"), "app.reorder"); +        section.append (_("Preferences"), "app.preferences");          section = new Menu ();          gear_menu.append_section (null, section); -        section.append (_("Preferences"), "app.preferences");          section.append (_("Keyboard Shortcuts"), "win.show-help-overlay");          section.append (_("Help"), "app.help");          section.append (_("About Document Scanner"), "app.about"); @@ -1750,6 +1925,20 @@ public class AppWindow : Gtk.ApplicationWindow              window_height = 400;          window_is_maximized = state_get_boolean (f, "window", "is-maximized");          window_is_fullscreen = state_get_boolean (f, "window", "is-fullscreen"); +        scan_type = Scanner.type_from_string(state_get_string (f, "scanner", "scan-type", "single")); +        set_scan_type (scan_type); +    } + +    private string state_get_string (KeyFile f, string group_name, string key, string default) +    { +        try +        { +            return f.get_string (group_name, key); +        } +        catch +        { +            return default; +        }      }      private int state_get_integer (KeyFile f, string group_name, string key, int default = 0) @@ -1798,6 +1987,7 @@ public class AppWindow : Gtk.ApplicationWindow          f.set_integer ("window", "height", window_height);          f.set_boolean ("window", "is-maximized", window_is_maximized);          f.set_boolean ("window", "is-fullscreen", window_is_fullscreen); +        f.set_string ("scanner", "scan-type", Scanner.type_to_string(scan_type));          try          {              FileUtils.set_contents (state_filename, f.to_data ()); @@ -1811,6 +2001,21 @@ public class AppWindow : Gtk.ApplicationWindow      public void start ()      {          visible = true; +        autosave_manager = new AutosaveManager (); +        autosave_manager.book = book; + +        if (autosave_manager.exists () && prompt_to_load_autosaved_book ()) +            autosave_manager.load (); + +        if (book.n_pages == 0) +            book_needs_saving = false; +        else +        { +            stack.set_visible_child_name ("document"); +            book_view.selected_page = book.get_page (0); +            book_needs_saving = true; +            book_changed_cb (book); +        }      }  } diff --git a/src/autosave-manager.vala b/src/autosave-manager.vala index 84a1e00..c5eb65e 100644 --- a/src/autosave-manager.vala +++ b/src/autosave-manager.vala @@ -59,6 +59,12 @@ public class AutosaveManager          page_filenames = new HashTable<Page, string> (direct_hash, direct_equal);      } +    public bool exists () +    { +        var file = File.new_for_path (AUTOSAVE_PATH); +        return file.query_exists (); +    } +      public void load ()      {          debug ("Loading autosave information"); @@ -328,7 +334,7 @@ public class AutosaveManager              file.set_integer (page_name, "crop-height", page.crop_height);          }          file.set_value ("simple-scan", "pages", page_names); -  +          try          {              DirUtils.create_with_parents (AUTOSAVE_DIR, 0777); diff --git a/src/book-view.vala b/src/book-view.vala index 782a011..12da06f 100644 --- a/src/book-view.vala +++ b/src/book-view.vala @@ -34,7 +34,7 @@ public class BookView : Gtk.Box              else                  return null;          } -        set  +        set          {              if (selected_page == value)                  return; diff --git a/src/help-overlay.ui b/src/help-overlay.ui index dabec9f..b1a0127 100644 --- a/src/help-overlay.ui +++ b/src/help-overlay.ui @@ -122,6 +122,33 @@              </child>            </object>          </child> +        <child> +          <object class="GtkShortcutsGroup"> +            <property name="visible">1</property> +            <property name="title" translatable="yes" context="shortcut window">General</property> +            <child> +              <object class="GtkShortcutsShortcut"> +                <property name="visible">1</property> +                <property name="accelerator">F1</property> +                <property name="title" translatable="yes" context="shortcut window">Show help</property> +              </object> +            </child> +            <child> +              <object class="GtkShortcutsShortcut"> +                <property name="visible">1</property> +                <property name="accelerator"><ctrl>F1</property> +                <property name="title" translatable="yes" context="shortcut window">Keyboard shortcuts</property> +              </object> +            </child> +            <child> +              <object class="GtkShortcutsShortcut"> +                <property name="visible">1</property> +                <property name="accelerator"><ctrl>q</property> +                <property name="title" translatable="yes" context="shortcut window">Quit</property> +              </object> +            </child> +          </object> +        </child>        </object>      </child>    </object> diff --git a/src/meson.build b/src/meson.build index 7d535c8..419ed06 100644 --- a/src/meson.build +++ b/src/meson.build @@ -24,6 +24,7 @@ simple_scan = executable ('simple-scan',                              'book.vala',                              'book-view.vala',                              'page.vala', +                            'page-icon.vala',                              'page-view.vala',                              'preferences-dialog.vala',                              'simple-scan.vala', diff --git a/src/page-icon.vala b/src/page-icon.vala new file mode 100644 index 0000000..793ca5b --- /dev/null +++ b/src/page-icon.vala @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009-2017 Canonical Ltd. + * Author: Robert Ancell <robert.ancell@canonical.com>, + *         Eduard Gotwig <g@ox.io> + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the + * license. + */ + +public class PageIcon : Gtk.DrawingArea +{ +    private string text; +    private double r; +    private double g; +    private double b; +    private const int MINIMUM_WIDTH = 20; + +    public PageIcon (string text, double r = 1.0, double g = 1.0, double b = 1.0) +    { +        this.text = text; +        this.r = r; +        this.g = g; +        this.b = b; +    } + +    public override void get_preferred_width (out int minimum_width, out int natural_width) +    { +        minimum_width = natural_width = MINIMUM_WIDTH; +    } + +    public override void get_preferred_height (out int minimum_height, out int natural_height) +    { +        minimum_height = natural_height = (int) Math.round (MINIMUM_WIDTH * Math.SQRT2); +    } + +    public override void get_preferred_height_for_width (int width, out int minimum_height, out int natural_height) +    { +        minimum_height = natural_height = (int) (width * Math.SQRT2); +    } + +    public override void get_preferred_width_for_height (int height, out int minimum_width, out int natural_width) +    { +        minimum_width = natural_width = (int) (height / Math.SQRT2); +    } + +    public override bool draw (Cairo.Context c) +    { +        var w = get_allocated_width (); +        var h = get_allocated_height (); +        if (w * Math.SQRT2 > h) +            w = (int) Math.round (h / Math.SQRT2); +        else +            h = (int) Math.round (w * Math.SQRT2); + +        c.translate ((get_allocated_width () - w) / 2, (get_allocated_height () - h) / 2); + +        c.rectangle (0.5, 0.5, w - 1, h - 1); + +        c.set_source_rgb (r, g, b); +        c.fill_preserve (); + +        c.set_line_width (1.0); +        c.set_source_rgb (0.0, 0.0, 0.0); +        c.stroke (); + +        Cairo.TextExtents extents; +        c.text_extents (text, out extents); +        c.translate ((w - extents.width) * 0.5 - 0.5, (h + extents.height) * 0.5 - 0.5); +        c.show_text (text); + +        return true; +    } +} diff --git a/src/page-view.vala b/src/page-view.vala index abe5e69..91a2c82 100644 --- a/src/page-view.vala +++ b/src/page-view.vala @@ -36,7 +36,7 @@ public class PageView : Object      public bool selected      {          get { return selected_; } -        set     +        set          {              if ((this.selected && selected) || (!this.selected && !selected))                  return; @@ -845,39 +845,6 @@ public class PageView : Object          Gdk.cairo_set_source_pixbuf (context, image, 0, 0);          context.paint (); -        /* Draw throbber */ -        if (page.is_scanning && !page.has_data) -        { -            double outer_radius; -            if (w > h) -                outer_radius = 0.15 * w; -            else -                outer_radius = 0.15 * h; -            var arc = Math.PI / animate_n_segments; - -            /* Space circles */ -            var x = outer_radius * Math.sin (arc); -            var y = outer_radius * (Math.cos (arc) - 1.0); -            var inner_radius = 0.6 * Math.sqrt (x*x + y*y); - -            double offset = 0.0; -            for (var i = 0; i < animate_n_segments; i++, offset += arc * 2) -            { -                x = w / 2 + outer_radius * Math.sin (offset); -                y = h / 2 - outer_radius * Math.cos (offset); -                context.arc (x, y, inner_radius, 0, 2 * Math.PI); - -                if (i == animate_segment) -                { -                    context.set_source_rgb (0.75, 0.75, 0.75); -                    context.fill_preserve (); -                } - -                context.set_source_rgb (0.5, 0.5, 0.5); -                context.stroke (); -            } -        } -          /* Draw scan line */          if (page.is_scanning && page.scan_line > 0)          { diff --git a/src/page.vala b/src/page.vala index 026fdcc..c6b532e 100644 --- a/src/page.vala +++ b/src/page.vala @@ -90,7 +90,7 @@ public class Page : Object      public ScanDirection scan_direction      {          get { return scan_direction_; } -         +          set          {              if (scan_direction_ == value) @@ -371,7 +371,7 @@ public class Page : Object      {          return_if_fail (width >= 1);          return_if_fail (height >= 1); -         +          if (crop_name == null && has_crop && crop_width == width && crop_height == height)              return;          crop_name = null; diff --git a/src/preferences-dialog.ui b/src/preferences-dialog.ui index 75d8a4c..63d06e0 100644 --- a/src/preferences-dialog.ui +++ b/src/preferences-dialog.ui @@ -14,14 +14,6 @@      <property name="step_increment">1</property>      <property name="page_increment">10</property>    </object> -  <object class="GtkListStore" id="device_model"> -    <columns> -      <!-- column-name device_name --> -      <column type="gchararray"/> -      <!-- column-name label --> -      <column type="gchararray"/> -    </columns> -  </object>    <object class="GtkListStore" id="paper_size_model">      <columns>        <!-- column-name width --> @@ -75,39 +67,11 @@                      <property name="row_spacing">15</property>                      <property name="column_spacing">10</property>                      <child> -                      <object class="GtkLabel" id="source_label"> -                        <property name="visible">True</property> -                        <property name="label" translatable="yes" comments="Label beside scan source combo box">_Scanner</property> -                        <property name="use_underline">True</property> -                        <property name="mnemonic_widget">device_combo</property> -                        <property name="xalign">1</property> -                        <style> -                          <class name="dim-label"/> -                        </style> -                      </object> -                      <packing> -                        <property name="left_attach">0</property> -                        <property name="top_attach">0</property> -                      </packing> -                    </child> -                    <child> -                      <object class="GtkComboBox" id="device_combo"> -                        <property name="visible">True</property> -                        <property name="hexpand">True</property> -                        <property name="model">device_model</property> -                        <signal name="changed" handler="device_combo_changed_cb" swapped="no"/> -                      </object> -                      <packing> -                        <property name="left_attach">1</property> -                        <property name="top_attach">0</property> -                      </packing> -                    </child> -                    <child>                        <object class="GtkLabel" id="page_side_label">                          <property name="visible">True</property> -                        <property name="label" translatable="yes" comments="Label beside scan side combo box">Scan Sides</property> +                        <property name="label" translatable="yes" comments="Label beside scan side combo box">Scan _Sides</property>                          <property name="use_underline">True</property> -                        <property name="mnemonic_widget">scan_side_box</property> +                        <property name="mnemonic_widget">front_side_button</property>                          <property name="xalign">1</property>                          <style>                            <class name="dim-label"/> @@ -115,14 +79,15 @@                        </object>                        <packing>                          <property name="left_attach">0</property> -                        <property name="top_attach">1</property> +                        <property name="top_attach">0</property>                        </packing>                      </child>                      <child>                        <object class="GtkLabel" id="paper_size_label">                          <property name="visible">True</property> -                        <property name="label" translatable="yes" comments="Label beside page size combo box">Page Size</property> +                        <property name="label" translatable="yes" comments="Label beside page size combo box">_Page Size</property>                          <property name="use_underline">True</property> +                        <property name="mnemonic_widget">paper_size_combo</property>                          <property name="xalign">1</property>                          <style>                            <class name="dim-label"/> @@ -130,7 +95,7 @@                        </object>                        <packing>                          <property name="left_attach">0</property> -                        <property name="top_attach">2</property> +                        <property name="top_attach">1</property>                        </packing>                      </child>                      <child> @@ -141,7 +106,7 @@                        </object>                        <packing>                          <property name="left_attach">1</property> -                        <property name="top_attach">2</property> +                        <property name="top_attach">1</property>                        </packing>                      </child>                      <child> @@ -184,7 +149,7 @@                        </object>                        <packing>                          <property name="left_attach">1</property> -                        <property name="top_attach">1</property> +                        <property name="top_attach">0</property>                        </packing>                      </child>                    </object> @@ -197,8 +162,9 @@                      <child>                        <object class="GtkLabel" id="page_delay_label">                          <property name="visible">True</property> -                        <property name="label" translatable="yes" comments="Label beside page delay scale">Delay</property> +                        <property name="label" translatable="yes" comments="Label beside page delay scale">_Delay</property>                          <property name="use_underline">True</property> +                        <property name="mnemonic_widget">page_delay_3s_button</property>                          <property name="xalign">1</property>                          <style>                            <class name="dim-label"/> @@ -316,7 +282,8 @@              <child type="tab">                <object class="GtkLabel">                  <property name="visible">True</property> -                <property name="label" translatable="yes" comments="Preferences Dialog: Tab label for scanning settings">Scanning</property> +                <property name="label" translatable="yes" comments="Preferences Dialog: Tab label for scanning settings">_Scanning</property> +                <property name="use_underline">True</property>                </object>                <packing>                  <property name="tab_fill">False</property> @@ -336,8 +303,9 @@                      <child>                        <object class="GtkLabel" id="text_dpi_label">                          <property name="visible">True</property> -                        <property name="label" translatable="yes" comments="Label beside scan source combo box">_Text Resolution</property> +                        <property name="label" translatable="yes" comments="Label beside scan resolution combo box">_Text Resolution</property>                          <property name="use_underline">True</property> +                        <property name="mnemonic_widget">text_dpi_combo</property>                          <property name="xalign">1</property>                          <style>                            <class name="dim-label"/> @@ -351,8 +319,9 @@                      <child>                        <object class="GtkLabel" id="photo_dpi_label">                          <property name="visible">True</property> -                        <property name="label" translatable="yes" comments="Label beside scan source combo box">_Photo Resolution</property> +                        <property name="label" translatable="yes" comments="Label beside scan resolution combo box">_Image Resolution</property>                          <property name="use_underline">True</property> +                        <property name="mnemonic_widget">photo_dpi_combo</property>                          <property name="xalign">1</property>                          <style>                            <class name="dim-label"/> @@ -395,8 +364,9 @@                      <child>                        <object class="GtkLabel" id="brightness_label">                          <property name="visible">True</property> -                        <property name="label" translatable="yes" comments="Label beside brightness scale">Brightness</property> +                        <property name="label" translatable="yes" comments="Label beside brightness scale">_Brightness</property>                          <property name="use_underline">True</property> +                        <property name="mnemonic_widget">brightness_scale</property>                          <property name="xalign">1</property>                          <style>                            <class name="dim-label"/> @@ -410,8 +380,9 @@                      <child>                        <object class="GtkLabel" id="contrast_label">                          <property name="visible">True</property> -                        <property name="label" translatable="yes" comments="Label beside contrast scale">Contrast</property> +                        <property name="label" translatable="yes" comments="Label beside contrast scale">_Contrast</property>                          <property name="use_underline">True</property> +                        <property name="mnemonic_widget">contrast_scale</property>                          <property name="xalign">1</property>                          <style>                            <class name="dim-label"/> @@ -458,7 +429,8 @@              <child type="tab">                <object class="GtkLabel">                  <property name="visible">True</property> -                <property name="label" translatable="yes" comments="Preferences Dialog: Tab for quality settings">Quality</property> +                <property name="label" translatable="yes" comments="Preferences Dialog: Tab for quality settings">_Quality</property> +                <property name="use_underline">True</property>                </object>                <packing>                  <property name="tab_fill">False</property> @@ -471,7 +443,6 @@    </template>    <object class="GtkSizeGroup" id="label_size_group">      <widgets> -      <widget name="source_label"/>        <widget name="page_side_label"/>        <widget name="paper_size_label"/>        <widget name="page_delay_label"/> diff --git a/src/preferences-dialog.vala b/src/preferences-dialog.vala index 1533541..06dca75 100644 --- a/src/preferences-dialog.vala +++ b/src/preferences-dialog.vala @@ -15,11 +15,6 @@ private class PreferencesDialog : Gtk.Dialog  {      private Settings settings; -    private bool setting_devices; -    private bool user_selected_device; - -    [GtkChild] -    private Gtk.ComboBox device_combo;      [GtkChild]      private Gtk.ComboBox text_dpi_combo;      [GtkChild] @@ -31,8 +26,6 @@ private class PreferencesDialog : Gtk.Dialog      [GtkChild]      private Gtk.Scale contrast_scale;      [GtkChild] -    private Gtk.ListStore device_model; -    [GtkChild]      private Gtk.RadioButton page_delay_3s_button;      [GtkChild]      private Gtk.RadioButton page_delay_5s_button; @@ -85,10 +78,6 @@ private class PreferencesDialog : Gtk.Dialog          paper_size_model.append (out iter);          paper_size_model.set (iter, 0, 1016, 1, 1524, 2, "4×6", -1); -        var renderer = new Gtk.CellRendererText (); -        device_combo.pack_start (renderer, true); -        device_combo.add_attribute (renderer, "text", 1); -          var dpi = settings.get_int ("text-dpi");          if (dpi <= 0)              dpi = DEFAULT_TEXT_DPI; @@ -105,7 +94,7 @@ private class PreferencesDialog : Gtk.Dialog          back_side_button.toggled.connect ((button) => { if (button.active) settings.set_enum ("page-side", ScanType.ADF_BACK); });          both_side_button.toggled.connect ((button) => { if (button.active) settings.set_enum ("page-side", ScanType.ADF_BOTH); }); -        renderer = new Gtk.CellRendererText (); +        var renderer = new Gtk.CellRendererText ();          paper_size_combo.pack_start (renderer, true);          paper_size_combo.add_attribute (renderer, "text", 2); @@ -148,147 +137,6 @@ private class PreferencesDialog : Gtk.Dialog          page_delay_15s_button.toggled.connect ((button) => { if (button.active) settings.set_int ("page-delay", 15000); });      } -    public void set_scan_devices (List<ScanDevice> devices) -    { -        setting_devices = true; - -        /* If the user hasn't chosen a scanner choose the best available one */ -        var have_selection = false; -        if (user_selected_device) -            have_selection = device_combo.active >= 0; - -        /* Add new devices */ -        int index = 0; -        Gtk.TreeIter iter; -        foreach (var device in devices) -        { -            int n_delete = -1; - -            /* Find if already exists */ -            if (device_model.iter_nth_child (out iter, null, index)) -            { -                int i = 0; -                do -                { -                    string name; -                    bool matched; - -                    device_model.get (iter, 0, out name, -1); -                    matched = name == device.name; - -                    if (matched) -                    { -                        n_delete = i; -                        break; -                    } -                    i++; -                } while (device_model.iter_next (ref iter)); -            } - -            /* If exists, remove elements up to this one */ -            if (n_delete >= 0) -            { -                int i; - -                /* Update label */ -                device_model.set (iter, 1, device.label, -1); - -                for (i = 0; i < n_delete; i++) -                { -                    device_model.iter_nth_child (out iter, null, index); -#if VALA_0_36 -                    device_model.remove (ref iter); -#else -                    device_model.remove (iter); -#endif -                } -            } -            else -            { -                device_model.insert (out iter, index); -                device_model.set (iter, 0, device.name, 1, device.label, -1); -            } -            index++; -        } - -        /* Remove any remaining devices */ -        while (device_model.iter_nth_child (out iter, null, index)) -#if VALA_0_36 -            device_model.remove (ref iter); -#else -            device_model.remove (iter); -#endif - -        /* Select the previously selected device or the first available device */ -        if (!have_selection) -        { -            var device = settings.get_string ("selected-device"); -            if (device != null && find_scan_device (device, out iter)) -                device_combo.set_active_iter (iter); -            else -                device_combo.set_active (0); -        } - -        setting_devices = false; -    } - -    public string? get_selected_device () -    { -        Gtk.TreeIter iter; - -        if (device_combo.get_active_iter (out iter)) -        { -            string device; -            device_model.get (iter, 0, out device, -1); -            return device; -        } - -        return null; -    } - -    public string? get_selected_device_label () -    { -        Gtk.TreeIter iter; - -        if (device_combo.get_active_iter (out iter)) -        { -            string label; -            device_model.get (iter, 1, out label, -1); -            return label; -        } - -        return null; -    } - -    public void set_selected_device (string device) -    { -        user_selected_device = true; - -        Gtk.TreeIter iter; -        if (!find_scan_device (device, out iter)) -            return; - -        device_combo.set_active_iter (iter); -    } - -    private bool find_scan_device (string device, out Gtk.TreeIter iter) -    { -        bool have_iter = false; - -        if (device_model.get_iter_first (out iter)) -        { -            do -            { -                string d; -                device_model.get (iter, 0, out d, -1); -                if (d == device) -                    have_iter = true; -            } while (!have_iter && device_model.iter_next (ref iter)); -        } - -        return have_iter; -    } -      private void set_page_side (ScanType page_side)      {          switch (page_side) @@ -453,79 +301,4 @@ private class PreferencesDialog : Gtk.Dialog                  combo.set_active_iter (iter);          }      } - -    [GtkCallback] -    private void device_combo_changed_cb (Gtk.Widget widget) -    { -        if (setting_devices) -            return; -        user_selected_device = true; -        if (get_selected_device () != null) -            settings.set_string ("selected-device", get_selected_device ()); -    } -} - -private class PageIcon : Gtk.DrawingArea -{ -    private string text; -    private double r; -    private double g; -    private double b; -    private const int MINIMUM_WIDTH = 20; - -    public PageIcon (string text, double r = 1.0, double g = 1.0, double b = 1.0) -    { -        this.text = text; -        this.r = r; -        this.g = g; -        this.b = b; -    } - -    public override void get_preferred_width (out int minimum_width, out int natural_width) -    { -        minimum_width = natural_width = MINIMUM_WIDTH; -    } - -    public override void get_preferred_height (out int minimum_height, out int natural_height) -    { -        minimum_height = natural_height = (int) Math.round (MINIMUM_WIDTH * Math.SQRT2); -    } - -    public override void get_preferred_height_for_width (int width, out int minimum_height, out int natural_height) -    { -        minimum_height = natural_height = (int) (width * Math.SQRT2); -    } - -    public override void get_preferred_width_for_height (int height, out int minimum_width, out int natural_width) -    { -        minimum_width = natural_width = (int) (height / Math.SQRT2); -    } - -    public override bool draw (Cairo.Context c) -    { -        var w = get_allocated_width (); -        var h = get_allocated_height (); -        if (w * Math.SQRT2 > h) -            w = (int) Math.round (h / Math.SQRT2); -        else -            h = (int) Math.round (w * Math.SQRT2); - -        c.translate ((get_allocated_width () - w) / 2, (get_allocated_height () - h) / 2); - -        c.rectangle (0.5, 0.5, w - 1, h - 1); - -        c.set_source_rgb (r, g, b); -        c.fill_preserve (); - -        c.set_line_width (1.0); -        c.set_source_rgb (0.0, 0.0, 0.0); -        c.stroke (); - -        Cairo.TextExtents extents; -        c.text_extents (text, out extents); -        c.translate ((w - extents.width) * 0.5 - 0.5, (h + extents.height) * 0.5 - 0.5); -        c.show_text (text); - -        return true; -    }  } diff --git a/src/sane-backends.vapi b/src/sane-backends.vapi index f636dac..b32c1a4 100644 --- a/src/sane-backends.vapi +++ b/src/sane-backends.vapi @@ -48,7 +48,7 @@ namespace Sane {          NO_MEM,          ACCESS_DENIED      } -      +      public static string status_to_string (Status status)      {          switch (status) @@ -88,7 +88,7 @@ namespace Sane {          SET_VALUE,          SET_AUTO      } -     +      public enum Frame      {          GRAY, @@ -154,7 +154,7 @@ namespace Sane {          PERCENT,          MICROSECOND      } -     +      [CCode (cname = "SANE_Constraint_Type", cprefix = "SANE_CONSTRAINT_")]      public enum ConstraintType      { @@ -163,7 +163,7 @@ namespace Sane {          WORD_LIST,          STRING_LIST      } -     +      public class Range      {          public Word min; @@ -225,7 +225,7 @@ namespace Sane {      public int VERSION_MINOR (Int code);      [CCode (cname = "SANE_VERSION_BUILD")]      public int VERSION_BUILD (Int code); -     +      [CCode (cname = "SANE_FIX")]      public Fixed FIX (double d);      [CCode (cname = "SANE_UNFIX")] diff --git a/src/scanner.vala b/src/scanner.vala index 8bc587f..caf740b 100644 --- a/src/scanner.vala +++ b/src/scanner.vala @@ -385,6 +385,24 @@ public class Scanner : Object          notify_event (new NotifyUpdateDevices ((owned) devices));      } +    private double scale_fixed (int source_min, int source_max, Sane.OptionDescriptor option, int value) +    { +        var v = (double) value; + +        return_val_if_fail (option.type == Sane.ValueType.FIXED, value); +        if (option.constraint_type == Sane.ConstraintType.RANGE && option.range.max != option.range.min) +        { +            v -= (double) source_min; +            v *= Sane.UNFIX (option.range.max) - Sane.UNFIX (option.range.min); +            v /= (double) (source_max - source_min); +            v += Sane.UNFIX (option.range.min); +            debug ("scale_fixed: scaling %d [min: %d, max: %d] to %f [min: %f, max: %f]", +                   value, source_min, source_max, v, Sane.UNFIX (option.range.min), Sane.UNFIX (option.range.max)); +        } + +        return v; +    } +      private int scale_int (int source_min, int source_max, Sane.OptionDescriptor option, int value)      {          var v = value; @@ -530,7 +548,11 @@ public class Scanner : Object              return;          var status = Sane.control_option (handle, option_index, Sane.Action.SET_VALUE, &option.range.max, null); -        debug ("sane_control_option (%d, SANE_ACTION_SET_VALUE, option.range.max) -> (%s)", (int) option_index, Sane.status_to_string (status)); + +        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)); +        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));      }      private bool set_string_option (Sane.Handle handle, Sane.OptionDescriptor option, Sane.Int option_index, string value, out string result) @@ -980,6 +1002,7 @@ public class Scanner : Object                  {                      Sane.VALUE_SCAN_MODE_COLOR,                      "Color", +                    "24bit Color[Fast]", /* brother4 driver, Brother DCP-1622WE, #134 */                      "24bit Color", /* Seen in the proprietary brother3 driver */                      "Color - 16 Million Colors" /* Samsung unified driver. LP: 892915 */                  }; @@ -1131,8 +1154,18 @@ public class Scanner : Object              {                  if (job.brightness != 0)                  { -                    var brightness = scale_int (-100, 100, option, job.brightness); -                    set_int_option (handle, option, index, brightness, null); +                    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");                  }              }              option = get_option_by_name (handle, Sane.NAME_CONTRAST, out index); @@ -1140,8 +1173,18 @@ public class Scanner : Object              {                  if (job.contrast != 0)                  { -                    var contrast = scale_int (-100, 100, option, job.contrast); -                    set_int_option (handle, option, index, contrast, null); +                    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");                  }              } @@ -1175,10 +1218,6 @@ public class Scanner : Object          if (option.type == Sane.ValueType.GROUP)              return; -        /* Option disabled */ -        if ((option.cap & Sane.Capability.INACTIVE) != 0) -            return; -          /* Some options are unnamed (e.g. Option 0) */          if (option.name == null)              return; @@ -1205,7 +1244,18 @@ public class Scanner : Object          if (index == 0)              return null; -        return Sane.get_option_descriptor (handle, index); +        var option_descriptor = Sane.get_option_descriptor (handle, index); +        /* +        The Sane.Capability.INACTIVE capability indicates that +        the option is not currently active (e.g., because it's meaningful +        only if another option is set to some other value). +        */ +        if ((option_descriptor.cap & Sane.Capability.INACTIVE) != 0) +        { +            warning ("The option %s (%d) is inactive and can't be set, please file a bug", name, index); +            return null; +        } +        return option_descriptor;      }      private void do_complete_document () @@ -1242,7 +1292,13 @@ public class Scanner : Object          if (status == Sane.Status.GOOD)              state = ScanState.GET_PARAMETERS;          else if (status == Sane.Status.NO_DOCS) +        {              do_complete_document (); +            if (page_number == 0) +                fail_scan (status, +                    /* Error displayed when no documents at the start of scanning */ +                    _("Document feeder empty")); +        }          else          {              warning ("Unable to start device: %s", Sane.strstatus (status)); @@ -1576,30 +1632,50 @@ public class Scanner : Object          }      } -    private string get_scan_type_string (ScanType type) +    public static string type_to_string (ScanType type)      {          switch (type)          {          case ScanType.SINGLE: -            return "ScanType.SINGLE"; +            return "single"; +        case ScanType.BATCH: +            return "batch";          case ScanType.ADF_FRONT: -            return "ScanType.ADF_FRONT"; +            return "adf-front";          case ScanType.ADF_BACK: -            return "ScanType.ADF_BACK"; +            return "adf-back";          case ScanType.ADF_BOTH: -            return "ScanType.ADF_BOTH"; -        case ScanType.BATCH: -            return "ScanType.BATCH"; +            return "adf-both";          default:              return "%d".printf (type);          }      } +    public static ScanType type_from_string (string type) +    { +        switch (type) +        { +        case "single": +            return ScanType.SINGLE; +        case "batch": +            return ScanType.BATCH; +        case "adf-front": +            return ScanType.ADF_FRONT; +        case "adf-back": +            return ScanType.ADF_BACK; +        case "adf-both": +            return ScanType.ADF_BOTH; +        default: +            warning ("Unknown ScanType: %s. Please report this error.", type); +            return ScanType.SINGLE; +        } +    } +      public void scan (string? device, ScanOptions options)      {          debug ("Scanner.scan (\"%s\", dpi=%d, scan_mode=%s, depth=%d, type=%s, paper_width=%d, paper_height=%d, brightness=%d, contrast=%d, delay=%dms)",                 device != null ? device : "(null)", options.dpi, get_scan_mode_string (options.scan_mode), options.depth, -               get_scan_type_string (options.type), options.paper_width, options.paper_height, +               type_to_string (options.type), options.paper_width, options.paper_height,                 options.brightness, options.contrast, options.page_delay);          var request = new RequestStartScan ();          request.job = new ScanJob (); @@ -1634,7 +1710,7 @@ public class Scanner : Object              thread.join ();              thread = null;          } -         +          Sane.exit ();          debug ("sane_exit ()");      } diff --git a/src/simple-scan.vala b/src/simple-scan.vala index 6175a8e..f41ba93 100644 --- a/src/simple-scan.vala +++ b/src/simple-scan.vala @@ -83,7 +83,7 @@ public class SimpleScan : Gtk.Application              device_list.append (default_device);              app.set_scan_devices (device_list); -            app.selected_device = default_device.name; +            app.set_selected_device (default_device.name);          }      } @@ -133,7 +133,7 @@ public class SimpleScan : Gtk.Application          app.set_scan_devices (devices_copy, missing_driver);      } -     +      /* Taken from /usr/local/Brother/sane/Brsane.ini from brscan driver */      private const uint32 brscan_devices[] = { 0x04f90110, 0x04f90111, 0x04f90112, 0x04f9011d, 0x04f9011e, 0x04f9011f, 0x04f9012b, 0x04f90124, 0x04f90153, 0x04f90125, 0x04f90113, 0x04f90114, 0x04f90115, 0x04f90116, 0x04f90119, 0x04f9011a, 0x04f9011b, 0x04f9011c, 0x04f9012e, 0x04f9012f, 0x04f90130, 0x04f90128, 0x04f90127, 0x04f90142, 0x04f90143, 0x04f90140, 0x04f90141, 0x04f9014e, 0x04f9014f, 0x04f90150, 0x04f90151, 0x04f9010e, 0x04f9013a, 0x04f90120, 0x04f9010f, 0x04f90121, 0x04f90122, 0x04f90132, 0x04f9013d, 0x04f9013c, 0x04f90136, 0x04f90135, 0x04f9013e, 0x04f9013f, 0x04f90144, 0x04f90146, 0x04f90148, 0x04f9014a, 0x04f9014b, 0x04f9014c, 0x04f90157, 0x04f90158, 0x04f9015d, 0x04f9015e, 0x04f9015f, 0x04f90160 }; @@ -144,7 +144,7 @@ public class SimpleScan : Gtk.Application      private const uint32 brscan3_devices[] = { 0x04f90222, 0x04f90223, 0x04f90224, 0x04f90225, 0x04f90229, 0x04f9022a, 0x04f9022c, 0x04f90228, 0x04f90236, 0x04f90227, 0x04f9022b, 0x04f9022d, 0x04f9022e, 0x04f9022f, 0x04f90230, 0x04f9021b, 0x04f9021a, 0x04f90219, 0x04f9023f, 0x04f90216, 0x04f9021d, 0x04f9021c, 0x04f90220, 0x04f9021e, 0x04f9023e, 0x04f90235, 0x04f9023a, 0x04f901c9, 0x04f901ca, 0x04f901cb, 0x04f901cc, 0x04f901ec, 0x04f9020d, 0x04f9020c, 0x04f90257, 0x04f9025d, 0x04f90254, 0x04f9025b, 0x04f9026b, 0x04f90258, 0x04f9025e, 0x04f90256, 0x04f90240, 0x04f9025f, 0x04f90260, 0x04f90261, 0x04f90278, 0x04f9026f, 0x04f9026e, 0x04f9026d, 0x04f90234, 0x04f90239, 0x04f90253, 0x04f90255, 0x04f90259, 0x04f9025a, 0x04f9025c, 0x04f90276 };      /* Taken from /opt/brother/scanner/brscan4/models4/*.ini from brscan4 driver */ -    private const uint32 brscan4_devices[] = { 0x04f90314, 0x04f90313, 0x04f90312, 0x04f90311, 0x04f90310, 0x04f9030f, 0x04f90366, 0x04f90365, 0x04f90364, 0x04f90350, 0x04f9034f, 0x04f9034e, 0x04f9034b, 0x04f90349, 0x04f90347, 0x04f90346, 0x04f90343, 0x04f90342, 0x04f90341, 0x04f90340, 0x04f9033d, 0x04f9033c, 0x04f9033a, 0x04f90339, 0x04f90392, 0x04f90373, 0x04f9036e, 0x04f9036d, 0x04f9036c, 0x04f9036b, 0x04f9036a, 0x04f90369, 0x04f90368, 0x04f90367, 0x04f90338, 0x04f90337, 0x04f90335, 0x04f90331, 0x04f90330, 0x04f90329, 0x04f90328, 0x04f90326, 0x04f90324, 0x04f90322, 0x04f90321, 0x04f90320, 0x04f90372, 0x04f90371, 0x04f90370, 0x04f9036f, 0x04f90361, 0x04f90360, 0x04f9035e, 0x04f9035d, 0x04f9035c, 0x04f9035b, 0x04f90379, 0x04f90378, 0x04f90376, 0x04f9037a, 0x04f9037b, 0x04f90377, 0x04f9037f, 0x04f9037e, 0x04f9037d, 0x04f9037c, 0x04f9035a, 0x04f90359, 0x04f90358, 0x04f90357, 0x04f90356, 0x04f90355, 0x04f90354, 0x04f90353, 0x04f90351, 0x04f90390, 0x04f903b3, 0x04f90396, 0x04f90395, 0x04f90394, 0x04f90393, 0x04f90380, 0x04f90381, 0x04f903bd, 0x04f90383, 0x04f90397, 0x04f90386, 0x04f90384, 0x04f90385, 0x04f90388, 0x04f90389, 0x04f9038b, 0x04f9038a, 0x04f9038c, 0x04f9038e, 0x04f9038f, 0x04f9038d, 0x04f903bc, 0x04f903bb, 0x04f903b6, 0x04f903b5, 0x04f903b4, 0x04f90290, 0x04f9028f, 0x04f9028d, 0x04f9028a, 0x04f90284, 0x04f90283, 0x04f90282, 0x04f90281, 0x04f9027e, 0x04f9027d, 0x04f9027c, 0x04f9027b, 0x04f90280, 0x04f9027a, 0x04f90279, 0x04f9027f, 0x04f90285, 0x04f9029a, 0x04f9029f, 0x04f9029e, 0x04f90289, 0x04f90288, 0x04f960a0, 0x04f960a1, 0x04f90293, 0x04f902b7, 0x04f90294, 0x04f90296, 0x04f90298, 0x04f902ba, 0x04f90299, 0x04f902bb, 0x04f902d4, 0x04f90291, 0x04f902ac, 0x04f902b5, 0x04f90292, 0x04f902b6, 0x04f90295, 0x04f902b8, 0x04f9029c, 0x04f902cb, 0x04f902ca, 0x04f902a6, 0x04f902a7, 0x04f902ab, 0x04f902a5, 0x04f902a8, 0x04f902a0, 0x04f902c1, 0x04f902c0, 0x04f902bf, 0x04f902be, 0x04f902bd, 0x04f902bc, 0x04f902b2, 0x04f90287, 0x04f902cf, 0x04f902ce, 0x04f902cd, 0x04f902c7, 0x04f902c6, 0x04f902c5, 0x04f902c4, 0x04f902b4, 0x04f902b3, 0x04f902c2, 0x04f960a4, 0x04f960a5, 0x04f902cc, 0x04f902c8, 0x04f902c3, 0x04f902d3, 0x04f902b1, 0x04f902b0, 0x04f902af, 0x04f902ae, 0x04f902ad, 0x04f902d1, 0x04f902d0, 0x04f902fb, 0x04f902f1, 0x04f902f0, 0x04f902ef, 0x04f902ed, 0x04f902ec, 0x04f902ee, 0x04f902eb, 0x04f902e9, 0x04f902e8, 0x04f902fa, 0x04f902ea, 0x04f902e6, 0x04f902e5, 0x04f902e4, 0x04f902e3, 0x04f902e2, 0x04f902f9, 0x04f902de, 0x04f902e0, 0x04f902df, 0x04f902e1, 0x04f902e7, 0x04f902fc, 0x04f902fd, 0x04f902fe, 0x04f902dd, 0x04f902c9, 0x04f902ff, 0x04f90300, 0x04f902f2, 0x04f902f3, 0x04f902f4, 0x04f902f8, 0x04f902f5, 0x04f902f6, 0x04f902f7, 0x04f90318, 0x04f960a6, 0x04f960a7, 0x04f960a8, 0x04f960a9 };  +    private const uint32 brscan4_devices[] = { 0x04f90314, 0x04f90313, 0x04f90312, 0x04f90311, 0x04f90310, 0x04f9030f, 0x04f90366, 0x04f90365, 0x04f90364, 0x04f90350, 0x04f9034f, 0x04f9034e, 0x04f9034b, 0x04f90349, 0x04f90347, 0x04f90346, 0x04f90343, 0x04f90342, 0x04f90341, 0x04f90340, 0x04f9033d, 0x04f9033c, 0x04f9033a, 0x04f90339, 0x04f90392, 0x04f90373, 0x04f9036e, 0x04f9036d, 0x04f9036c, 0x04f9036b, 0x04f9036a, 0x04f90369, 0x04f90368, 0x04f90367, 0x04f90338, 0x04f90337, 0x04f90335, 0x04f90331, 0x04f90330, 0x04f90329, 0x04f90328, 0x04f90326, 0x04f90324, 0x04f90322, 0x04f90321, 0x04f90320, 0x04f90372, 0x04f90371, 0x04f90370, 0x04f9036f, 0x04f90361, 0x04f90360, 0x04f9035e, 0x04f9035d, 0x04f9035c, 0x04f9035b, 0x04f90379, 0x04f90378, 0x04f90376, 0x04f9037a, 0x04f9037b, 0x04f90377, 0x04f9037f, 0x04f9037e, 0x04f9037d, 0x04f9037c, 0x04f9035a, 0x04f90359, 0x04f90358, 0x04f90357, 0x04f90356, 0x04f90355, 0x04f90354, 0x04f90353, 0x04f90351, 0x04f90390, 0x04f903b3, 0x04f90396, 0x04f90395, 0x04f90394, 0x04f90393, 0x04f90380, 0x04f90381, 0x04f903bd, 0x04f90383, 0x04f90397, 0x04f90386, 0x04f90384, 0x04f90385, 0x04f90388, 0x04f90389, 0x04f9038b, 0x04f9038a, 0x04f9038c, 0x04f9038e, 0x04f9038f, 0x04f9038d, 0x04f903bc, 0x04f903bb, 0x04f903b6, 0x04f903b5, 0x04f903b4, 0x04f90290, 0x04f9028f, 0x04f9028d, 0x04f9028a, 0x04f90284, 0x04f90283, 0x04f90282, 0x04f90281, 0x04f9027e, 0x04f9027d, 0x04f9027c, 0x04f9027b, 0x04f90280, 0x04f9027a, 0x04f90279, 0x04f9027f, 0x04f90285, 0x04f9029a, 0x04f9029f, 0x04f9029e, 0x04f90289, 0x04f90288, 0x04f960a0, 0x04f960a1, 0x04f90293, 0x04f902b7, 0x04f90294, 0x04f90296, 0x04f90298, 0x04f902ba, 0x04f90299, 0x04f902bb, 0x04f902d4, 0x04f90291, 0x04f902ac, 0x04f902b5, 0x04f90292, 0x04f902b6, 0x04f90295, 0x04f902b8, 0x04f9029c, 0x04f902cb, 0x04f902ca, 0x04f902a6, 0x04f902a7, 0x04f902ab, 0x04f902a5, 0x04f902a8, 0x04f902a0, 0x04f902c1, 0x04f902c0, 0x04f902bf, 0x04f902be, 0x04f902bd, 0x04f902bc, 0x04f902b2, 0x04f90287, 0x04f902cf, 0x04f902ce, 0x04f902cd, 0x04f902c7, 0x04f902c6, 0x04f902c5, 0x04f902c4, 0x04f902b4, 0x04f902b3, 0x04f902c2, 0x04f960a4, 0x04f960a5, 0x04f902cc, 0x04f902c8, 0x04f902c3, 0x04f902d3, 0x04f902b1, 0x04f902b0, 0x04f902af, 0x04f902ae, 0x04f902ad, 0x04f902d1, 0x04f902d0, 0x04f902fb, 0x04f902f1, 0x04f902f0, 0x04f902ef, 0x04f902ed, 0x04f902ec, 0x04f902ee, 0x04f902eb, 0x04f902e9, 0x04f902e8, 0x04f902fa, 0x04f902ea, 0x04f902e6, 0x04f902e5, 0x04f902e4, 0x04f902e3, 0x04f902e2, 0x04f902f9, 0x04f902de, 0x04f902e0, 0x04f902df, 0x04f902e1, 0x04f902e7, 0x04f902fc, 0x04f902fd, 0x04f902fe, 0x04f902dd, 0x04f902c9, 0x04f902ff, 0x04f90300, 0x04f902f2, 0x04f902f3, 0x04f902f4, 0x04f902f8, 0x04f902f5, 0x04f902f6, 0x04f902f7, 0x04f90318, 0x04f960a6, 0x04f960a7, 0x04f960a8, 0x04f960a9 };      /* 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, 0x04e83446, 0x04e8341a, 0x04e83437, 0x04e83442, 0x04e83466, 0x04e8340d, 0x04e8341d, 0x04e83420, 0x04e83429, 0x04e83443, 0x04e83438, 0x04e8344c, 0x04e8345d, 0x04e83463, 0x04e83465, 0x04e83450, 0x04e83468, 0x04e83469, 0x04e83471 }; @@ -156,7 +156,7 @@ public class SimpleScan : Gtk.Application      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 };      /* Brother IDs extracted using the following Python -     * import sys    +     * import sys       * ids = []       * for f in sys.argv:       *   for l in file (f).readlines (): @@ -194,7 +194,7 @@ public class SimpleScan : Gtk.Application          add_devices (driver_map, brscan4_devices, "brscan4");          add_devices (driver_map, samsung_devices, "samsung");          add_devices (driver_map, hpaio_devices, "hpaio"); -        add_devices (driver_map, epkowa_devices, "epkowa");         +        add_devices (driver_map, epkowa_devices, "epkowa");          var devices = usb_context.get_devices ();          for (var i = 0; i < devices.length; i++)          { @@ -211,7 +211,7 @@ public class SimpleScan : Gtk.Application      {          for (var i = 0; i < devices.length; i++)              map.insert (devices[i], driver); -    }    +    }      private void authorize_cb (Scanner scanner, string resource)      { | 
