diff options
author | Sascha Silbe <sascha-pgp@silbe.org> | 2012-08-14 09:05:31 (GMT) |
---|---|---|
committer | Sascha Silbe <sascha-pgp@silbe.org> | 2012-08-14 09:12:35 (GMT) |
commit | 77315c7d10dc06008ca80e67fe22a9ba279c5df4 (patch) | |
tree | fbabe6eeb5b085af5a560aba66d517ea83646347 | |
parent | de41bbd42ff2f45f2be9c17991e1e018ec05abd7 (diff) |
Use the same scanner device again when resuming
Save the scanner device in-use at the time of closing and try to open
the same device again when resuming the session. Connecting new
devices supported by SANE (e.g. webcams) won't cause the wrong device
to be picked anymore.
Also lays the foundation for letting the user change the scanner
device during the session.
-rw-r--r-- | scan.py | 120 |
1 files changed, 80 insertions, 40 deletions
@@ -64,7 +64,7 @@ class SettingsToolbar(gtk.ToolPalette): def set_scanner(self, scanner): self._scanner = scanner self._clear() - if self._scanner: + if self._scanner is not None: self._add_options() def _clear(self): @@ -286,9 +286,9 @@ class SettingsToolbar(gtk.ToolPalette): class ScanThread(threading.Thread): - def __init__(self, devs, temp_dir, callback=None): + def __init__(self, temp_dir, callback=None): threading.Thread.__init__(self) - self._devs = devs + self._device = None self._temp_dir = temp_dir self._callback = callback self._cond = threading.Condition() @@ -298,6 +298,10 @@ class ScanThread(threading.Thread): self._ready = False self._dpi = None + def set_device(self, device): + with self._cond: + self._device = device + def run(self): while True: with self._cond: @@ -323,6 +327,9 @@ class ScanThread(threading.Thread): @trace() def start_scan(self): with self._cond: + if self._device is None: + raise ValueError('No device set') + logging.debug('start_scan(): got lock') self._action = 'start' self._cond.notify() @@ -358,8 +365,8 @@ class ScanThread(threading.Thread): self._images = None self._error = None - source = getattr(self._devs[0], 'source', 'Auto') - if getattr(self._devs[0], 'batch_scan', False): + source = getattr(self._device, 'source', 'Auto') + if getattr(self._device, 'batch_scan', False): scan_multi = source in ['Auto', 'ADF'] else: scan_multi = source == 'ADF' @@ -369,8 +376,8 @@ class ScanThread(threading.Thread): self._scan_multi() else: logging.debug('starting single scan') - self._dpi = self._devs[0].resolution - self._images = [self._process_image(self._devs[0].scan())] + self._dpi = self._device.resolution + self._images = [self._process_image(self._device.scan())] except sane.error, exc: # Ouch. sane.error doesn't derive from Exception :-/ @@ -391,18 +398,18 @@ class ScanThread(threading.Thread): @trace() def _scan_multi(self): logging.debug('_scan: calling multi_scan()') - scan_iter = self._devs[0].multi_scan() + scan_iter = self._device.multi_scan() logging.debug('_scan: acquiring images') images = [] try: - self._dpi = self._devs[0].resolution + self._dpi = self._device.resolution for image in scan_iter: images.append(self._process_image(image)) if self._check_action(['stop', 'quit']): break - self._dpi = self._devs[0].resolution + self._dpi = self._device.resolution self._images = images @@ -480,8 +487,10 @@ class ScanActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) self.max_participants = 1 - self._scanner_name = None - self._scanners = [] + # content: (device_name, vendor, model, description) + self._scanner_infos = [] + self._current_scanner = None + self._current_scanner_name = None self._scanner_options = {'source': 'ADF'} self._status = 'init' self._msg_box_buf = None @@ -489,10 +498,12 @@ class ScanActivity(activity.Activity): self._scan_button = None self._settings_toolbar = None temp_dir = os.path.join(self.get_activity_root(), 'tmp') - self._scan_thread = ScanThread(self._scanners, temp_dir, + self._scan_thread = ScanThread(temp_dir, callback=self._scan_finished_cb) self._scan_thread.start() self._setup_widgets() + # TODO: delay opening scanner device if we're resuming a + # previous session self._init_scanner() @trace() @@ -504,47 +515,62 @@ class ScanActivity(activity.Activity): activity.Activity.destroy(self) def read_file(self, file_path): - if not self._scanners: + if not self._scanner_infos: + # no scanners available, nothing to do for now (see TODO + # item in write_file()) return globals_dict = {'__builtins__': None} settings = eval(file(file_path).read(), globals_dict) + logging.debug('old settings: %r', settings) + scanner_name = settings.pop('_scanner_name', None) + if not scanner_name: + # Saved by a previous version, just pick the first + # available scanner like the previous version did. + scanner_name = self._scanner_infos[0][0] + + if scanner_name not in [info[0] for info in self._scanner_infos]: + # The previous scanner is not available right now, pick + # another one and apply as much of the previous settings + # as we can. + scanner_name = self._scanner_infos[0][0] + + self._open_scanner(scanner_name) self._set_settings(settings) - # TODO: don't call set_scanner() twice when resuming (once in - # _init_scanner() and once here) - self._settings_toolbar.set_scanner(self._scanners[0]) + # HACK: cause the toolbar to re-read the settings after + # changing them + self._settings_toolbar.set_scanner(self._current_scanner) def write_file(self, file_path): + # TODO: retain settings for all scanners, not just the current one self.metadata['mime_type'] = 'text/plain' with file(file_path, 'w') as f: f.write(repr(self._get_settings())) @trace() def _get_settings(self): - if not self._scanners: + if self._current_scanner is None: return {} - settings = {} - scanner = self._scanners[0] - for py_name in scanner.optlist: + settings = {'_scanner_name': self._current_scanner_name} + for py_name in self._current_scanner.optlist: logging.debug('getting value for setting %r', py_name) - option = scanner[py_name] + option = self._current_scanner[py_name] if option.type in [sane.TYPE_BOOL, sane.TYPE_INT, sane.TYPE_FIXED, sane.TYPE_STRING] and option.is_active(): - settings[py_name] = getattr(scanner, py_name) + settings[py_name] = getattr(self._current_scanner, py_name) return settings @trace() def _set_settings(self, settings): - if not self._scanners: + if self._current_scanner is None: return - scanner = self._scanners[0] for name, value in settings.items(): try: - setattr(scanner, name, value) + setattr(self._current_scanner, name, value) except AttributeError: logging.info('Saved setting %r=%r not support by current' @@ -557,41 +583,55 @@ class ScanActivity(activity.Activity): @trace() def _init_scanner(self): sane.init() - scanner_devs = sane.get_devices() - if not scanner_devs: + self._scanner_infos = sane.get_devices() + if not self._scanner_infos: self._set_status('no-dev') return - self._scanner_name = scanner_devs[0][0] - self._reopen_scanner() + self._open_scanner(self._scanner_infos[0][0]) + + def _open_scanner(self, name): + """Open the current scanner device - def _reopen_scanner(self): - """Reopen scanner device to work around lower layer bugs.""" - if self._scanners: + Close the previous device if there is one, but ignore errors + while closing. Open the device identified by name. + + Can be used to open the scanner device on start-up, change the + current scanner or reopen the scanner device to work around + lower layer bugs. + """ + if self._current_scanner: + old_scanner, self._current_scanner = self._current_scanner, None try: - old_scanner = self._scanners.pop() old_scanner.close() del old_scanner except sane.error, exc: logging.exception('Error closing scanner') - if not self._scanner_name: + if not name: self._set_status('no-dev') + self._set_scanner(None, None) return try: - self._scanners.append(sane.open(self._scanner_name)) + scanner = sane.open(name) except sane.error, exc: - logging.exception('Error opening scanner %r', self._scanner_name) + logging.exception('Error opening scanner %r', name) self._show_error(exc) return - self._settings_toolbar.set_scanner(self._scanners[0]) - + self._set_scanner(scanner, name) self._set_status('ready') + @trace() + def _set_scanner(self, device, name): + self._current_scanner = device + self._current_scanner_name = name + self._scan_thread.set_device(device) + self._settings_toolbar.set_scanner(device) + def _setup_widgets(self): self._setup_toolbar() self._setup_canvas() @@ -755,7 +795,7 @@ class ScanActivity(activity.Activity): if not exc: self._set_status('ready') else: - self._reopen_scanner() + self._open_scanner(self._current_scanner_name) def _add_images(self, image_infos): for info in image_infos: |