sane.ds: Add a few trace messages useful in following color format.
[wine/multimedia.git] / dlls / sane.ds / capability.c
blob63a836182b768eaac48fd234b14394f63b9e7bcd
1 /*
2 * Copyright 2000 Corel Corporation
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
22 #include "config.h"
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "twain.h"
29 #include "sane_i.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
34 static TW_UINT16 get_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 *type, TW_UINT32 *value)
36 if (pCapability->hContainer)
38 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
39 if (pVal)
41 *value = pVal->Item;
42 if (type)
43 *type = pVal->ItemType;
44 GlobalUnlock (pCapability->hContainer);
45 return TWCC_SUCCESS;
48 return TWCC_BUMMER;
52 static TW_UINT16 set_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 type, TW_UINT32 value)
54 pCapability->hContainer = GlobalAlloc (0, sizeof(TW_ONEVALUE));
56 if (pCapability->hContainer)
58 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
59 if (pVal)
61 pCapability->ConType = TWON_ONEVALUE;
62 pVal->ItemType = type;
63 pVal->Item = value;
64 GlobalUnlock (pCapability->hContainer);
65 return TWCC_SUCCESS;
68 return TWCC_LOWMEMORY;
71 static TW_UINT16 msg_set(pTW_CAPABILITY pCapability, TW_UINT32 *val)
73 if (pCapability->ConType == TWON_ONEVALUE)
74 return get_onevalue(pCapability, NULL, val);
76 FIXME("Partial Stub: MSG_SET only supports TW_ONEVALUE\n");
77 return TWCC_BADCAP;
81 static TW_UINT16 msg_get_enum(pTW_CAPABILITY pCapability, const TW_UINT32 *values, int value_count,
82 TW_UINT16 type, TW_UINT32 current, TW_UINT32 default_value)
84 TW_ENUMERATION *enumv = NULL;
85 TW_UINT32 *p32;
86 TW_UINT16 *p16;
87 int i;
89 pCapability->ConType = TWON_ENUMERATION;
90 pCapability->hContainer = 0;
92 if (type == TWTY_INT16 || type == TWTY_UINT16)
93 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT16)]));
95 if (type == TWTY_INT32 || type == TWTY_UINT32)
96 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT32)]));
98 if (pCapability->hContainer)
99 enumv = GlobalLock(pCapability->hContainer);
101 if (! enumv)
102 return TWCC_LOWMEMORY;
104 enumv->ItemType = type;
105 enumv->NumItems = value_count;
107 p16 = (TW_UINT16 *) enumv->ItemList;
108 p32 = (TW_UINT32 *) enumv->ItemList;
109 for (i = 0; i < value_count; i++)
111 if (values[i] == current)
112 enumv->CurrentIndex = i;
113 if (values[i] == default_value)
114 enumv->DefaultIndex = i;
115 if (type == TWTY_INT16 || type == TWTY_UINT16)
116 p16[i] = values[i];
117 if (type == TWTY_INT32 || type == TWTY_UINT32)
118 p32[i] = values[i];
121 GlobalUnlock(pCapability->hContainer);
122 return TWCC_SUCCESS;
125 #ifdef SONAME_LIBSANE
126 static TW_UINT16 msg_get_range(pTW_CAPABILITY pCapability, TW_UINT16 type,
127 TW_UINT32 minval, TW_UINT32 maxval, TW_UINT32 step, TW_UINT32 def, TW_UINT32 current)
129 TW_RANGE *range = NULL;
131 pCapability->ConType = TWON_RANGE;
132 pCapability->hContainer = 0;
134 pCapability->hContainer = GlobalAlloc (0, sizeof(*range));
135 if (pCapability->hContainer)
136 range = GlobalLock(pCapability->hContainer);
138 if (! range)
139 return TWCC_LOWMEMORY;
141 range->ItemType = type;
142 range->MinValue = minval;
143 range->MaxValue = maxval;
144 range->StepSize = step;
145 range->DefaultValue = def;
146 range->CurrentValue = current;
148 GlobalUnlock(pCapability->hContainer);
149 return TWCC_SUCCESS;
151 #endif
153 static TW_UINT16 TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability)
155 TW_ARRAY *a;
156 static const UINT16 supported_caps[] = { CAP_SUPPORTEDCAPS, CAP_XFERCOUNT, CAP_UICONTROLLABLE,
157 ICAP_XFERMECH, ICAP_PIXELTYPE, ICAP_UNITS, ICAP_BITDEPTH, ICAP_COMPRESSION, ICAP_PIXELFLAVOR,
158 ICAP_XRESOLUTION, ICAP_YRESOLUTION };
160 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
161 pCapability->ConType = TWON_ARRAY;
163 if (pCapability->hContainer)
165 UINT16 *u;
166 int i;
167 a = GlobalLock (pCapability->hContainer);
168 a->ItemType = TWTY_UINT16;
169 a->NumItems = sizeof(supported_caps) / sizeof(supported_caps[0]);
170 u = (UINT16 *) a->ItemList;
171 for (i = 0; i < a->NumItems; i++)
172 u[i] = supported_caps[i];
173 GlobalUnlock (pCapability->hContainer);
174 return TWCC_SUCCESS;
176 else
177 return TWCC_LOWMEMORY;
181 /* ICAP_XFERMECH */
182 static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
184 static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY };
185 TW_UINT32 val;
186 TW_UINT16 twCC = TWCC_BADCAP;
188 TRACE("ICAP_XFERMECH\n");
190 switch (action)
192 case MSG_QUERYSUPPORT:
193 twCC = set_onevalue(pCapability, TWTY_INT32,
194 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
195 break;
197 case MSG_GET:
198 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
199 TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE);
200 break;
202 case MSG_SET:
203 twCC = msg_set(pCapability, &val);
204 if (twCC == TWCC_SUCCESS)
206 activeDS.capXferMech = (TW_UINT16) val;
207 FIXME("Partial Stub: XFERMECH set to %d, but ignored\n", val);
209 break;
211 case MSG_GETDEFAULT:
212 twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE);
213 break;
215 case MSG_RESET:
216 activeDS.capXferMech = TWSX_NATIVE;
217 /* .. fall through intentional .. */
219 case MSG_GETCURRENT:
220 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech);
221 FIXME("Partial Stub: XFERMECH of %d not actually used\n", activeDS.capXferMech);
222 break;
224 return twCC;
228 /* CAP_XFERCOUNT */
229 static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action)
231 TW_UINT32 val;
232 TW_UINT16 twCC = TWCC_BADCAP;
234 TRACE("CAP_XFERCOUNT\n");
236 switch (action)
238 case MSG_QUERYSUPPORT:
239 twCC = set_onevalue(pCapability, TWTY_INT32,
240 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
241 break;
243 case MSG_GET:
244 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
245 FIXME("Partial Stub: Reporting only support for transfer all\n");
246 break;
248 case MSG_SET:
249 twCC = msg_set(pCapability, &val);
250 if (twCC == TWCC_SUCCESS)
251 FIXME("Partial Stub: XFERCOUNT set to %d, but ignored\n", val);
252 break;
254 case MSG_GETDEFAULT:
255 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
256 break;
258 case MSG_RESET:
259 /* .. fall through intentional .. */
261 case MSG_GETCURRENT:
262 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
263 break;
265 return twCC;
268 #ifdef SONAME_LIBSANE
269 static BOOL pixeltype_to_sane_mode(TW_UINT16 pixeltype, SANE_String mode, int len)
271 SANE_String_Const m = NULL;
272 switch (pixeltype)
274 case TWPT_GRAY:
275 m = SANE_VALUE_SCAN_MODE_GRAY;
276 break;
277 case TWPT_RGB:
278 m = SANE_VALUE_SCAN_MODE_COLOR;
279 break;
280 case TWPT_BW:
281 m = SANE_VALUE_SCAN_MODE_LINEART;
282 break;
284 if (! m)
285 return FALSE;
286 if (strlen(m) >= len)
287 return FALSE;
288 strcpy(mode, m);
289 return TRUE;
291 static BOOL sane_mode_to_pixeltype(SANE_String_Const mode, TW_UINT16 *pixeltype)
293 if (strcmp(mode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
294 *pixeltype = TWPT_BW;
295 else if (memcmp(mode, SANE_VALUE_SCAN_MODE_GRAY, strlen(SANE_VALUE_SCAN_MODE_GRAY)) == 0)
296 *pixeltype = TWPT_GRAY;
297 else if (strcmp(mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
298 *pixeltype = TWPT_RGB;
299 else
300 return FALSE;
302 return TRUE;
305 static TW_UINT16 sane_status_to_twcc(SANE_Status rc)
307 switch (rc)
309 case SANE_STATUS_GOOD:
310 return TWCC_SUCCESS;
311 case SANE_STATUS_UNSUPPORTED:
312 return TWCC_CAPUNSUPPORTED;
313 case SANE_STATUS_JAMMED:
314 return TWCC_PAPERJAM;
315 case SANE_STATUS_NO_MEM:
316 return TWCC_LOWMEMORY;
317 case SANE_STATUS_ACCESS_DENIED:
318 return TWCC_DENIED;
320 case SANE_STATUS_IO_ERROR:
321 case SANE_STATUS_NO_DOCS:
322 case SANE_STATUS_COVER_OPEN:
323 case SANE_STATUS_EOF:
324 case SANE_STATUS_INVAL:
325 case SANE_STATUS_CANCELLED:
326 case SANE_STATUS_DEVICE_BUSY:
327 default:
328 return TWCC_BUMMER;
331 #endif
333 /* ICAP_PIXELTYPE */
334 static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 action)
336 TW_UINT16 twCC = TWCC_BADCAP;
337 #ifdef SONAME_LIBSANE
338 TW_UINT32 possible_values[3];
339 int possible_value_count;
340 TW_UINT32 val;
341 SANE_Status rc;
342 SANE_Int status;
343 SANE_String_Const *choices;
344 char current_mode[64];
345 TW_UINT16 current_pixeltype = TWPT_BW;
346 SANE_Char mode[64];
348 TRACE("ICAP_PIXELTYPE\n");
350 rc = sane_option_probe_mode(activeDS.deviceHandle, &choices, current_mode, sizeof(current_mode));
351 if (rc != SANE_STATUS_GOOD)
353 ERR("Unable to retrieve mode from sane, ICAP_PIXELTYPE unsupported\n");
354 return twCC;
357 sane_mode_to_pixeltype(current_mode, &current_pixeltype);
359 /* Sane does not support a concept of a default mode, so we simply cache
360 * the first mode we find */
361 if (! activeDS.PixelTypeSet)
363 activeDS.PixelTypeSet = TRUE;
364 activeDS.defaultPixelType = current_pixeltype;
367 switch (action)
369 case MSG_QUERYSUPPORT:
370 twCC = set_onevalue(pCapability, TWTY_INT32,
371 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
372 break;
374 case MSG_GET:
375 for (possible_value_count = 0; choices && *choices && possible_value_count < 3; choices++)
377 TW_UINT16 pix;
378 if (sane_mode_to_pixeltype(*choices, &pix))
379 possible_values[possible_value_count++] = pix;
381 twCC = msg_get_enum(pCapability, possible_values, possible_value_count,
382 TWTY_UINT16, current_pixeltype, activeDS.defaultPixelType);
383 break;
385 case MSG_SET:
386 twCC = msg_set(pCapability, &val);
387 if (twCC == TWCC_SUCCESS)
389 TRACE("Setting pixeltype to %d\n", val);
390 if (! pixeltype_to_sane_mode(val, mode, sizeof(mode)))
391 return TWCC_BADVALUE;
393 status = 0;
394 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
395 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
396 if (rc == SANE_STATUS_INVAL && strcmp(mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
398 strcpy(mode, "Grayscale");
399 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
401 if (rc != SANE_STATUS_GOOD)
402 return sane_status_to_twcc(rc);
403 if (status & SANE_INFO_RELOAD_PARAMS)
404 psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
406 break;
408 case MSG_GETDEFAULT:
409 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.defaultPixelType);
410 break;
412 case MSG_RESET:
413 current_pixeltype = activeDS.defaultPixelType;
414 if (! pixeltype_to_sane_mode(current_pixeltype, mode, sizeof(mode)))
415 return TWCC_BADVALUE;
417 status = 0;
418 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
419 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
420 if (rc == SANE_STATUS_INVAL && strcmp(mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
422 strcpy(mode, "Grayscale");
423 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
425 if (rc != SANE_STATUS_GOOD)
426 return sane_status_to_twcc(rc);
427 if (status & SANE_INFO_RELOAD_PARAMS)
428 psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
430 /* .. fall through intentional .. */
432 case MSG_GETCURRENT:
433 twCC = set_onevalue(pCapability, TWTY_UINT16, current_pixeltype);
434 TRACE("Returning current pixeltype of %d\n", current_pixeltype);
435 break;
438 #endif
439 return twCC;
442 /* ICAP_UNITS */
443 static TW_UINT16 SANE_ICAPUnits (pTW_CAPABILITY pCapability, TW_UINT16 action)
445 TW_UINT32 val;
446 TW_UINT16 twCC = TWCC_BADCAP;
448 TRACE("ICAP_UNITS\n");
450 switch (action)
452 case MSG_QUERYSUPPORT:
453 twCC = set_onevalue(pCapability, TWTY_INT32,
454 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
455 break;
457 case MSG_GET:
458 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
459 break;
461 case MSG_SET:
462 twCC = msg_set(pCapability, &val);
463 if (twCC == TWCC_SUCCESS)
465 if (val != TWUN_INCHES)
467 ERR("Sane supports only SANE_UNIT_DPI\n");
468 twCC = TWCC_BADVALUE;
471 break;
473 case MSG_GETDEFAULT:
474 case MSG_RESET:
475 /* .. fall through intentional .. */
477 case MSG_GETCURRENT:
478 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
479 break;
482 return twCC;
485 /* ICAP_BITDEPTH */
486 static TW_UINT16 SANE_ICAPBitDepth(pTW_CAPABILITY pCapability, TW_UINT16 action)
488 TW_UINT16 twCC = TWCC_BADCAP;
489 #ifdef SONAME_LIBSANE
490 TW_UINT32 possible_values[1];
492 TRACE("ICAP_BITDEPTH\n");
494 possible_values[0] = activeDS.sane_param.depth;
496 switch (action)
498 case MSG_QUERYSUPPORT:
499 twCC = set_onevalue(pCapability, TWTY_INT32,
500 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
501 break;
503 case MSG_GET:
504 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
505 TWTY_UINT16, activeDS.sane_param.depth, activeDS.sane_param.depth);
506 break;
508 case MSG_GETDEFAULT:
509 /* .. Fall through intentional .. */
511 case MSG_GETCURRENT:
512 TRACE("Returning current bitdepth of %d\n", activeDS.sane_param.depth);
513 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.sane_param.depth);
514 break;
516 #endif
517 return twCC;
520 /* CAP_UICONTROLLABLE */
521 static TW_UINT16 SANE_CAPUiControllable(pTW_CAPABILITY pCapability, TW_UINT16 action)
523 TW_UINT16 twCC = TWCC_BADCAP;
525 TRACE("CAP_UICONTROLLABLE\n");
527 switch (action)
529 case MSG_QUERYSUPPORT:
530 twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET);
531 break;
533 case MSG_GET:
534 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
535 break;
538 return twCC;
541 /* ICAP_COMPRESSION */
542 static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 action)
544 static const TW_UINT32 possible_values[] = { TWCP_NONE };
545 TW_UINT32 val;
546 TW_UINT16 twCC = TWCC_BADCAP;
548 TRACE("ICAP_COMPRESSION\n");
550 switch (action)
552 case MSG_QUERYSUPPORT:
553 twCC = set_onevalue(pCapability, TWTY_INT32,
554 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
555 break;
557 case MSG_GET:
558 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
559 TWTY_UINT16, TWCP_NONE, TWCP_NONE);
560 FIXME("Partial stub: We don't attempt to support compression\n");
561 break;
563 case MSG_SET:
564 twCC = msg_set(pCapability, &val);
565 if (twCC == TWCC_SUCCESS)
566 FIXME("Partial Stub: COMPRESSION set to %d, but ignored\n", val);
567 break;
569 case MSG_GETDEFAULT:
570 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
571 break;
573 case MSG_RESET:
574 /* .. fall through intentional .. */
576 case MSG_GETCURRENT:
577 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
578 break;
580 return twCC;
583 /* ICAP_XRESOLUTION, ICAP_YRESOLUTION */
584 static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
586 TW_UINT16 twCC = TWCC_BADCAP;
587 #ifdef SONAME_LIBSANE
588 TW_UINT32 val;
589 SANE_Int current_resolution;
590 TW_FIX32 *default_res;
591 const char *best_option_name;
592 SANE_Int minval, maxval, quantval;
593 SANE_Status sane_rc;
594 SANE_Int set_status;
596 TRACE("ICAP_%cRESOLUTION\n", cap == ICAP_XRESOLUTION ? 'X' : 'Y');
598 /* Some scanners support 'x-resolution', most seem to just support 'resolution' */
599 if (cap == ICAP_XRESOLUTION)
601 best_option_name = "x-resolution";
602 default_res = &activeDS.defaultXResolution;
604 else
606 best_option_name = "y-resolution";
607 default_res = &activeDS.defaultYResolution;
609 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, &current_resolution) != SANE_STATUS_GOOD)
611 best_option_name = "resolution";
612 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, &current_resolution) != SANE_STATUS_GOOD)
613 return TWCC_BADCAP;
616 /* Sane does not support a concept of 'default' resolution, so we have to
617 * cache the resolution the very first time we load the scanner, and use that
618 * as the default */
619 if (cap == ICAP_XRESOLUTION && ! activeDS.XResolutionSet)
621 default_res->Whole = current_resolution;
622 default_res->Frac = 0;
623 activeDS.XResolutionSet = TRUE;
626 if (cap == ICAP_YRESOLUTION && ! activeDS.YResolutionSet)
628 default_res->Whole = current_resolution;
629 default_res->Frac = 0;
630 activeDS.YResolutionSet = TRUE;
633 switch (action)
635 case MSG_QUERYSUPPORT:
636 twCC = set_onevalue(pCapability, TWTY_INT32,
637 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
638 break;
640 case MSG_GET:
641 sane_rc = sane_option_probe_resolution(activeDS.deviceHandle, best_option_name, &minval, &maxval, &quantval);
642 if (sane_rc != SANE_STATUS_GOOD)
643 twCC = TWCC_BADCAP;
644 else
645 twCC = msg_get_range(pCapability, TWTY_FIX32,
646 minval, maxval, quantval == 0 ? 1 : quantval, default_res->Whole, current_resolution);
647 break;
649 case MSG_SET:
650 twCC = msg_set(pCapability, &val);
651 if (twCC == TWCC_SUCCESS)
653 TW_FIX32 f32;
654 memcpy(&f32, &val, sizeof(f32));
655 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, f32.Whole, &set_status);
656 if (sane_rc != SANE_STATUS_GOOD)
658 FIXME("Status of %d not expected or handled\n", sane_rc);
659 twCC = TWCC_BADCAP;
661 else if (set_status == SANE_INFO_INEXACT)
662 twCC = TWCC_CHECKSTATUS;
664 break;
666 case MSG_GETDEFAULT:
667 twCC = set_onevalue(pCapability, TWTY_FIX32, default_res->Whole);
668 break;
670 case MSG_RESET:
671 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, default_res->Whole, NULL);
672 if (sane_rc != SANE_STATUS_GOOD)
673 return TWCC_BADCAP;
675 /* .. fall through intentional .. */
677 case MSG_GETCURRENT:
678 twCC = set_onevalue(pCapability, TWTY_FIX32, current_resolution);
679 break;
681 #endif
682 return twCC;
685 /* ICAP_PIXELFLAVOR */
686 static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
688 static const TW_UINT32 possible_values[] = { TWPF_CHOCOLATE, TWPF_VANILLA };
689 TW_UINT32 val;
690 TW_UINT16 twCC = TWCC_BADCAP;
692 TRACE("ICAP_PIXELFLAVOR\n");
694 switch (action)
696 case MSG_QUERYSUPPORT:
697 twCC = set_onevalue(pCapability, TWTY_INT32,
698 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
699 break;
701 case MSG_GET:
702 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
703 TWTY_UINT16, TWPF_CHOCOLATE, TWPF_CHOCOLATE);
704 break;
706 case MSG_SET:
707 twCC = msg_set(pCapability, &val);
708 if (twCC == TWCC_SUCCESS)
710 FIXME("Stub: PIXELFLAVOR set to %d, but ignored\n", val);
712 break;
714 case MSG_GETDEFAULT:
715 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
716 break;
718 case MSG_RESET:
719 /* .. fall through intentional .. */
721 case MSG_GETCURRENT:
722 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
723 break;
725 return twCC;
729 TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
731 TW_UINT16 twCC = TWCC_CAPUNSUPPORTED;
733 TRACE("capability=%d action=%d\n", pCapability->Cap, action);
735 switch (pCapability->Cap)
737 case CAP_SUPPORTEDCAPS:
738 if (action == MSG_GET)
739 twCC = TWAIN_GetSupportedCaps(pCapability);
740 else
741 twCC = TWCC_BADVALUE;
742 break;
744 case CAP_XFERCOUNT:
745 twCC = SANE_CAPXferCount (pCapability, action);
746 break;
748 case CAP_UICONTROLLABLE:
749 twCC = SANE_CAPUiControllable (pCapability, action);
750 break;
752 case ICAP_PIXELTYPE:
753 twCC = SANE_ICAPPixelType (pCapability, action);
754 break;
756 case ICAP_UNITS:
757 twCC = SANE_ICAPUnits (pCapability, action);
758 break;
760 case ICAP_BITDEPTH:
761 twCC = SANE_ICAPBitDepth(pCapability, action);
762 break;
764 case ICAP_XFERMECH:
765 twCC = SANE_ICAPXferMech (pCapability, action);
766 break;
768 case ICAP_PIXELFLAVOR:
769 twCC = SANE_ICAPPixelFlavor (pCapability, action);
770 break;
772 case ICAP_COMPRESSION:
773 twCC = SANE_ICAPCompression(pCapability, action);
774 break;
776 case ICAP_XRESOLUTION:
777 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
778 break;
780 case ICAP_YRESOLUTION:
781 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
782 break;
785 /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
786 * even if you don't formally support the capability */
787 if (twCC == TWCC_CAPUNSUPPORTED && action == MSG_QUERYSUPPORT)
788 twCC = set_onevalue(pCapability, 0, TWTY_INT32);
790 if (twCC == TWCC_CAPUNSUPPORTED)
791 TRACE("capability 0x%x/action=%d being reported as unsupported\n", pCapability->Cap, action);
793 return twCC;