wininet: Avoid a crash with traces on.
[wine] / dlls / wintab32 / context.c
1 /*
2  * Tablet Context
3  *
4  * Copyright 2002 Patrik Stridvall
5  * Copyright 2003 CodeWeavers, Aric Stewart
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winerror.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winnls.h"
32
33 #include "wintab.h"
34 #include "wintab_internal.h"
35
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(wintab32);
39
40 /*
41  * Documentation found at
42  * http://www.csl.sony.co.jp/projects/ar/restricted/wintabl.html
43  */
44
45 static BOOL gLoaded;
46 static LPOPENCONTEXT gOpenContexts;
47 static HCTX gTopContext = (HCTX)0xc00;
48
49 static void LOGCONTEXTAtoW(const LOGCONTEXTA *in, LOGCONTEXTW *out)
50 {
51     MultiByteToWideChar(CP_ACP, 0, in->lcName, -1, out->lcName, LCNAMELEN);
52     out->lcName[LCNAMELEN - 1] = 0;
53     /* we use the fact that the fields after lcName are the same in LOGCONTEXTA and W */
54     memcpy(&out->lcOptions, &in->lcOptions, sizeof(LOGCONTEXTA) - FIELD_OFFSET(LOGCONTEXTA, lcOptions));
55 }
56
57 static void LOGCONTEXTWtoA(const LOGCONTEXTW *in, LOGCONTEXTA *out)
58 {
59     WideCharToMultiByte(CP_ACP, 0, in->lcName, LCNAMELEN, out->lcName, LCNAMELEN, NULL, NULL);
60     out->lcName[LCNAMELEN - 1] = 0;
61     /* we use the fact that the fields after lcName are the same in LOGCONTEXTA and W */
62     memcpy(&out->lcOptions, &in->lcOptions, sizeof(LOGCONTEXTW) - FIELD_OFFSET(LOGCONTEXTW, lcOptions));
63 }
64
65 static BOOL is_logcontext_category(UINT wCategory)
66 {
67     return wCategory == WTI_DEFSYSCTX || wCategory == WTI_DEFCONTEXT || wCategory == WTI_DDCTXS;
68 }
69
70 static BOOL is_string_field(UINT wCategory, UINT nIndex)
71 {
72     if (wCategory == WTI_INTERFACE && nIndex == IFC_WINTABID)
73         return TRUE;
74     if (is_logcontext_category(wCategory) && nIndex == CTX_NAME)
75         return TRUE;
76     if ((wCategory >= WTI_CURSORS && wCategory <= WTI_CURSORS + 9) &&
77             (nIndex == CSR_NAME || nIndex == CSR_BTNNAMES))
78         return TRUE;
79     if (wCategory == WTI_DEVICES && (nIndex == DVC_NAME || nIndex == DVC_PNPID))
80         return TRUE;
81     return FALSE;
82 }
83
84 static const char* DUMPBITS(int x)
85 {
86     char buf[200];
87     buf[0] = 0;
88     if (x&PK_CONTEXT) strcat(buf,"PK_CONTEXT ");
89     if (x&PK_STATUS) strcat(buf, "PK_STATUS ");
90     if (x&PK_TIME) strcat(buf, "PK_TIME ");
91     if (x&PK_CHANGED) strcat(buf, "PK_CHANGED ");
92     if (x&PK_SERIAL_NUMBER) strcat(buf, "PK_SERIAL_NUMBER ");
93     if (x&PK_CURSOR) strcat(buf, "PK_CURSOR ");
94     if (x&PK_BUTTONS) strcat(buf, "PK_BUTTONS ");
95     if (x&PK_X) strcat(buf, "PK_X ");
96     if (x&PK_Y) strcat(buf, "PK_Y ");
97     if (x&PK_Z) strcat(buf, "PK_Z ");
98     if (x&PK_NORMAL_PRESSURE) strcat(buf, "PK_NORMAL_PRESSURE ");
99     if (x&PK_TANGENT_PRESSURE) strcat(buf, "PK_TANGENT_PRESSURE ");
100     if (x&PK_ORIENTATION) strcat(buf, "PK_ORIENTATION ");
101     if (x&PK_ROTATION) strcat(buf, "PK_ROTATION ");
102     return wine_dbg_sprintf("{%s}",buf);
103 }
104
105 static inline void DUMPPACKET(WTPACKET packet)
106 {
107     TRACE("pkContext: %p pkStatus: 0x%x pkTime : 0x%x pkChanged: 0x%x pkSerialNumber: 0x%x pkCursor : %i pkButtons: %x pkX: %i pkY: %i pkZ: %i pkNormalPressure: %i pkTangentPressure: %i pkOrientation: (%i,%i,%i) pkRotation: (%i,%i,%i)\n",
108           packet.pkContext, packet.pkStatus, packet.pkTime, packet.pkChanged, packet.pkSerialNumber,
109           packet.pkCursor, packet.pkButtons, packet.pkX, packet.pkY, packet.pkZ,
110           packet.pkNormalPressure, packet.pkTangentPressure,
111           packet.pkOrientation.orAzimuth, packet.pkOrientation.orAltitude, packet.pkOrientation.orTwist,
112           packet.pkRotation.roPitch, packet.pkRotation.roRoll, packet.pkRotation.roYaw);
113 }
114
115 static inline void DUMPCONTEXT(LOGCONTEXTW lc)
116 {
117     TRACE("context: %s, %x, %x, %x, %x, %x, %x, %x%s, %x%s, %x%s, %x, %x, %i, %i, %i, %i ,%i, %i, %i, %i, %i,%i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i %i %i\n",
118           wine_dbgstr_w(lc.lcName), lc.lcOptions, lc.lcStatus, lc.lcLocks, lc.lcMsgBase,
119           lc.lcDevice, lc.lcPktRate, lc.lcPktData, DUMPBITS(lc.lcPktData),
120           lc.lcPktMode, DUMPBITS(lc.lcPktMode), lc.lcMoveMask,
121           DUMPBITS(lc.lcMoveMask), lc.lcBtnDnMask, lc.lcBtnUpMask,
122           lc.lcInOrgX, lc.lcInOrgY, lc.lcInOrgZ, lc.lcInExtX, lc.lcInExtY,
123           lc.lcInExtZ, lc.lcOutOrgX, lc.lcOutOrgY, lc.lcOutOrgZ, lc.lcOutExtX,
124           lc.lcOutExtY, lc.lcOutExtZ, lc.lcSensX, lc.lcSensY, lc.lcSensZ, lc.lcSysMode,
125           lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY, lc.lcSysSensX,
126           lc.lcSysSensY);
127 }
128
129
130 /* Find an open context given the handle */
131 static LPOPENCONTEXT TABLET_FindOpenContext(HCTX hCtx)
132 {
133     LPOPENCONTEXT ptr = gOpenContexts;
134     while (ptr)
135     {
136         if (ptr->handle == hCtx) return ptr;
137         ptr = ptr->next;
138     }
139     return NULL;
140 }
141
142 static void LoadTablet(void)
143 {
144     TRACE("Initializing the tablet to hwnd %p\n",hwndDefault);
145     gLoaded= TRUE;
146     pLoadTabletInfo(hwndDefault);
147 }
148
149 int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam,
150                              LPARAM lParam, BOOL send_always)
151 {
152     if ((send_always) || (newcontext->context.lcOptions & CXO_MESSAGES))
153     {
154         TRACE("Posting message %x to %p\n",msg, newcontext->hwndOwner);
155         return PostMessageA(newcontext->hwndOwner, msg, wParam, lParam);
156     }
157     return 0;
158 }
159
160 static inline DWORD ScaleForContext(DWORD In, LONG InOrg, LONG InExt, LONG OutOrg, LONG OutExt)
161 {
162     if (((InExt > 0 )&&(OutExt > 0)) || ((InExt<0) && (OutExt < 0)))
163         return ((In - InOrg) * abs(OutExt) / abs(InExt)) + OutOrg;
164     else
165         return ((abs(InExt) - (In - InOrg))*abs(OutExt) / abs(InExt)) + OutOrg;
166 }
167
168 LPOPENCONTEXT AddPacketToContextQueue(LPWTPACKET packet, HWND hwnd)
169 {
170     LPOPENCONTEXT ptr=NULL;
171
172     EnterCriticalSection(&csTablet);
173
174     ptr = gOpenContexts;
175     while (ptr)
176     {
177         TRACE("Trying Queue %p (%p %p)\n", ptr->handle, hwnd, ptr->hwndOwner);
178
179         if (ptr->hwndOwner == hwnd)
180         {
181             int tgt;
182             if (!ptr->enabled)
183             {
184                 ptr = ptr->next;
185                 continue;
186             }
187
188             tgt = ptr->PacketsQueued;
189
190             packet->pkContext = ptr->handle;
191
192             /* translate packet data to the context */
193
194             /* Scale  as per documentation */
195             packet->pkY = ScaleForContext(packet->pkY, ptr->context.lcInOrgY,
196                                 ptr->context.lcInExtY, ptr->context.lcOutOrgY,
197                                 ptr->context.lcOutExtY);
198
199             packet->pkX = ScaleForContext(packet->pkX, ptr->context.lcInOrgX,
200                                 ptr->context.lcInExtX, ptr->context.lcOutOrgX,
201                                 ptr->context.lcOutExtX);
202
203             /* flip the Y axis */
204             if (ptr->context.lcOutExtY > 0)
205                 packet->pkY = ptr->context.lcOutExtY - packet->pkY;
206
207             DUMPPACKET(*packet);
208
209             if (tgt == ptr->QueueSize)
210             {
211                 TRACE("Queue Overflow %p\n",ptr->handle);
212                 ptr->PacketQueue[tgt-1].pkStatus |= TPS_QUEUE_ERR;
213             }
214             else
215             {
216                 TRACE("Placed in queue %p index %i\n",ptr->handle,tgt);
217                 ptr->PacketQueue[tgt] = *packet;
218                 ptr->PacketsQueued++;
219
220                 if (ptr->ActiveCursor != packet->pkCursor)
221                 {
222                     ptr->ActiveCursor = packet->pkCursor;
223                     if (ptr->context.lcOptions & CXO_CSRMESSAGES)
224                         TABLET_PostTabletMessage(ptr, _WT_CSRCHANGE(ptr->context.lcMsgBase),
225                           (WPARAM)packet->pkSerialNumber, (LPARAM)ptr->handle,
226                             FALSE);
227                 }
228             }
229             break;
230          }
231         ptr = ptr->next;
232     }
233     LeaveCriticalSection(&csTablet);
234     TRACE("Done (%p)\n",ptr);
235     return ptr;
236 }
237
238 /*
239  * Flushes all packets from the queue.
240  */
241 static inline void TABLET_FlushQueue(LPOPENCONTEXT context)
242 {
243     context->PacketsQueued = 0;
244 }
245
246 static inline int CopyTabletData(LPVOID target, LPVOID src, INT size)
247 {
248     memcpy(target,src,size);
249     return(size);
250 }
251
252 static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial,
253                                 LPWTPACKET *pkt)
254 {
255     int loop;
256     int index  = -1;
257     for (loop = 0; loop < context->PacketsQueued; loop++)
258         if (context->PacketQueue[loop].pkSerialNumber == wSerial)
259         {
260             index = loop;
261             *pkt = &context->PacketQueue[loop];
262             break;
263         }
264
265     TRACE("%i .. %i\n",context->PacketsQueued,index);
266
267     return index;
268 }
269
270
271 static LPVOID TABLET_CopyPacketData(LPOPENCONTEXT context, LPVOID lpPkt,
272                                     LPWTPACKET wtp)
273 {
274     LPBYTE ptr;
275
276     ptr = lpPkt;
277     TRACE("Packet Bits %s\n",DUMPBITS(context->context.lcPktData));
278
279     if (context->context.lcPktData & PK_CONTEXT)
280         ptr+=CopyTabletData(ptr,&wtp->pkContext,sizeof(HCTX));
281     if (context->context.lcPktData & PK_STATUS)
282         ptr+=CopyTabletData(ptr,&wtp->pkStatus,sizeof(UINT));
283     if (context->context.lcPktData & PK_TIME)
284         ptr+=CopyTabletData(ptr,&wtp->pkTime,sizeof(LONG));
285     if (context->context.lcPktData & PK_CHANGED)
286         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(WTPKT));
287     if (context->context.lcPktData & PK_SERIAL_NUMBER)
288         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(UINT));
289     if (context->context.lcPktData & PK_CURSOR)
290         ptr+=CopyTabletData(ptr,&wtp->pkCursor,sizeof(UINT));
291     if (context->context.lcPktData & PK_BUTTONS)
292         ptr+=CopyTabletData(ptr,&wtp->pkButtons,sizeof(DWORD));
293     if (context->context.lcPktData & PK_X)
294         ptr+=CopyTabletData(ptr,&wtp->pkX,sizeof(DWORD));
295     if (context->context.lcPktData & PK_Y)
296         ptr+=CopyTabletData(ptr,&wtp->pkY,sizeof(DWORD));
297     if (context->context.lcPktData & PK_Z)
298         ptr+=CopyTabletData(ptr,&wtp->pkZ,sizeof(DWORD));
299     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
300         ptr+=CopyTabletData(ptr,&wtp->pkNormalPressure,sizeof(UINT));
301     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
302         ptr+=CopyTabletData(ptr,&wtp->pkTangentPressure,sizeof(UINT));
303     if (context->context.lcPktData & PK_ORIENTATION)
304         ptr+=CopyTabletData(ptr,&wtp->pkOrientation,sizeof(ORIENTATION));
305     if (context->context.lcPktData & PK_ROTATION)
306         ptr+=CopyTabletData(ptr,&wtp->pkRotation,sizeof(ROTATION));
307
308     /*TRACE("Copied %i bytes\n",(INT)ptr - (INT)lpPkt); */
309     return ptr;
310 }
311
312 static VOID TABLET_BlankPacketData(LPOPENCONTEXT context, LPVOID lpPkt, INT n)
313 {
314     int rc = 0;
315
316     if (context->context.lcPktData & PK_CONTEXT)
317         rc +=sizeof(HCTX);
318     if (context->context.lcPktData & PK_STATUS)
319         rc +=sizeof(UINT);
320     if (context->context.lcPktData & PK_TIME)
321         rc += sizeof(LONG);
322     if (context->context.lcPktData & PK_CHANGED)
323         rc += sizeof(WTPKT);
324     if (context->context.lcPktData & PK_SERIAL_NUMBER)
325         rc += sizeof(UINT);
326     if (context->context.lcPktData & PK_CURSOR)
327         rc += sizeof(UINT);
328     if (context->context.lcPktData & PK_BUTTONS)
329         rc += sizeof(DWORD);
330     if (context->context.lcPktData & PK_X)
331         rc += sizeof(DWORD);
332     if (context->context.lcPktData & PK_Y)
333         rc += sizeof(DWORD);
334     if (context->context.lcPktData & PK_Z)
335         rc += sizeof(DWORD);
336     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
337         rc += sizeof(UINT);
338     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
339         rc += sizeof(UINT);
340     if (context->context.lcPktData & PK_ORIENTATION)
341         rc += sizeof(ORIENTATION);
342     if (context->context.lcPktData & PK_ROTATION)
343         rc += sizeof(ROTATION);
344
345     rc *= n;
346     memset(lpPkt,0,rc);
347 }
348
349
350 UINT WINAPI WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode)
351 {
352     UINT result;
353
354     TRACE("(%d, %d, %p, %d)\n", wCategory, nIndex, lpOutput, bUnicode);
355     if (gLoaded == FALSE)
356          LoadTablet();
357
358     /*
359      *  Handle system extents here, as we can use user32.dll code to set them.
360      */
361     if(wCategory == WTI_DEFSYSCTX)
362     {
363         switch(nIndex)
364         {
365             case CTX_SYSEXTX:
366                 if(lpOutput != NULL)
367                     *(LONG*)lpOutput = GetSystemMetrics(SM_CXSCREEN);
368                 return sizeof(LONG);
369             case CTX_SYSEXTY:
370                 if(lpOutput != NULL)
371                     *(LONG*)lpOutput = GetSystemMetrics(SM_CYSCREEN);
372                 return sizeof(LONG);
373            /* No action, delegate to X11Drv */
374         }
375     }
376
377     if (is_logcontext_category(wCategory) && nIndex == 0)
378     {
379         if (lpOutput)
380         {
381             LOGCONTEXTW buf;
382             pWTInfoW(wCategory, nIndex, &buf);
383
384             /*  Handle system extents here, as we can use user32.dll code to set them */
385             if(wCategory == WTI_DEFSYSCTX && nIndex == 0)
386             {
387                 buf.lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
388                 buf.lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
389             }
390
391             if (bUnicode)
392                 memcpy(lpOutput, &buf, sizeof(buf));
393             else
394                 LOGCONTEXTWtoA(&buf, lpOutput);
395         }
396
397         result = bUnicode ? sizeof(LOGCONTEXTW) : sizeof(LOGCONTEXTA);
398     }
399     else if (is_string_field(wCategory, nIndex) && !bUnicode)
400     {
401         int size = pWTInfoW(wCategory, nIndex, NULL);
402         WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, size);
403         pWTInfoW(wCategory, nIndex, buf);
404         result = WideCharToMultiByte(CP_ACP, 0, buf, size/sizeof(WCHAR), lpOutput, lpOutput ? 2*size : 0, NULL, NULL);
405         HeapFree(GetProcessHeap(), 0, buf);
406     }
407     else
408         result =  pWTInfoW(wCategory, nIndex, lpOutput);
409
410     TRACE("returns %d\n", result);
411     return result;
412 }
413
414 /***********************************************************************
415  *              WTInfoA (WINTAB32.20)
416  */
417 UINT WINAPI WTInfoA(UINT wCategory, UINT nIndex, LPVOID lpOutput)
418 {
419     return WTInfoT(wCategory, nIndex, lpOutput, FALSE);
420 }
421
422
423 /***********************************************************************
424  *              WTInfoW (WINTAB32.1020)
425  */
426 UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
427 {
428     return WTInfoT(wCategory, nIndex, lpOutput, TRUE);
429 }
430
431 /***********************************************************************
432  *              WTOpenW (WINTAB32.2021)
433  */
434 HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable)
435 {
436     LPOPENCONTEXT newcontext;
437
438     TRACE("(%p, %p, %u)\n", hWnd, lpLogCtx, fEnable);
439     DUMPCONTEXT(*lpLogCtx);
440
441     newcontext = HeapAlloc(GetProcessHeap(), 0 , sizeof(OPENCONTEXT));
442     newcontext->context = *lpLogCtx;
443     newcontext->hwndOwner = hWnd;
444     newcontext->enabled = fEnable;
445     newcontext->ActiveCursor = -1;
446     newcontext->QueueSize = 10;
447     newcontext->PacketsQueued = 0;
448     newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10);
449
450     EnterCriticalSection(&csTablet);
451     newcontext->handle = gTopContext++;
452     newcontext->next = gOpenContexts;
453     gOpenContexts = newcontext;
454     LeaveCriticalSection(&csTablet);
455
456     pAttachEventQueueToTablet(hWnd);
457
458     TABLET_PostTabletMessage(newcontext, _WT_CTXOPEN(newcontext->context.lcMsgBase), (WPARAM)newcontext->handle,
459                       newcontext->context.lcStatus, TRUE);
460
461     newcontext->context.lcStatus = CXS_ONTOP;
462
463     TABLET_PostTabletMessage(newcontext, _WT_CTXOVERLAP(newcontext->context.lcMsgBase),
464                             (WPARAM)newcontext->handle,
465                             newcontext->context.lcStatus, TRUE);
466
467     return newcontext->handle;
468 }
469
470 /***********************************************************************
471  *              WTOpenA (WINTAB32.21)
472  */
473 HCTX WINAPI WTOpenA(HWND hWnd, LPLOGCONTEXTA lpLogCtx, BOOL fEnable)
474 {
475     LOGCONTEXTW logCtxW;
476
477     LOGCONTEXTAtoW(lpLogCtx, &logCtxW);
478     return WTOpenW(hWnd, &logCtxW, fEnable);
479 }
480
481 /***********************************************************************
482  *              WTClose (WINTAB32.22)
483  */
484 BOOL WINAPI WTClose(HCTX hCtx)
485 {
486     LPOPENCONTEXT context,ptr;
487
488     TRACE("(%p)\n", hCtx);
489
490     EnterCriticalSection(&csTablet);
491
492     ptr = context = gOpenContexts;
493
494     while (context && (context->handle != hCtx))
495     {
496         ptr = context;
497         context = context->next;
498     }
499     if (!context)
500     {
501         LeaveCriticalSection(&csTablet);
502         return TRUE;
503     }
504
505     if (context == gOpenContexts)
506         gOpenContexts = context->next;
507     else
508         ptr->next = context->next;
509
510     LeaveCriticalSection(&csTablet);
511
512     TABLET_PostTabletMessage(context, _WT_CTXCLOSE(context->context.lcMsgBase), (WPARAM)context->handle,
513                       context->context.lcStatus,TRUE);
514
515     HeapFree(GetProcessHeap(),0,context->PacketQueue);
516     HeapFree(GetProcessHeap(),0,context);
517
518     return TRUE;
519 }
520
521 /***********************************************************************
522  *              WTPacketsGet (WINTAB32.23)
523  */
524 int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
525 {
526     int limit;
527     LPOPENCONTEXT context;
528     LPVOID ptr = lpPkts;
529
530     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
531
532     if (!hCtx)
533         return 0;
534
535     EnterCriticalSection(&csTablet);
536
537     context = TABLET_FindOpenContext(hCtx);
538
539     if (lpPkts != NULL)
540         TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
541
542     if (context->PacketsQueued == 0)
543     {
544         LeaveCriticalSection(&csTablet);
545         return 0;
546     }
547
548     limit = min(cMaxPkts,context->PacketsQueued);
549
550     if(ptr != NULL)
551     {
552         int i = 0;
553         for(i = 0; i < limit; i++)
554             ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[i]);
555     }
556
557
558     if (limit < context->PacketsQueued)
559     {
560         memmove(context->PacketQueue, &context->PacketQueue[limit],
561             (context->PacketsQueued - (limit))*sizeof(WTPACKET));
562     }
563     context->PacketsQueued -= limit;
564     LeaveCriticalSection(&csTablet);
565
566     TRACE("Copied %i packets\n",limit);
567
568     return limit;
569 }
570
571 /***********************************************************************
572  *              WTPacket (WINTAB32.24)
573  */
574 BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
575 {
576     int rc = 0;
577     LPOPENCONTEXT context;
578     LPWTPACKET wtp = NULL;
579
580     TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
581
582     if (!hCtx)
583         return 0;
584
585     EnterCriticalSection(&csTablet);
586
587     context = TABLET_FindOpenContext(hCtx);
588
589     rc = TABLET_FindPacket(context ,wSerial, &wtp);
590
591     if (rc >= 0)
592     {
593         if (lpPkt)
594            TABLET_CopyPacketData(context ,lpPkt, wtp);
595
596         if ((rc+1) < context->QueueSize)
597         {
598             memmove(context->PacketQueue, &context->PacketQueue[rc+1],
599                 (context->PacketsQueued - (rc+1))*sizeof(WTPACKET));
600         }
601         context->PacketsQueued -= (rc+1);
602     }
603     LeaveCriticalSection(&csTablet);
604
605     TRACE("Returning %i\n",rc+1);
606     return rc+1;
607 }
608
609 /***********************************************************************
610  *              WTEnable (WINTAB32.40)
611  */
612 BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
613 {
614     LPOPENCONTEXT context;
615
616     TRACE("(%p, %u)\n", hCtx, fEnable);
617
618     if (!hCtx) return 0;
619
620     EnterCriticalSection(&csTablet);
621     context = TABLET_FindOpenContext(hCtx);
622     if(!fEnable)
623         TABLET_FlushQueue(context);
624     context->enabled = fEnable;
625     LeaveCriticalSection(&csTablet);
626
627     return TRUE;
628 }
629
630 /***********************************************************************
631  *              WTOverlap (WINTAB32.41)
632  */
633 BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
634 {
635     FIXME("(%p, %u): stub\n", hCtx, fToTop);
636
637     return TRUE;
638 }
639
640 /***********************************************************************
641  *              WTConfig (WINTAB32.61)
642  */
643 BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
644 {
645     FIXME("(%p, %p): stub\n", hCtx, hWnd);
646
647     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
648
649     return FALSE;
650 }
651
652 /***********************************************************************
653  *              WTGetA (WINTAB32.61)
654  */
655 BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
656 {
657     LPOPENCONTEXT context;
658
659     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
660
661     if (!hCtx) return 0;
662
663     EnterCriticalSection(&csTablet);
664     context = TABLET_FindOpenContext(hCtx);
665     LOGCONTEXTWtoA(&context->context, lpLogCtx);
666     LeaveCriticalSection(&csTablet);
667
668     return TRUE;
669 }
670
671 /***********************************************************************
672  *              WTGetW (WINTAB32.1061)
673  */
674 BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
675 {
676     LPOPENCONTEXT context;
677
678     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
679
680     if (!hCtx) return 0;
681
682     EnterCriticalSection(&csTablet);
683     context = TABLET_FindOpenContext(hCtx);
684     memmove(lpLogCtx,&context->context,sizeof(LOGCONTEXTW));
685     LeaveCriticalSection(&csTablet);
686
687     return TRUE;
688 }
689
690 /***********************************************************************
691  *              WTSetA (WINTAB32.62)
692  */
693 BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
694 {
695     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
696
697     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
698
699     return FALSE;
700 }
701
702 /***********************************************************************
703  *              WTSetW (WINTAB32.1062)
704  */
705 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
706 {
707     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
708
709     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
710
711     return FALSE;
712 }
713
714 /***********************************************************************
715  *              WTExtGet (WINTAB32.63)
716  */
717 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
718 {
719     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
720
721     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
722
723     return FALSE;
724 }
725
726 /***********************************************************************
727  *              WTExtSet (WINTAB32.64)
728  */
729 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
730 {
731     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
732
733     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
734
735     return FALSE;
736 }
737
738 /***********************************************************************
739  *              WTSave (WINTAB32.65)
740  */
741 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
742 {
743     FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
744
745     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
746
747     return FALSE;
748 }
749
750 /***********************************************************************
751  *              WTRestore (WINTAB32.66)
752  */
753 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
754 {
755     FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
756
757     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
758
759     return 0;
760 }
761
762 /***********************************************************************
763  *              WTPacketsPeek (WINTAB32.80)
764  */
765 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
766 {
767     int limit;
768     LPOPENCONTEXT context;
769     LPVOID ptr = lpPkts;
770
771     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
772
773     if (!hCtx || !lpPkts) return 0;
774
775     EnterCriticalSection(&csTablet);
776
777     context = TABLET_FindOpenContext(hCtx);
778
779     if (context->PacketsQueued == 0)
780     {
781         LeaveCriticalSection(&csTablet);
782         return 0;
783     }
784
785     for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
786         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
787
788     LeaveCriticalSection(&csTablet);
789     TRACE("Copied %i packets\n",limit);
790     return limit;
791 }
792
793 /***********************************************************************
794  *              WTDataGet (WINTAB32.81)
795  */
796 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
797                      int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
798 {
799     LPOPENCONTEXT context;
800     LPVOID ptr = lpPkts;
801     INT bgn = 0;
802     INT end = 0;
803     INT num = 0;
804
805     TRACE("(%p, %u, %u, %d, %p, %p)\n",
806           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
807
808     if (!hCtx) return 0;
809
810     EnterCriticalSection(&csTablet);
811
812     context = TABLET_FindOpenContext(hCtx);
813
814     if (context->PacketsQueued == 0)
815     {
816         LeaveCriticalSection(&csTablet);
817         return 0;
818     }
819
820     while (bgn < context->PacketsQueued &&
821            context->PacketQueue[bgn].pkSerialNumber != wBegin)
822         bgn++;
823
824     end = bgn;
825     while (end < context->PacketsQueued &&
826            context->PacketQueue[end].pkSerialNumber != wEnd)
827         end++;
828
829     if ((bgn == end) && (end == context->PacketsQueued))
830     {
831         LeaveCriticalSection(&csTablet);
832         return 0;
833     }
834
835     for (num = bgn; num <= end; num++)
836         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
837
838     /* remove read packets */
839     if ((end+1) < context->PacketsQueued)
840         memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
841                 (context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
842
843     context->PacketsQueued -= ((end-bgn)+1);
844     *lpNPkts = ((end-bgn)+1);
845
846     LeaveCriticalSection(&csTablet);
847     TRACE("Copied %i packets\n",*lpNPkts);
848     return (end - bgn)+1;
849 }
850
851 /***********************************************************************
852  *              WTDataPeek (WINTAB32.82)
853  */
854 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
855                       int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
856 {
857     LPOPENCONTEXT context;
858     LPVOID ptr = lpPkts;
859     INT bgn = 0;
860     INT end = 0;
861     INT num = 0;
862
863     TRACE("(%p, %u, %u, %d, %p, %p)\n",
864           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
865
866     if (!hCtx || !lpPkts) return 0;
867
868     EnterCriticalSection(&csTablet);
869
870     context = TABLET_FindOpenContext(hCtx);
871
872     if (context->PacketsQueued == 0)
873     {
874         LeaveCriticalSection(&csTablet);
875         return 0;
876     }
877
878     while (bgn < context->PacketsQueued &&
879            context->PacketQueue[bgn].pkSerialNumber != wBegin)
880         bgn++;
881
882     end = bgn;
883     while (end < context->PacketsQueued &&
884            context->PacketQueue[end].pkSerialNumber != wEnd)
885         end++;
886
887     if (bgn == context->PacketsQueued ||  end == context->PacketsQueued)
888     {
889         TRACE("%i %i %i\n", bgn, end, context->PacketsQueued);
890         LeaveCriticalSection(&csTablet);
891         return 0;
892     }
893
894     for (num = bgn; num <= end; num++)
895         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
896
897     *lpNPkts = ((end-bgn)+1);
898     LeaveCriticalSection(&csTablet);
899
900     TRACE("Copied %i packets\n",*lpNPkts);
901     return (end - bgn)+1;
902 }
903
904 /***********************************************************************
905  *              WTQueuePacketsEx (WINTAB32.200)
906  */
907 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
908 {
909     LPOPENCONTEXT context;
910
911     TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
912
913     if (!hCtx) return 0;
914
915     EnterCriticalSection(&csTablet);
916
917     context = TABLET_FindOpenContext(hCtx);
918
919     if (context->PacketsQueued)
920     {
921         *lpOld = context->PacketQueue[0].pkSerialNumber;
922         *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
923     }
924     else
925     {
926         TRACE("No packets\n");
927         LeaveCriticalSection(&csTablet);
928         return FALSE;
929     }
930     LeaveCriticalSection(&csTablet);
931
932     return TRUE;
933 }
934
935 /***********************************************************************
936  *              WTQueueSizeGet (WINTAB32.84)
937  */
938 int WINAPI WTQueueSizeGet(HCTX hCtx)
939 {
940     LPOPENCONTEXT context;
941     TRACE("(%p)\n", hCtx);
942
943     if (!hCtx) return 0;
944
945     EnterCriticalSection(&csTablet);
946     context = TABLET_FindOpenContext(hCtx);
947     LeaveCriticalSection(&csTablet);
948     return context->QueueSize;
949 }
950
951 /***********************************************************************
952  *              WTQueueSizeSet (WINTAB32.85)
953  */
954 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
955 {
956     LPOPENCONTEXT context;
957
958     TRACE("(%p, %d)\n", hCtx, nPkts);
959
960     if (!hCtx) return 0;
961
962     EnterCriticalSection(&csTablet);
963
964     context = TABLET_FindOpenContext(hCtx);
965
966     context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
967                         context->PacketQueue, sizeof(WTPACKET)*nPkts);
968
969     context->QueueSize = nPkts;
970     LeaveCriticalSection(&csTablet);
971
972     return nPkts;
973 }