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