comctl32: A couple fixes for tab icon offsets.
[wine] / dlls / twain / dsm_ctrl.c
1 /*
2  * TWAIN32 Source Manager
3  *
4  * Copyright 2000 Corel Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winbase.h"
31 #include "twain.h"
32 #include "twain_i.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(twain);
36
37 /* DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS */
38 TW_UINT16 TWAIN_CloseDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
39 {
40 #ifndef HAVE_SANE
41     DSM_twCC = TWCC_NODS;
42     return TWRC_FAILURE;
43 #else
44     TW_UINT16 twRC = TWRC_SUCCESS;
45     pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
46     activeDS *currentDS = NULL, *prevDS = NULL;
47
48     TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_CLOSEDS\n");
49
50     for (currentDS = activeSources; currentDS; currentDS = currentDS->next)
51     {
52         if (currentDS->identity.Id == pIdentity->Id)
53             break;
54         prevDS = currentDS;
55     }
56     if (currentDS)
57     {
58         /* Only valid to close a data source if it is in state 4 */
59         if (currentDS->currentState == 4)
60         {
61             sane_close (currentDS->deviceHandle);
62             /* remove the data source from active data source list */
63             if (prevDS)
64                 prevDS->next = currentDS->next;
65             else
66                 activeSources = currentDS->next;
67             HeapFree (GetProcessHeap(), 0, currentDS);
68             twRC = TWRC_SUCCESS;
69             DSM_twCC = TWCC_SUCCESS;
70         }
71         else
72         {
73             twRC = TWRC_FAILURE;
74             DSM_twCC = TWCC_SEQERROR;
75         }
76     }
77     else
78     {
79         twRC = TWRC_FAILURE;
80         DSM_twCC = TWCC_NODS;
81     }
82
83     return twRC;
84 #endif
85 }
86
87 /* Sane returns device names that are longer than the 32 bytes allowed
88    by TWAIN.  However, it colon separates them, and the last bit is
89    the most interesting.  So we use the last bit, and add a signature
90    to ensure uniqueness */
91 #ifdef HAVE_SANE
92 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
93 {
94     const char *p;
95     int  signature = 0;
96
97     if (strlen(in) <= outsize - 1)
98     {
99         strcpy(out, in);
100         return;
101     }
102
103     for (p = in; *p; p++)
104         signature += *p;
105
106     p = strrchr(in, ':');
107     if (!p)
108         p = in;
109     else
110         p++;
111
112     if (strlen(p) > outsize - 7 - 1)
113         p += strlen(p) - (outsize - 7 - 1);
114
115     strcpy(out, p);
116     sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
117
118 }
119 #endif
120
121 /* DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT */
122 TW_UINT16 TWAIN_IdentityGetDefault (pTW_IDENTITY pOrigin, TW_MEMREF pData)
123 {
124 #ifndef HAVE_SANE
125     DSM_twCC = TWCC_NODS;
126     return TWRC_FAILURE;
127 #else
128     TW_UINT16 twRC = TWRC_SUCCESS;
129     pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
130
131     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETDEFAULT\n");
132
133     if (!device_list)
134     {
135         if ((sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
136         {
137             DSM_twCC = TWCC_NODS;
138             return TWRC_FAILURE;
139         }
140     }
141
142     /* FIXME: the default device is not necessarily the first device.  *
143      * Users should be able to choose the default device               */
144     if (device_list && device_list[0])
145     {
146         pSourceIdentity->Id = DSM_sourceId ++;
147         copy_sane_short_name(device_list[0]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
148         TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, pSourceIdentity->ProductName, device_list[0]->vendor, device_list[0]->model);
149         lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
150         lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
151         pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
152         pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
153
154         twRC = TWRC_SUCCESS;
155         DSM_twCC = TWCC_SUCCESS;
156
157     }
158     else
159     {
160         twRC = TWRC_FAILURE;
161         DSM_twCC = TWCC_NODS;
162     }
163
164     return twRC;
165 #endif
166 }
167
168 /* DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST */
169 TW_UINT16 TWAIN_IdentityGetFirst (pTW_IDENTITY pOrigin, TW_MEMREF pData)
170 {
171 #ifndef HAVE_SANE
172     DSM_twCC = TWCC_NODS;
173     return TWRC_FAILURE;
174 #else
175     TW_UINT16 twRC = TWRC_SUCCESS;
176     pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
177     SANE_Status status;
178
179     TRACE ("DG_CONTROL/DAT_IDENTITY/MSG_GETFIRST\n");
180
181     device_list = NULL;
182     status = sane_get_devices (&device_list, SANE_FALSE);
183     if (status == SANE_STATUS_GOOD)
184     {
185         if (device_list[0])
186         {
187             pSourceIdentity->Id = DSM_sourceId ++;
188             copy_sane_short_name(device_list[0]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
189             TRACE("got: %s (short [%s]), %s, %s\n", device_list[0]->name, pSourceIdentity->ProductName, device_list[0]->vendor, device_list[0]->model);
190             lstrcpynA (pSourceIdentity->Manufacturer, device_list[0]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
191             lstrcpynA (pSourceIdentity->ProductFamily, device_list[0]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
192             pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
193             pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
194
195             DSM_currentDevice = 1;
196             twRC = TWRC_SUCCESS;
197             DSM_twCC = TWCC_SUCCESS;
198         }
199         else
200         {
201             TRACE("got empty device list\n");
202             twRC = TWRC_FAILURE;
203             DSM_twCC = TWCC_NODS;
204         }
205     }
206     else if (status == SANE_STATUS_NO_MEM)
207     {
208         twRC = TWRC_FAILURE;
209         DSM_twCC = TWCC_LOWMEMORY;
210     }
211     else
212     {
213         WARN("sane_get_devices() failed: %s\n", sane_strstatus (status));
214         twRC = TWRC_FAILURE;
215         DSM_twCC = TWCC_NODS;
216     }
217
218     return twRC;
219 #endif
220 }
221
222 /* DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT */
223 TW_UINT16 TWAIN_IdentityGetNext (pTW_IDENTITY pOrigin, TW_MEMREF pData)
224 {
225 #ifndef HAVE_SANE
226     DSM_twCC = TWCC_SUCCESS;
227     return TWRC_ENDOFLIST;
228 #else
229     TW_UINT16 twRC = TWRC_SUCCESS;
230     pTW_IDENTITY pSourceIdentity = (pTW_IDENTITY) pData;
231
232     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_GETNEXT\n");
233
234     if (device_list && device_list[DSM_currentDevice] &&
235         device_list[DSM_currentDevice]->name &&
236         device_list[DSM_currentDevice]->vendor &&
237         device_list[DSM_currentDevice]->model)
238     {
239         pSourceIdentity->Id = DSM_sourceId ++;
240         copy_sane_short_name(device_list[DSM_currentDevice]->name, pSourceIdentity->ProductName, sizeof(pSourceIdentity->ProductName) - 1);
241         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);
242         lstrcpynA (pSourceIdentity->Manufacturer, device_list[DSM_currentDevice]->vendor, sizeof(pSourceIdentity->Manufacturer) - 1);
243         lstrcpynA (pSourceIdentity->ProductFamily, device_list[DSM_currentDevice]->model, sizeof(pSourceIdentity->ProductFamily) - 1);
244         pSourceIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
245         pSourceIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
246         DSM_currentDevice ++;
247
248         twRC = TWRC_SUCCESS;
249         DSM_twCC = TWCC_SUCCESS;
250     }
251     else
252     {
253         DSM_twCC = TWCC_SUCCESS;
254         twRC = TWRC_ENDOFLIST;
255     }
256
257     return twRC;
258 #endif
259 }
260
261 /* DG_CONTROL/DAT_IDENTITY/MSG_OPENDS */
262 TW_UINT16 TWAIN_OpenDS (pTW_IDENTITY pOrigin, TW_MEMREF pData)
263 {
264 #ifndef HAVE_SANE
265     DSM_twCC = TWCC_NODS;
266     return TWRC_FAILURE;
267 #else
268     TW_UINT16 twRC = TWRC_SUCCESS, i = 0;
269     pTW_IDENTITY pIdentity = (pTW_IDENTITY) pData;
270     TW_STR32 shortname;
271     activeDS *newSource;
272     SANE_Status status;
273
274     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_OPENDS\n");
275
276     if (DSM_currentState != 3)
277     {
278         DSM_twCC = TWCC_SEQERROR;
279         return TWRC_FAILURE;
280     }
281
282     if (!device_list &&
283        (sane_get_devices (&device_list, SANE_FALSE) != SANE_STATUS_GOOD))
284     {
285         DSM_twCC = TWCC_NODS;
286         return TWRC_FAILURE;
287     }
288
289     if (pIdentity->ProductName[0] != '\0')
290     {
291         /* Make sure the source to be opened exists in the device list */
292         for (i = 0; device_list[i]; i ++)
293         {
294             copy_sane_short_name(device_list[i]->name, shortname, sizeof(shortname) - 1);
295             if (strcmp (shortname, pIdentity->ProductName) == 0)
296                 break;
297         }
298
299     }
300
301     if (device_list[i])
302     {
303         /* the source is found in the device list */
304         newSource = HeapAlloc (GetProcessHeap(), 0, sizeof (activeDS));
305         if (newSource)
306         {
307             status = sane_open(device_list[i]->name,&newSource->deviceHandle);
308             if (status == SANE_STATUS_GOOD)
309             {
310                 /* Assign name and id for the opened data source */
311                 lstrcpynA (pIdentity->ProductName, shortname, sizeof(pIdentity->ProductName) - 1);
312                 pIdentity->Id = DSM_sourceId ++;
313                 /* add the data source to an internal active source list */
314                 newSource->next = activeSources;
315                 newSource->identity.Id = pIdentity->Id;
316                 strcpy (newSource->identity.ProductName, pIdentity->ProductName);
317                 newSource->currentState = 4; /*transition into state 4*/
318                 newSource->twCC = TWCC_SUCCESS;
319                 activeSources = newSource;
320                 twRC = TWRC_SUCCESS;
321                 DSM_twCC = TWCC_SUCCESS;
322             }
323             else
324             {
325                 twRC = TWRC_FAILURE;
326                 DSM_twCC = TWCC_OPERATIONERROR;
327             }
328         }
329         else
330         {
331             twRC = TWRC_FAILURE;
332             DSM_twCC = TWCC_LOWMEMORY;
333         }
334     }
335     else
336     {
337         twRC = TWRC_FAILURE;
338         DSM_twCC = TWCC_NODS;
339     }
340
341     return twRC;
342 #endif
343 }
344
345 /* DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT */
346 TW_UINT16 TWAIN_UserSelect (pTW_IDENTITY pOrigin, TW_MEMREF pData)
347 {
348 #ifndef HAVE_SANE
349     return TWRC_SUCCESS;
350 #else
351     TW_UINT16 twRC = TWRC_SUCCESS;
352
353     TRACE("DG_CONTROL/DAT_IDENTITY/MSG_USERSELECT\n");
354
355     /* FIXME: we should replace xscanimage with our own  User Select UI */
356     system("xscanimage");
357
358     DSM_twCC = TWCC_SUCCESS;
359     return twRC;
360 #endif
361 }
362
363 /* DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM */
364 TW_UINT16 TWAIN_CloseDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
365 {
366 #ifndef HAVE_SANE
367     return TWRC_FAILURE;
368 #else
369     TW_UINT16 twRC = TWRC_SUCCESS;
370     activeDS *currentDS = activeSources, *nextDS;
371
372     TRACE("DG_CONTROL/DAT_PARENT/MSG_CLOSEDSM\n");
373
374     if (DSM_currentState == 3)
375     {
376         sane_exit ();
377         DSM_initialized = FALSE;
378         DSM_parentHWND = 0;
379         DSM_currentState = 2;
380
381         /* If there are data sources still open, close them now. */
382         while (currentDS != NULL)
383         {
384             nextDS = currentDS->next;
385             sane_close (currentDS->deviceHandle);
386             HeapFree (GetProcessHeap(), 0, currentDS);
387             currentDS = nextDS;
388         }
389         activeSources = NULL;
390         DSM_twCC = TWCC_SUCCESS;
391         twRC = TWRC_SUCCESS;
392     }
393     else
394     {
395         DSM_twCC = TWCC_SEQERROR;
396         twRC = TWRC_FAILURE;
397     }
398
399     return twRC;
400 #endif
401 }
402
403 /* DG_CONTROL/DAT_PARENT/MSG_OPENDSM */
404 TW_UINT16 TWAIN_OpenDSM (pTW_IDENTITY pOrigin, TW_MEMREF pData)
405 {
406 #ifndef HAVE_SANE
407     return TWRC_FAILURE;
408 #else
409     TW_UINT16 twRC = TWRC_SUCCESS;
410     SANE_Status status;
411     SANE_Int version_code;
412
413     TRACE("DG_CONTROL/DAT_PARENT/MSG_OPENDSM\n");
414
415     if (DSM_currentState == 2)
416     {
417         if (!DSM_initialized)
418         {
419             DSM_initialized = TRUE;
420             status = sane_init (&version_code, NULL);
421             device_list = NULL;
422             DSM_currentDevice = 0;
423             DSM_sourceId = 0;
424         }
425         DSM_parentHWND = *(TW_HANDLE*)pData;
426         DSM_currentState = 3; /* transition to state 3 */
427         DSM_twCC = TWCC_SUCCESS;
428         twRC = TWRC_SUCCESS;
429     }
430     else
431     {
432         /* operation invoked in invalid state */
433         DSM_twCC = TWCC_SEQERROR;
434         twRC = TWRC_FAILURE;
435     }
436
437     return twRC;
438 #endif
439 }
440
441 /* DG_CONTROL/DAT_STATUS/MSG_GET */
442 TW_UINT16 TWAIN_GetDSMStatus (pTW_IDENTITY pOrigin, TW_MEMREF pData)
443 {
444     pTW_STATUS pSourceStatus = (pTW_STATUS) pData;
445
446     TRACE ("DG_CONTROL/DAT_STATUS/MSG_GET\n");
447
448     pSourceStatus->ConditionCode = DSM_twCC;
449     DSM_twCC = TWCC_SUCCESS;  /* clear the condition code */
450
451     return TWRC_SUCCESS;
452 }