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;