Hi,
I have started adding gphoto2 support to twain.dll.
My current work (before a otherwise busy week begins again),
is attached.
I started to break up the currently very sane centric view.
Alexandre/Aric, can I do it this way? Some other general comments?
(The code btw works as-is for detection at least.)
Ciao, Marcus
Index: configure.ac
===================================================================
RCS file: /home/wine/wine/configure.ac,v
retrieving revision 1.468
diff -u -r1.468 configure.ac
--- configure.ac 6 Apr 2006 10:53:39 -0000 1.468
+++ configure.ac 9 Apr 2006 19:13:29 -0000
@@ -521,6 +521,37 @@
CPPFLAGS="$ac_save_CPPFLAGS"
fi
+dnl **** Check for libgphoto2 ****
+AC_CHECK_PROG(gphoto2_devel,gphoto2-config,gphoto2-config,no)
+AC_CHECK_PROG(gphoto2port_devel,gphoto2-port-config,gphoto2-port-config,no)
+AC_SUBST(GPHOTO2LIBS,"")
+AC_SUBST(GPHOTO2INCL,"")
+if test "$gphoto2_devel" != "no" -a "$gphoto2port_devel" != "no"
+then
+ GPHOTO2INCL="`$gphoto2_devel --cflags` `$gphoto2port_devel --cflags`"
+ GPHOTO2LIBS=""
+ for i in `$gphoto2_devel --libs` `$gphoto2port_devel --libs`
+ do
+ case "$i" in
+ -L/usr/lib|-L/usr/lib64) ;;
+ -L*|-l*) GPHOTO2LIBS="$GPHOTO2LIBS $i";;
+ esac
+ done
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ ac_save_LIBS="$LIBS"
+ CPPFLAGS="$CPPFLAGS $GPHOTO2INCL"
+ LIBS="$LIBS $GPHOTO2LIBS"
+ AC_CHECK_HEADER(gphoto2-camera.h,
+ [AC_CHECK_LIB(gphoto2,gp_camera_new,
+ [AC_DEFINE(HAVE_GPHOTO2, 1, [Define if we have libgphoto2 development environment])],
+ [GPHOTO2LIBS=""
+ GPHOTO2INCL=""])],
+ [GPHOTO2LIBS=""
+ GPHOTO2INCL=""])
+ LIBS="$ac_save_LIBS"
+ CPPFLAGS="$ac_save_CPPFLAGS"
+fi
+
dnl **** Check for the ICU library ****
if test "$ac_cv_header_unicode_ubidi_h" = "yes"
then
Index: dlls/twain/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/twain/Makefile.in,v
retrieving revision 1.10
diff -u -r1.10 Makefile.in
--- dlls/twain/Makefile.in 28 Mar 2006 18:13:00 -0000 1.10
+++ dlls/twain/Makefile.in 9 Apr 2006 19:13:29 -0000
@@ -4,8 +4,8 @@
VPATH = @srcdir@
MODULE = twain_32.dll
IMPORTS = comctl32 user32 gdi32 kernel32 ntdll
-EXTRALIBS = @SANELIBS@
-EXTRAINCL = @SANEINCL@
+EXTRALIBS = @SANELIBS@ @GPHOTO2LIBS@
+EXTRAINCL = @SANEINCL@ @GPHOTO2INCL@
C_SRCS = \
capability.c \
Index: dlls/twain/ds_ctrl.c
===================================================================
RCS file: /home/wine/wine/dlls/twain/ds_ctrl.c,v
retrieving revision 1.6
diff -u -r1.6 ds_ctrl.c
--- dlls/twain/ds_ctrl.c 28 Mar 2006 18:13:00 -0000 1.6
+++ dlls/twain/ds_ctrl.c 9 Apr 2006 19:13:29 -0000
@@ -648,27 +650,37 @@
if (pUserInterface->ShowUI)
{
BOOL rc;
+ FIXME("Showing UI now.\n");
pSource->currentState = 5; /* Transitions to state 5 */
- rc = DoScannerUI(pSource);
- if (!rc)
- {
- pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
- }
+ switch (devices[pSource->deviceIndex].type) {
#ifdef HAVE_SANE
- else
- {
- sane_get_parameters (pSource->deviceHandle, &pSource->sane_param);
- pSource->sane_param_valid = TRUE;
- }
+ case DEVTYPE_SANE:
+ rc = DoScannerUI(pSource);
+ if (!rc) {
+ pSource->pendingEvent.TWMessage = MSG_CLOSEDSREQ;
+ } else {
+ sane_get_parameters (pSource->deviceHandle, &pSource->sane_param);
+ pSource->sane_param_valid = TRUE;
+ }
+ break;
#endif
- }
- else
- {
+#ifdef HAVE_GPHOTO2
+ case DEVTYPE_GPHOTO:
+ FIXME("No GPHOTO UI yet.\n");
+ pSource->pendingEvent.TWMessage = MSG_XFERREADY;
+ pSource->currentState = 6; /* Transitions to state 6 directly */
+ break;
+#endif
+ default:
+ FIXME("Device type %d is unknown\n", devices[pSource->deviceIndex].type);
+ break;
+ }
+ } else {
+ FIXME("UI not shown, preparing to transfer data.\n");
/* no UI will be displayed, so source is ready to transfer data */
pSource->pendingEvent.TWMessage = MSG_XFERREADY;
pSource->currentState = 6; /* Transitions to state 6 directly */
}
-
pSource->hwndOwner = pUserInterface->hParent;
twRC = TWRC_SUCCESS;
pSource->twCC = TWCC_SUCCESS;
Index: dlls/twain/ds_image.c
===================================================================
RCS file: /home/wine/wine/dlls/twain/ds_image.c,v
retrieving revision 1.8
diff -u -r1.8 ds_image.c
--- dlls/twain/ds_image.c 28 Mar 2006 18:13:00 -0000 1.8
+++ dlls/twain/ds_image.c 9 Apr 2006 19:13:29 -0000
@@ -80,76 +80,81 @@
TW_UINT16 TWAIN_ImageInfoGet (pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
- activeDS *pSource = TWAIN_LookupSource (pDest);
- SANE_Status status;
-
- TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
-
- if (!pSource)
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_BADDEST;
- }
- else if (pSource->currentState != 6 && pSource->currentState != 7)
- {
- twRC = TWRC_FAILURE;
- pSource->twCC = TWCC_SEQERROR;
- }
- else
- {
- if (pSource->currentState == 6)
- {
- /* return general image description information about the image about to be transferred */
- status = sane_get_parameters (pSource->deviceHandle, &pSource->sane_param);
- pSource->sane_param_valid = TRUE;
- TRACE("Getting parameters\n");
- }
+ pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
+ activeDS *pSource = TWAIN_LookupSource (pDest);
- pImageInfo->XResolution.Whole = -1;
- pImageInfo->XResolution.Frac = 0;
- pImageInfo->YResolution.Whole = -1;
- pImageInfo->YResolution.Frac = 0;
- pImageInfo->ImageWidth = pSource->sane_param.pixels_per_line;
- pImageInfo->ImageLength = pSource->sane_param.lines;
+ TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
- TRACE("Bits per Sample %i\n",pSource->sane_param.depth);
- TRACE("Frame Format %i\n",pSource->sane_param.format);
-
- if (pSource->sane_param.format == SANE_FRAME_RGB )
- {
- pImageInfo->BitsPerPixel = pSource->sane_param.depth * 3;
- pImageInfo->Compression = TWCP_NONE;
- pImageInfo->Planar = TRUE;
- pImageInfo->SamplesPerPixel = 3;
- pImageInfo->BitsPerSample[0] = pSource->sane_param.depth;
- pImageInfo->BitsPerSample[1] = pSource->sane_param.depth;
- pImageInfo->BitsPerSample[2] = pSource->sane_param.depth;
- pImageInfo->PixelType = TWPT_RGB;
- }
- else if (pSource->sane_param.format == SANE_FRAME_GRAY)
- {
- pImageInfo->BitsPerPixel = pSource->sane_param.depth;
- pImageInfo->Compression = TWCP_NONE;
- pImageInfo->Planar = TRUE;
- pImageInfo->SamplesPerPixel = 1;
- pImageInfo->BitsPerSample[0] = pSource->sane_param.depth;
- pImageInfo->PixelType = TWPT_GRAY;
- }
- else
- {
- ERR("Unhandled source frame type %i\n",pSource->sane_param.format);
- twRC = TWRC_FAILURE;
- pSource->twCC = TWCC_SEQERROR;
- }
- }
-
- return twRC;
+ if (!pSource) {
+ FIXME("no source\n");
+ DSM_twCC = TWCC_BADDEST;
+ return TWRC_FAILURE;
+ }
+ if (pSource->currentState != 6 && pSource->currentState != 7) {
+ FIXME("bad state %d\n", pSource->currentState);
+ pSource->twCC = TWCC_SEQERROR;
+ return TWRC_FAILURE;
+ }
+
+ switch (devices[pSource->deviceIndex].type) {
+#ifdef HAVE_SANE
+ case DEVTYPE_SANE: {
+ SANE_Status status;
+ if (pSource->currentState == 6)
+ {
+ /* return general image description information about the image about to be transferred */
+ status = sane_get_parameters (pSource->deviceHandle, &pSource->sane_param);
+ pSource->sane_param_valid = TRUE;
+ TRACE("Getting parameters\n");
+ }
+
+ pImageInfo->XResolution.Whole = -1;
+ pImageInfo->XResolution.Frac = 0;
+ pImageInfo->YResolution.Whole = -1;
+ pImageInfo->YResolution.Frac = 0;
+ pImageInfo->ImageWidth = pSource->sane_param.pixels_per_line;
+ pImageInfo->ImageLength = pSource->sane_param.lines;
+
+ TRACE("Bits per Sample %i\n",pSource->sane_param.depth);
+ TRACE("Frame Format %i\n",pSource->sane_param.format);
+
+ if (pSource->sane_param.format == SANE_FRAME_RGB )
+ {
+ pImageInfo->BitsPerPixel = pSource->sane_param.depth * 3;
+ pImageInfo->Compression = TWCP_NONE;
+ pImageInfo->Planar = TRUE;
+ pImageInfo->SamplesPerPixel = 3;
+ pImageInfo->BitsPerSample[0] = pSource->sane_param.depth;
+ pImageInfo->BitsPerSample[1] = pSource->sane_param.depth;
+ pImageInfo->BitsPerSample[2] = pSource->sane_param.depth;
+ pImageInfo->PixelType = TWPT_RGB;
+ }
+ else if (pSource->sane_param.format == SANE_FRAME_GRAY)
+ {
+ pImageInfo->BitsPerPixel = pSource->sane_param.depth;
+ pImageInfo->Compression = TWCP_NONE;
+ pImageInfo->Planar = TRUE;
+ pImageInfo->SamplesPerPixel = 1;
+ pImageInfo->BitsPerSample[0] = pSource->sane_param.depth;
+ pImageInfo->PixelType = TWPT_GRAY;
+ }
+ else
+ {
+ ERR("Unhandled source frame type %i\n",pSource->sane_param.format);
+ pSource->twCC = TWCC_SEQERROR;
+ return TWRC_FAILURE;
+ }
+ break;
+ }
#endif
+ case DEVTYPE_GPHOTO:
+ FIXME("gphoto case\n");
+ break;
+ default:
+ FIXME("Unknown devtype %d\n", devices[pSource->deviceIndex].type);
+ break;
+ }
+ return TWRC_SUCCESS;
}
/* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
Index: dlls/twain/dsm_ctrl.c
===================================================================
RCS file: /home/wine/wine/dlls/twain/dsm_ctrl.c,v
retrieving revision 1.13
diff -u -r1.13 dsm_ctrl.c
--- dlls/twain/dsm_ctrl.c 28 Mar 2006 18:13:00 -0000 1.13
+++ dlls/twain/dsm_ctrl.c 9 Apr 2006 19:13:29 -0000
@@ -2,6 +2,7 @@
* TWAIN32 Source Manager
*
* Copyright 2000 Corel Corporation
+ * Copyright 2006 Marcus Meissner
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,54 +35,149 @@
WINE_DEFAULT_DEBUG_CHANNEL(twain);
-/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
-TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
-{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
- activeDS *currentDS = NULL, *prevDS = NULL;
+int nrdevices = 0;
+struct all_devices *devices = NULL;
- TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
+static int detectionrun = 0;
- for (currentDS = activeSources; currentDS; currentDS = currentDS->next)
- {
- if (currentDS->identity.Id == pIdentity->Id)
- break;
- prevDS = currentDS;
- }
- if (currentDS)
- {
- /* Only valid to close a data source if it is in state 4 */
- if (currentDS->currentState == 4)
- {
- sane_close (currentDS->deviceHandle);
- /* remove the data source from active data source list */
- if (prevDS)
- prevDS->next = currentDS->next;
- else
- activeSources = currentDS->next;
- HeapFree (GetProcessHeap(), 0, currentDS);
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
+static void
+detect_sane_devices() {
+#ifdef HAVE_SANE
+ const SANE_Device **sane_devlist;
+ int i;
+
+ FIXME("detecting sane...\n");
+ if (sane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
+ return;
+ for ( i=0;
+ sane_devlist[i] &&
+ sane_devlist[i]->model &&
+ sane_devlist[i]->vendor &&
+ sane_devlist[i]->name;
+ i++
+ ) {
+ if (nrdevices)
+ devices = realloc(devices, sizeof(devices[0])*(nrdevices+1));
+ else
+ devices = malloc(sizeof(devices[0]));
+ devices[nrdevices].type = DEVTYPE_SANE;
+ devices[nrdevices].u.sane.dev = sane_devlist[i];
+ nrdevices++;
+ }
+ return;
+#endif
+}
+
+static void
+detect_gphoto_devices() {
+#ifdef HAVE_GPHOTO2
+ int x, count;
+ CameraList *list;
+ CameraAbilitiesList *al = NULL;
+ int result;
+
+ GPPortInfoList *plist = NULL;
+
+ TRACE("detecting gphoto...\n");
+ if (gp_port_info_list_new (&plist) < GP_OK)
+ return;
+ result = gp_port_info_list_load (plist);
+ if (result < 0) {
+ gp_port_info_list_free (plist);
+ return;
}
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_SEQERROR;
+ count = gp_port_info_list_count (plist);
+ if (count <= 0)
+ return;
+ if (gp_list_new (&list) < GP_OK)
+ return;
+ gp_abilities_list_new (&al);
+ gp_abilities_list_load (al, NULL);
+ gp_abilities_list_detect (al, plist, list, NULL);
+ gp_abilities_list_free (al);
+
+ count = gp_list_count (list);
+ if (count < GP_OK) {
+ gp_list_free (list);
+ return;
+ }
+ for (x = 0; x < count; x++) {
+ const char *s;
+ if (nrdevices)
+ devices = realloc(devices, sizeof(devices[0])*(nrdevices+1));
+ else
+ devices = malloc(sizeof(devices[0]));
+ devices[nrdevices].type = DEVTYPE_GPHOTO;
+ gp_list_get_name (list, x, &s);
+ devices[nrdevices].u.gphoto.name = strdup(s);
+ gp_list_get_value (list, x, &s);
+ devices[nrdevices].u.gphoto.port = strdup(s);
+ TRACE("Adding gphoto device %s:%s...\n", devices[nrdevices].u.gphoto.name, devices[nrdevices].u.gphoto.port);
+ nrdevices++;
}
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
- }
+ gp_list_free (list);
+#endif
+}
- return twRC;
+static void
+twain_autodetect() {
+ if (detectionrun) return;
+ detectionrun = 1;
+
+ detect_sane_devices();
+ detect_gphoto_devices();
+}
+
+/* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
+TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
+{
+ TW_UINT16 twRC = TWRC_SUCCESS;
+ pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
+ activeDS *currentDS = NULL, *prevDS = NULL;
+
+ TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
+
+ for (currentDS = activeSources; currentDS; currentDS = currentDS->next) {
+ if (currentDS->identity.Id == pIdentity->Id)
+ break;
+ prevDS = currentDS;
+ }
+ if (currentDS) {
+ /* Only valid to close a data source if it is in state 4 */
+ if (currentDS->currentState == 4) {
+ switch (devices[currentDS->deviceIndex].type) {
+#ifdef HAVE_SANE
+ case DEVTYPE_SANE:
+ sane_close (currentDS->deviceHandle);
+ break;
+#endif
+#ifdef HAVE_GPHOTO2
+ case DEVTYPE_GPHOTO:
+ gp_camera_exit (currentDS->camera, NULL);
+ currentDS->camera = NULL;
+ break;
#endif
+ default:
+ FIXME("Unknown devtype %d\n", devices[currentDS->deviceIndex].type);
+ break;
+ }
+ /* remove the data source from active data source list */
+ if (prevDS)
+ prevDS->next = currentDS->next;
+ else
+ activeSources = currentDS->next;
+ HeapFree (GetProcessHeap(), 0, currentDS);
+ twRC = TWRC_SUCCESS;
+ DSM_twCC = TWCC_SUCCESS;
+ } else {
+ twRC = TWRC_FAILURE;
+ DSM_twCC = TWCC_SEQERROR;
+ }
+ } else {
+ twRC = TWRC_FAILURE;
+ DSM_twCC = TWCC_NODS;
+ }
+ return twRC;
}
/* Sane returns device names that are longer than the 32 bytes allowed
@@ -118,229 +214,221 @@
}
#endif
+static int
+_get_id(pTW_IDENTITY pSourceIdentity, int i) {
+ pSourceIdentity->Id = DSM_sourceId++;
+ pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
+ pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
+
+ /* FIXME: the default device is not necessarily the first device. *
+ * Users should be able to choose the default device */
+ switch (devices[i].type) {
+#ifdef HAVE_SANE
+ case DEVTYPE_SANE: {
+ copy_sane_short_name(devices[i].u.sane.dev->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
+ TRACE("got: %s (short [%s]), %s, %s\n",
+ devices[i].u.sane.dev->name,
+ pSourceIdentity->ProductName,
+ devices[i].u.sane.dev->vendor,
+ devices[i].u.sane.dev->model
+ );
+ lstrcpynA (pSourceIdentity->Manufacturer, devices[i].u.sane.dev->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
+ lstrcpynA (pSourceIdentity->ProductFamily, devices[i].u.sane.dev->model, sizeof(pSourceIdentity->ProductFamily) - 1);
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_SUCCESS;
+ }
+#endif
+ case DEVTYPE_GPHOTO: {
+ TRACE ("return gphoto entry %s.%s\n", devices[i].u.gphoto.name, devices[i].u.gphoto.port);
+ lstrcpynA (pSourceIdentity->Manufacturer, devices[i].u.gphoto.name, sizeof(pSourceIdentity->Manufacturer) - 1);
+ lstrcpynA (pSourceIdentity->ProductFamily, "GPhoto Camera", sizeof(pSourceIdentity->ProductFamily) - 1);
+ lstrcpynA (pSourceIdentity->ProductName, devices[i].u.gphoto.port, sizeof(pSourceIdentity->ProductName) - 1);
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_SUCCESS;
+ }
+ default:
+ TRACE("No TWAIN device available.\n");
+ DSM_twCC = TWCC_NODS;
+ return TWRC_FAILURE;
+ }
+}
+
/* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
-
- TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
-
- if (!device_list)
- {
- if ((sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
- {
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
- }
- }
-
- /* FIXME: the default device is not necessarily the first device. *
- * Users should be able to choose the default device */
- if (device_list && device_list[0])
- {
- pSourceIdentity->Id = DSM_sourceId ++;
- copy_sane_short_name(device_list[0]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
- TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, pSourceIdentity->ProductName, device_list[0]->vendor, device_list[0]->model);
- lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
- lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
- pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
- pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
-
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
-
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
- }
+ pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
- return twRC;
-#endif
+ TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
+ DSM_twCC = TWCC_NODS;
+ twain_autodetect();
+ if (!nrdevices)
+ return TWRC_FAILURE;
+ return _get_id(pSourceIdentity,0);
}
/* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
- SANE_Status status;
-
- TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
-
- device_list = NULL;
- status = sane_get_devices (&device_list, SANE_FALSE);
- if (status == SANE_STATUS_GOOD)
- {
- if (device_list[0])
- {
- pSourceIdentity->Id = DSM_sourceId ++;
- copy_sane_short_name(device_list[0]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
- TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, pSourceIdentity->ProductName, device_list[0]->vendor, device_list[0]->model);
- lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
- lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
- pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
- pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
-
- DSM_currentDevice = 1;
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
- }
- else
- {
- TRACE("got empty device list\n");
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
- }
- }
- else if (status == SANE_STATUS_NO_MEM)
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_LOWMEMORY;
- }
- else
- {
- WARN("sane_get_devices() failed: %s\n", sane_strstatus (status));
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
- }
+ pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
- return twRC;
-#endif
+ TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
+ twain_autodetect();
+ if (!nrdevices) {
+ TRACE ("no entries found.\n");
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_ENDOFLIST;
+ }
+ DSM_currentDevice = 0;
+ return _get_id(pSourceIdentity,DSM_currentDevice++);
}
/* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_SUCCESS;
- return TWRC_ENDOFLIST;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
-
- TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
-
- if (device_list && device_list[DSM_currentDevice] &&
- device_list[DSM_currentDevice]->name &&
- device_list[DSM_currentDevice]->vendor &&
- device_list[DSM_currentDevice]->model)
- {
- pSourceIdentity->Id = DSM_sourceId ++;
- copy_sane_short_name(device_list[DSM_currentDevice]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
- TRACE("got: %s (short [%s]), %s, %s\n", device_list[DSM_currentDevice]->name, pSourceIdentity->ProductName, device_list[DSM_currentDevice]->vendor, device_list[DSM_currentDevice]->model);
- lstrcpynA (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
- lstrcpynA (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
- pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
- pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
- DSM_currentDevice ++;
-
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
- }
- else
- {
- DSM_twCC = TWCC_SUCCESS;
- twRC = TWRC_ENDOFLIST;
- }
+ pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
- return twRC;
-#endif
+ TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
+ if (!nrdevices || (DSM_currentDevice == nrdevices)) {
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_ENDOFLIST;
+ }
+ return _get_id(pSourceIdentity,DSM_currentDevice++);
}
/* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
+ TW_UINT16 i = 0;
+ pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
+ TW_STR32 shortname;
+ activeDS *newSource;
+
+ TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
+
+ if (DSM_currentState != 3) {
+ DSM_twCC = TWCC_SEQERROR;
+ FIXME("sequence error\n");
+ return TWRC_FAILURE;
+ }
+ twain_autodetect();
+ if (!nrdevices) {
+ DSM_twCC = TWCC_NODS;
+ FIXME("No devices.\n");
+ return TWRC_FAILURE;
+ }
+
+ if (pIdentity->ProductName[0] != '\0') {
+ /* Make sure the source to be opened exists in the device list */
+ for (i = 0; i<nrdevices; i++) {
+ int found = 0;
+ switch (devices[i].type) {
+#ifdef HAVE_SANE
+ case DEVTYPE_SANE:
+ copy_sane_short_name(devices[i].u.sane.dev->name, shortname, sizeof(shortname) - 1);
+ if (strcmp (shortname, pIdentity->ProductName) == 0)
+ found = 1;
+ break;
+#endif
+ case DEVTYPE_GPHOTO:
+ if (strcmp (devices[i].u.gphoto.port, pIdentity->ProductName) == 0)
+ found = 1;
+ break;
+ default:break;
+ }
+ if (found)
+ break;
+ }
+ if (i == nrdevices)
+ i=0;
+ } /* else use the first device */
+
+ /* the source is found in the device list */
+ newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
+ if (!newSource) {
+ DSM_twCC = TWCC_LOWMEMORY;
+ FIXME("Out of memory.\n");
+ return TWRC_FAILURE;
+ }
+ newSource->deviceIndex = i;
+ switch (devices[i].type) {
+#ifdef HAVE_SANE
+ case DEVTYPE_SANE: {
+ SANE_Status status;
+ status = sane_open(devices[i].u.sane.dev->name,&newSource->deviceHandle);
+ if (status == SANE_STATUS_GOOD) {
+ /* Assign name and id for the opened data source */
+ lstrcpynA (pIdentity->ProductName, shortname, sizeof(pIdentity->ProductName) - 1);
+ pIdentity->Id = DSM_sourceId ++;
+ /* add the data source to an internal active source list */
+ newSource->next = activeSources;
+ newSource->identity.Id = pIdentity->Id;
+ strcpy (newSource->identity.ProductName, pIdentity->ProductName);
+ newSource->currentState = 4; /*transition into state 4*/
+ newSource->twCC = TWCC_SUCCESS;
+ activeSources = newSource;
+ DSM_twCC = TWCC_SUCCESS;
+ return TWRC_SUCCESS;
+ } else {
+ DSM_twCC = TWCC_OPERATIONERROR;
+ return TWRC_FAILURE;
+ }
+ break;
+ }
+#endif
+ case DEVTYPE_GPHOTO: {
+#ifdef HAVE_GPHOTO2
+ int ret, m;
+ CameraAbilities a;
+ CameraAbilitiesList *al = NULL;
+
+
+ DSM_twCC = TWCC_OPERATIONERROR;
+ ret = gp_camera_new (&newSource->camera);
+ if (ret < GP_OK) {
+ FIXME("failed to gp_camera_new\n");
+ return TWRC_FAILURE;
+ }
+
+ gp_abilities_list_new (&al);
+ gp_abilities_list_load (al, NULL);
+ m = gp_abilities_list_lookup_model (al, devices[i].u.gphoto.name);
+ if (m < GP_OK) {
+ FIXME("failed to gp_camera_list_lookup_model\n");
+ return TWRC_FAILURE;
+ }
+ ret = gp_abilities_list_get_abilities (al, m, &a);
+ if (ret < GP_OK) {
+ FIXME("failed to gp_camera_list_get_abilities\n");
+ return TWRC_FAILURE;
+ }
+ ret = gp_camera_set_abilities (newSource->camera, a);
+ if (ret < GP_OK) {
+ FIXME("failed to gp_camera_set_abilities\n");
+ return TWRC_FAILURE;
+ }
+ gp_abilities_list_free (al);
+ /* Assign name and id for the opened data source */
+ lstrcpynA (pIdentity->ProductName, shortname, sizeof(pIdentity->ProductName) - 1);
+ pIdentity->Id = DSM_sourceId ++;
+ /* add the data source to an internal active source list */
+ newSource->next = activeSources;
+ newSource->identity.Id = pIdentity->Id;
+ strcpy (newSource->identity.ProductName, pIdentity->ProductName);
+ newSource->currentState = 4; /*transition into state 4*/
+ newSource->twCC = TWCC_SUCCESS;
+ activeSources = newSource;
+ DSM_twCC = TWCC_SUCCESS;
+ TRACE("succeeded opening gphoto camera.\n");
+ return TWRC_SUCCESS;
#else
- TW_UINT16 twRC = TWRC_SUCCESS, i = 0;
- pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
- TW_STR32 shortname;
- activeDS *newSource;
- SANE_Status status;
-
- TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
-
- if (DSM_currentState != 3)
- {
- DSM_twCC = TWCC_SEQERROR;
- return TWRC_FAILURE;
- }
-
- if (!device_list &&
- (sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
- {
- DSM_twCC = TWCC_NODS;
- return TWRC_FAILURE;
- }
-
- if (pIdentity->ProductName[0] != '\0')
- {
- /* Make sure the source to be opened exists in the device list */
- for (i = 0; device_list[i]; i ++)
- {
- copy_sane_short_name(device_list[i]->name, shortname, sizeof(shortname) - 1);
- if (strcmp (shortname, pIdentity->ProductName) == 0)
- break;
- }
-
- }
-
- if (device_list[i])
- {
- /* the source is found in the device list */
- newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
- if (newSource)
- {
- newSource->deviceIndex = i;
- status = sane_open(device_list[i]->name,&newSource->deviceHandle);
- if (status == SANE_STATUS_GOOD)
- {
- /* Assign name and id for the opened data source */
- lstrcpynA (pIdentity->ProductName, shortname, sizeof(pIdentity->ProductName) - 1);
- pIdentity->Id = DSM_sourceId ++;
- /* add the data source to an internal active source list */
- newSource->next = activeSources;
- newSource->identity.Id = pIdentity->Id;
- strcpy (newSource->identity.ProductName, pIdentity->ProductName);
- newSource->currentState = 4; /*transition into state 4*/
- newSource->twCC = TWCC_SUCCESS;
- activeSources = newSource;
- twRC = TWRC_SUCCESS;
- DSM_twCC = TWCC_SUCCESS;
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_OPERATIONERROR;
- }
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_LOWMEMORY;
- }
- }
- else
- {
- twRC = TWRC_FAILURE;
- DSM_twCC = TWCC_NODS;
- }
-
- return twRC;
+ ERR("No gphoto support?\n");
#endif
+ }
+ default:
+ FIXME("default case, device type %d?\n", devices[i].type);
+ DSM_twCC = TWCC_OPERATIONERROR;
+ return TWRC_FAILURE;
+ }
}
/* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
@@ -351,7 +439,7 @@
#else
TW_UINT16 twRC = TWRC_SUCCESS;
- TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
+ FIXME("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
/* FIXME: we should replace xscanimage with our own User Select UI */
system("xscanimage");
@@ -404,50 +492,40 @@
/* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
-#ifndef HAVE_SANE
- return TWRC_FAILURE;
-#else
- TW_UINT16 twRC = TWRC_SUCCESS;
- SANE_Status status;
- SANE_Int version_code;
+ TW_UINT16 twRC = TWRC_SUCCESS;
- TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
-
- if (DSM_currentState == 2)
- {
- if (!DSM_initialized)
- {
- DSM_initialized = TRUE;
- status = sane_init (&version_code, NULL);
- device_list = NULL;
- DSM_currentDevice = 0;
- DSM_sourceId = 0;
- }
- DSM_parentHWND = *(TW_HANDLE*)pData;
- DSM_currentState = 3; /* transition to state 3 */
- DSM_twCC = TWCC_SUCCESS;
- twRC = TWRC_SUCCESS;
- }
- else
- {
- /* operation invoked in invalid state */
- DSM_twCC = TWCC_SEQERROR;
- twRC = TWRC_FAILURE;
- }
+ TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
+ if (DSM_currentState == 2) {
+ if (!DSM_initialized) {
+#ifdef HAVE_SANE
+ SANE_Status status;
+ SANE_Int version_code;
- return twRC;
+ status = sane_init (&version_code, NULL);
#endif
+ DSM_currentDevice = 0;
+ DSM_initialized = TRUE;
+ }
+ DSM_parentHWND = *(TW_HANDLE*)pData;
+ DSM_currentState = 3; /* transition to state 3 */
+ DSM_twCC = TWCC_SUCCESS;
+ twRC = TWRC_SUCCESS;
+ } else {
+ /* operation invoked in invalid state */
+ DSM_twCC = TWCC_SEQERROR;
+ twRC = TWRC_FAILURE;
+ }
+ return twRC;
}
/* DG_CONTROL/DAT_STATUS/MSG_GET */
TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
{
- pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
+ pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
- TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
+ TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
- pSourceStatus->ConditionCode = DSM_twCC;
- DSM_twCC = TWCC_SUCCESS; /* clear the condition code */
-
- return TWRC_SUCCESS;
+ pSourceStatus->ConditionCode = DSM_twCC;
+ DSM_twCC = TWCC_SUCCESS; /* clear the condition code */
+ return TWRC_SUCCESS;
}
Index: dlls/twain/twain_i.h
===================================================================
RCS file: /home/wine/wine/dlls/twain/twain_i.h,v
retrieving revision 1.8
diff -u -r1.8 twain_i.h
--- dlls/twain/twain_i.h 28 Mar 2006 18:13:00 -0000 1.8
+++ dlls/twain/twain_i.h 9 Apr 2006 19:13:29 -0000
@@ -28,6 +28,13 @@
#endif
#include <stdarg.h>
+#ifdef HAVE_GPHOTO2
+/* Hack ... otherwise gphoto2 thinks its on Windows */
+# undef WIN32
+# include <gphoto2/gphoto2-camera.h>
+# define WIN32
+#endif
+
#include "windef.h"
#include "winbase.h"
#include "twain.h"
@@ -43,12 +50,15 @@
TW_UINT16 twCC; /* condition code */
HWND hwndOwner; /* window handle of the app */
HWND progressWnd; /* window handle of the scanning window */
+ INT deviceIndex; /* index of the current device */
#ifdef HAVE_SANE
SANE_Handle deviceHandle; /* device handle */
SANE_Parameters sane_param; /* parameters about the image
transferred */
- BOOL sane_param_valid; /* true if valid sane_param*/
- INT deviceIndex; /* index of the current device */
+ BOOL sane_param_valid; /* true if valid sane_param*/
+#endif
+#ifdef HAVE_GPHOTO2
+ Camera *camera;
#endif
/* Capabiblities */
TW_UINT16 capXferMech; /* ICAP_XFERMECH */
@@ -62,9 +72,33 @@
TW_UINT16 DSM_currentDevice; /* keep track of device during enumeration */
HINSTANCE DSM_instance;
+enum twain_devtype {
+ DEVTYPE_SANE,
+ DEVTYPE_GPHOTO
+};
+
+struct sane_device {
#ifdef HAVE_SANE
-const SANE_Device **device_list;/* a list of all sane devices */
+ const SANE_Device *dev;
#endif
+};
+
+struct gphoto_device {
+ const char *name;
+ const char *port;
+};
+
+struct all_devices {
+ enum twain_devtype type;
+ union {
+ struct sane_device sane;
+ struct gphoto_device gphoto;
+ } u;
+};
+
+extern int nrdevices;
+extern struct all_devices *devices;
+
activeDS *activeSources; /* list of active data sources */
/* Helper functions */
Index: dlls/twain/ui.c
===================================================================
RCS file: /home/wine/wine/dlls/twain/ui.c,v
retrieving revision 1.1
diff -u -r1.1 ui.c
--- dlls/twain/ui.c 28 Mar 2006 18:13:00 -0000 1.1
+++ dlls/twain/ui.c 9 Apr 2006 19:13:30 -0000
@@ -574,15 +574,15 @@
index ++;
}
- len = lstrlenA(device_list[pSource->deviceIndex]->vendor)
- + lstrlenA(device_list[pSource->deviceIndex]->model) + 2;
+ len = lstrlenA(devices[pSource->deviceIndex].u.sane.dev->vendor)
+ + lstrlenA(devices[pSource->deviceIndex].u.sane.dev->model) + 2;
szCaption = HeapAlloc(GetProcessHeap(),0,len *sizeof(WCHAR));
- MultiByteToWideChar(CP_ACP,0,device_list[pSource->deviceIndex]->vendor,-1,
+ MultiByteToWideChar(CP_ACP,0,devices[pSource->deviceIndex].u.sane.dev->vendor,-1,
szCaption,len);
- szCaption[lstrlenA(device_list[pSource->deviceIndex]->vendor)] = ' ';
- MultiByteToWideChar(CP_ACP,0,device_list[pSource->deviceIndex]->model,-1,
- &szCaption[lstrlenA(device_list[pSource->deviceIndex]->vendor)+1],len);
+ szCaption[lstrlenA(devices[pSource->deviceIndex].u.sane.dev->vendor)] = ' ';
+ MultiByteToWideChar(CP_ACP,0,devices[pSource->deviceIndex].u.sane.dev->model,-1,
+ &szCaption[lstrlenA(devices[pSource->deviceIndex].u.sane.dev->vendor)+1],len);
psh.dwSize = sizeof(PROPSHEETHEADERW);
psh.dwFlags = PSH_PROPSHEETPAGE|PSH_PROPTITLE|PSH_USECALLBACK;