d3dxof: Release properly all allocated resources.
[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("Name: %s, Options: %x, Status: %x, Locks: %x, MsgBase: %x, "
118           "Device: %x, PktRate: %x, "
119           "%x%s, %x%s, %x%s, "
120           "BtnDnMask: %x, BtnUpMask: %x, "
121           "InOrgX: %i, InOrgY: %i, InOrgZ: %i, "
122           "InExtX: %i, InExtY: %i, InExtZ: %i, "
123           "OutOrgX: %i, OutOrgY: %i, OutOrgZ: %i, "
124           "OutExtX: %i, OutExtY: %i, OutExtZ: %i, "
125           "SensX: %i, SensY: %i, SensZ: %i, "
126           "SysMode: %i, "
127           "SysOrgX: %i, SysOrgY: %i, "
128           "SysExtX: %i, SysExtY: %i, "
129           "SysSensX: %i, SysSensY: %i\n",
130           wine_dbgstr_w(lc.lcName), lc.lcOptions, lc.lcStatus, lc.lcLocks, lc.lcMsgBase,
131           lc.lcDevice, lc.lcPktRate, lc.lcPktData, DUMPBITS(lc.lcPktData),
132           lc.lcPktMode, DUMPBITS(lc.lcPktMode), lc.lcMoveMask,
133           DUMPBITS(lc.lcMoveMask), lc.lcBtnDnMask, lc.lcBtnUpMask,
134           lc.lcInOrgX, lc.lcInOrgY, lc.lcInOrgZ, lc.lcInExtX, lc.lcInExtY,
135           lc.lcInExtZ, lc.lcOutOrgX, lc.lcOutOrgY, lc.lcOutOrgZ, lc.lcOutExtX,
136           lc.lcOutExtY, lc.lcOutExtZ, lc.lcSensX, lc.lcSensY, lc.lcSensZ, lc.lcSysMode,
137           lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY, lc.lcSysSensX,
138           lc.lcSysSensY);
139 }
140
141
142 /* Find an open context given the handle */
143 static LPOPENCONTEXT TABLET_FindOpenContext(HCTX hCtx)
144 {
145     LPOPENCONTEXT ptr = gOpenContexts;
146     while (ptr)
147     {
148         if (ptr->handle == hCtx) return ptr;
149         ptr = ptr->next;
150     }
151     return NULL;
152 }
153
154 static void LoadTablet(void)
155 {
156     TRACE("Initializing the tablet to hwnd %p\n",hwndDefault);
157     gLoaded= TRUE;
158     pLoadTabletInfo(hwndDefault);
159 }
160
161 int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam,
162                              LPARAM lParam, BOOL send_always)
163 {
164     if ((send_always) || (newcontext->context.lcOptions & CXO_MESSAGES))
165     {
166         TRACE("Posting message %x to %p\n",msg, newcontext->hwndOwner);
167         return PostMessageA(newcontext->hwndOwner, msg, wParam, lParam);
168     }
169     return 0;
170 }
171
172 static inline DWORD ScaleForContext(DWORD In, LONG InOrg, LONG InExt, LONG OutOrg, LONG OutExt)
173 {
174     if (((InExt > 0 )&&(OutExt > 0)) || ((InExt<0) && (OutExt < 0)))
175         return ((In - InOrg) * abs(OutExt) / abs(InExt)) + OutOrg;
176     else
177         return ((abs(InExt) - (In - InOrg))*abs(OutExt) / abs(InExt)) + OutOrg;
178 }
179
180 LPOPENCONTEXT AddPacketToContextQueue(LPWTPACKET packet, HWND hwnd)
181 {
182     LPOPENCONTEXT ptr=NULL;
183
184     EnterCriticalSection(&csTablet);
185
186     ptr = gOpenContexts;
187     while (ptr)
188     {
189         TRACE("Trying Queue %p (%p %p)\n", ptr->handle, hwnd, ptr->hwndOwner);
190
191         if (ptr->hwndOwner == hwnd)
192         {
193             int tgt;
194             if (!ptr->enabled)
195             {
196                 ptr = ptr->next;
197                 continue;
198             }
199
200             tgt = ptr->PacketsQueued;
201
202             packet->pkContext = ptr->handle;
203
204             /* translate packet data to the context */
205
206             /* Scale  as per documentation */
207             packet->pkY = ScaleForContext(packet->pkY, ptr->context.lcInOrgY,
208                                 ptr->context.lcInExtY, ptr->context.lcOutOrgY,
209                                 ptr->context.lcOutExtY);
210
211             packet->pkX = ScaleForContext(packet->pkX, ptr->context.lcInOrgX,
212                                 ptr->context.lcInExtX, ptr->context.lcOutOrgX,
213                                 ptr->context.lcOutExtX);
214
215             /* flip the Y axis */
216             if (ptr->context.lcOutExtY > 0)
217                 packet->pkY = ptr->context.lcOutExtY - packet->pkY;
218             else if (ptr->context.lcOutExtY < 0)
219                 packet->pkY = abs(ptr->context.lcOutExtY + packet->pkY);
220
221             DUMPPACKET(*packet);
222
223             if (tgt == ptr->QueueSize)
224             {
225                 TRACE("Queue Overflow %p\n",ptr->handle);
226                 ptr->PacketQueue[tgt-1].pkStatus |= TPS_QUEUE_ERR;
227             }
228             else
229             {
230                 TRACE("Placed in queue %p index %i\n",ptr->handle,tgt);
231                 ptr->PacketQueue[tgt] = *packet;
232                 ptr->PacketsQueued++;
233
234                 if (ptr->ActiveCursor != packet->pkCursor)
235                 {
236                     ptr->ActiveCursor = packet->pkCursor;
237                     if (ptr->context.lcOptions & CXO_CSRMESSAGES)
238                         TABLET_PostTabletMessage(ptr, _WT_CSRCHANGE(ptr->context.lcMsgBase),
239                           (WPARAM)packet->pkSerialNumber, (LPARAM)ptr->handle,
240                             FALSE);
241                 }
242             }
243             break;
244          }
245         ptr = ptr->next;
246     }
247     LeaveCriticalSection(&csTablet);
248     TRACE("Done (%p)\n",ptr);
249     return ptr;
250 }
251
252 /*
253  * Flushes all packets from the queue.
254  */
255 static inline void TABLET_FlushQueue(LPOPENCONTEXT context)
256 {
257     context->PacketsQueued = 0;
258 }
259
260 static inline int CopyTabletData(LPVOID target, LPVOID src, INT size)
261 {
262     memcpy(target,src,size);
263     return(size);
264 }
265
266 static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial,
267                                 LPWTPACKET *pkt)
268 {
269     int loop;
270     int index  = -1;
271     for (loop = 0; loop < context->PacketsQueued; loop++)
272         if (context->PacketQueue[loop].pkSerialNumber == wSerial)
273         {
274             index = loop;
275             *pkt = &context->PacketQueue[loop];
276             break;
277         }
278
279     TRACE("%i .. %i\n",context->PacketsQueued,index);
280
281     return index;
282 }
283
284
285 static LPVOID TABLET_CopyPacketData(LPOPENCONTEXT context, LPVOID lpPkt,
286                                     LPWTPACKET wtp)
287 {
288     LPBYTE ptr;
289
290     ptr = lpPkt;
291     TRACE("Packet Bits %s\n",DUMPBITS(context->context.lcPktData));
292
293     if (context->context.lcPktData & PK_CONTEXT)
294         ptr+=CopyTabletData(ptr,&wtp->pkContext,sizeof(HCTX));
295     if (context->context.lcPktData & PK_STATUS)
296         ptr+=CopyTabletData(ptr,&wtp->pkStatus,sizeof(UINT));
297     if (context->context.lcPktData & PK_TIME)
298         ptr+=CopyTabletData(ptr,&wtp->pkTime,sizeof(LONG));
299     if (context->context.lcPktData & PK_CHANGED)
300         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(WTPKT));
301     if (context->context.lcPktData & PK_SERIAL_NUMBER)
302         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(UINT));
303     if (context->context.lcPktData & PK_CURSOR)
304         ptr+=CopyTabletData(ptr,&wtp->pkCursor,sizeof(UINT));
305     if (context->context.lcPktData & PK_BUTTONS)
306         ptr+=CopyTabletData(ptr,&wtp->pkButtons,sizeof(DWORD));
307     if (context->context.lcPktData & PK_X)
308         ptr+=CopyTabletData(ptr,&wtp->pkX,sizeof(DWORD));
309     if (context->context.lcPktData & PK_Y)
310         ptr+=CopyTabletData(ptr,&wtp->pkY,sizeof(DWORD));
311     if (context->context.lcPktData & PK_Z)
312         ptr+=CopyTabletData(ptr,&wtp->pkZ,sizeof(DWORD));
313     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
314         ptr+=CopyTabletData(ptr,&wtp->pkNormalPressure,sizeof(UINT));
315     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
316         ptr+=CopyTabletData(ptr,&wtp->pkTangentPressure,sizeof(UINT));
317     if (context->context.lcPktData & PK_ORIENTATION)
318         ptr+=CopyTabletData(ptr,&wtp->pkOrientation,sizeof(ORIENTATION));
319     if (context->context.lcPktData & PK_ROTATION)
320         ptr+=CopyTabletData(ptr,&wtp->pkRotation,sizeof(ROTATION));
321
322     /*TRACE("Copied %i bytes\n",(INT)ptr - (INT)lpPkt); */
323     return ptr;
324 }
325
326 static VOID TABLET_BlankPacketData(LPOPENCONTEXT context, LPVOID lpPkt, INT n)
327 {
328     int rc = 0;
329
330     if (context->context.lcPktData & PK_CONTEXT)
331         rc +=sizeof(HCTX);
332     if (context->context.lcPktData & PK_STATUS)
333         rc +=sizeof(UINT);
334     if (context->context.lcPktData & PK_TIME)
335         rc += sizeof(LONG);
336     if (context->context.lcPktData & PK_CHANGED)
337         rc += sizeof(WTPKT);
338     if (context->context.lcPktData & PK_SERIAL_NUMBER)
339         rc += sizeof(UINT);
340     if (context->context.lcPktData & PK_CURSOR)
341         rc += sizeof(UINT);
342     if (context->context.lcPktData & PK_BUTTONS)
343         rc += sizeof(DWORD);
344     if (context->context.lcPktData & PK_X)
345         rc += sizeof(DWORD);
346     if (context->context.lcPktData & PK_Y)
347         rc += sizeof(DWORD);
348     if (context->context.lcPktData & PK_Z)
349         rc += sizeof(DWORD);
350     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
351         rc += sizeof(UINT);
352     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
353         rc += sizeof(UINT);
354     if (context->context.lcPktData & PK_ORIENTATION)
355         rc += sizeof(ORIENTATION);
356     if (context->context.lcPktData & PK_ROTATION)
357         rc += sizeof(ROTATION);
358
359     rc *= n;
360     memset(lpPkt,0,rc);
361 }
362
363
364 static UINT WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode)
365 {
366     UINT result;
367
368     TRACE("(%d, %d, %p, %d)\n", wCategory, nIndex, lpOutput, bUnicode);
369     if (gLoaded == FALSE)
370          LoadTablet();
371
372     /*
373      *  Handle system extents here, as we can use user32.dll code to set them.
374      */
375     if(wCategory == WTI_DEFSYSCTX)
376     {
377         switch(nIndex)
378         {
379             case CTX_SYSEXTX:
380                 if(lpOutput != NULL)
381                     *(LONG*)lpOutput = GetSystemMetrics(SM_CXSCREEN);
382                 return sizeof(LONG);
383             case CTX_SYSEXTY:
384                 if(lpOutput != NULL)
385                     *(LONG*)lpOutput = GetSystemMetrics(SM_CYSCREEN);
386                 return sizeof(LONG);
387            /* No action, delegate to X11Drv */
388         }
389     }
390
391     if (is_logcontext_category(wCategory) && nIndex == 0)
392     {
393         if (lpOutput)
394         {
395             LOGCONTEXTW buf;
396             pWTInfoW(wCategory, nIndex, &buf);
397
398             /*  Handle system extents here, as we can use user32.dll code to set them */
399             if(wCategory == WTI_DEFSYSCTX && nIndex == 0)
400             {
401                 buf.lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
402                 buf.lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
403             }
404
405             if (bUnicode)
406                 memcpy(lpOutput, &buf, sizeof(buf));
407             else
408                 LOGCONTEXTWtoA(&buf, lpOutput);
409         }
410
411         result = bUnicode ? sizeof(LOGCONTEXTW) : sizeof(LOGCONTEXTA);
412     }
413     else if (is_string_field(wCategory, nIndex) && !bUnicode)
414     {
415         int size = pWTInfoW(wCategory, nIndex, NULL);
416         WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, size);
417         pWTInfoW(wCategory, nIndex, buf);
418         result = WideCharToMultiByte(CP_ACP, 0, buf, size/sizeof(WCHAR), lpOutput, lpOutput ? 2*size : 0, NULL, NULL);
419         HeapFree(GetProcessHeap(), 0, buf);
420     }
421     else
422         result =  pWTInfoW(wCategory, nIndex, lpOutput);
423
424     TRACE("returns %d\n", result);
425     return result;
426 }
427
428 /***********************************************************************
429  *              WTInfoA (WINTAB32.20)
430  */
431 UINT WINAPI WTInfoA(UINT wCategory, UINT nIndex, LPVOID lpOutput)
432 {
433     return WTInfoT(wCategory, nIndex, lpOutput, FALSE);
434 }
435
436
437 /***********************************************************************
438  *              WTInfoW (WINTAB32.1020)
439  */
440 UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
441 {
442     return WTInfoT(wCategory, nIndex, lpOutput, TRUE);
443 }
444
445 /***********************************************************************
446  *              WTOpenW (WINTAB32.2021)
447  */
448 HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable)
449 {
450     LPOPENCONTEXT newcontext;
451
452     TRACE("hWnd=%p, lpLogCtx=%p, fEnable=%u\n", hWnd, lpLogCtx, fEnable);
453     DUMPCONTEXT(*lpLogCtx);
454
455     newcontext = HeapAlloc(GetProcessHeap(), 0 , sizeof(OPENCONTEXT));
456     newcontext->context = *lpLogCtx;
457     newcontext->hwndOwner = hWnd;
458     newcontext->ActiveCursor = -1;
459     newcontext->QueueSize = 10;
460     newcontext->PacketsQueued = 0;
461     newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10);
462
463     EnterCriticalSection(&csTablet);
464     newcontext->handle = gTopContext++;
465     newcontext->next = gOpenContexts;
466     gOpenContexts = newcontext;
467     LeaveCriticalSection(&csTablet);
468
469     pAttachEventQueueToTablet(hWnd);
470
471     TABLET_PostTabletMessage(newcontext, _WT_CTXOPEN(newcontext->context.lcMsgBase), (WPARAM)newcontext->handle,
472                       newcontext->context.lcStatus, TRUE);
473
474     if (fEnable)
475     {
476         newcontext->enabled = TRUE;
477         /* TODO: Add to top of overlap order */
478         newcontext->context.lcStatus = CXS_ONTOP;
479     }
480     else
481     {
482         newcontext->enabled = FALSE;
483         newcontext->context.lcStatus = CXS_DISABLED;
484     }
485
486     TABLET_PostTabletMessage(newcontext, _WT_CTXOVERLAP(newcontext->context.lcMsgBase),
487                             (WPARAM)newcontext->handle,
488                             newcontext->context.lcStatus, TRUE);
489
490     return newcontext->handle;
491 }
492
493 /***********************************************************************
494  *              WTOpenA (WINTAB32.21)
495  */
496 HCTX WINAPI WTOpenA(HWND hWnd, LPLOGCONTEXTA lpLogCtx, BOOL fEnable)
497 {
498     LOGCONTEXTW logCtxW;
499
500     LOGCONTEXTAtoW(lpLogCtx, &logCtxW);
501     return WTOpenW(hWnd, &logCtxW, fEnable);
502 }
503
504 /***********************************************************************
505  *              WTClose (WINTAB32.22)
506  */
507 BOOL WINAPI WTClose(HCTX hCtx)
508 {
509     LPOPENCONTEXT context,ptr;
510
511     TRACE("(%p)\n", hCtx);
512
513     EnterCriticalSection(&csTablet);
514
515     ptr = context = gOpenContexts;
516
517     while (context && (context->handle != hCtx))
518     {
519         ptr = context;
520         context = context->next;
521     }
522     if (!context)
523     {
524         LeaveCriticalSection(&csTablet);
525         return TRUE;
526     }
527
528     if (context == gOpenContexts)
529         gOpenContexts = context->next;
530     else
531         ptr->next = context->next;
532
533     LeaveCriticalSection(&csTablet);
534
535     TABLET_PostTabletMessage(context, _WT_CTXCLOSE(context->context.lcMsgBase), (WPARAM)context->handle,
536                       context->context.lcStatus,TRUE);
537
538     HeapFree(GetProcessHeap(),0,context->PacketQueue);
539     HeapFree(GetProcessHeap(),0,context);
540
541     return TRUE;
542 }
543
544 /***********************************************************************
545  *              WTPacketsGet (WINTAB32.23)
546  */
547 int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
548 {
549     int limit;
550     LPOPENCONTEXT context;
551     LPVOID ptr = lpPkts;
552
553     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
554
555     if (!hCtx)
556         return 0;
557
558     EnterCriticalSection(&csTablet);
559
560     context = TABLET_FindOpenContext(hCtx);
561
562     if (lpPkts != NULL)
563         TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
564
565     if (context->PacketsQueued == 0)
566     {
567         LeaveCriticalSection(&csTablet);
568         return 0;
569     }
570
571     limit = min(cMaxPkts,context->PacketsQueued);
572
573     if(ptr != NULL)
574     {
575         int i = 0;
576         for(i = 0; i < limit; i++)
577             ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[i]);
578     }
579
580
581     if (limit < context->PacketsQueued)
582     {
583         memmove(context->PacketQueue, &context->PacketQueue[limit],
584             (context->PacketsQueued - (limit))*sizeof(WTPACKET));
585     }
586     context->PacketsQueued -= limit;
587     LeaveCriticalSection(&csTablet);
588
589     TRACE("Copied %i packets\n",limit);
590
591     return limit;
592 }
593
594 /***********************************************************************
595  *              WTPacket (WINTAB32.24)
596  */
597 BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
598 {
599     int rc = 0;
600     LPOPENCONTEXT context;
601     LPWTPACKET wtp = NULL;
602
603     TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
604
605     if (!hCtx)
606         return 0;
607
608     EnterCriticalSection(&csTablet);
609
610     context = TABLET_FindOpenContext(hCtx);
611
612     rc = TABLET_FindPacket(context ,wSerial, &wtp);
613
614     if (rc >= 0)
615     {
616         if (lpPkt)
617            TABLET_CopyPacketData(context ,lpPkt, wtp);
618
619         if ((rc+1) < context->QueueSize)
620         {
621             memmove(context->PacketQueue, &context->PacketQueue[rc+1],
622                 (context->PacketsQueued - (rc+1))*sizeof(WTPACKET));
623         }
624         context->PacketsQueued -= (rc+1);
625     }
626     LeaveCriticalSection(&csTablet);
627
628     TRACE("Returning %i\n",rc+1);
629     return rc+1;
630 }
631
632 /***********************************************************************
633  *              WTEnable (WINTAB32.40)
634  */
635 BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
636 {
637     LPOPENCONTEXT context;
638
639     TRACE("hCtx=%p, fEnable=%u\n", hCtx, fEnable);
640
641     if (!hCtx) return FALSE;
642
643     EnterCriticalSection(&csTablet);
644     context = TABLET_FindOpenContext(hCtx);
645     /* if we want to enable and it is not enabled then */
646     if(fEnable && !context->enabled)
647     {
648         context->enabled = TRUE;
649         /* TODO: Add to top of overlap order */
650         context->context.lcStatus = CXS_ONTOP;
651         TABLET_PostTabletMessage(context,
652             _WT_CTXOVERLAP(context->context.lcMsgBase),
653             (WPARAM)context->handle,
654             context->context.lcStatus, TRUE);
655     }
656     /* if we want to disable and it is not disabled then */
657     else if (!fEnable && context->enabled)
658     {
659         context->enabled = FALSE;
660         /* TODO: Remove from overlap order?? needs a test */
661         context->context.lcStatus = CXS_DISABLED;
662         TABLET_FlushQueue(context);
663         TABLET_PostTabletMessage(context,
664             _WT_CTXOVERLAP(context->context.lcMsgBase),
665             (WPARAM)context->handle,
666             context->context.lcStatus, TRUE);
667     }
668     LeaveCriticalSection(&csTablet);
669
670     return TRUE;
671 }
672
673 /***********************************************************************
674  *              WTOverlap (WINTAB32.41)
675  *
676  *              Move context to top or bottom of overlap order
677  */
678 BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
679 {
680     LPOPENCONTEXT context;
681
682     TRACE("hCtx=%p, fToTop=%u\n", hCtx, fToTop);
683
684     if (!hCtx) return FALSE;
685
686     EnterCriticalSection(&csTablet);
687     context = TABLET_FindOpenContext(hCtx);
688     /* if we want to send to top and it's not already there */
689     if (fToTop && context->context.lcStatus != CXS_ONTOP)
690     {
691         /* TODO: Move context to top of overlap order */
692         FIXME("Not moving context to top of overlap order\n");
693         context->context.lcStatus = CXS_ONTOP;
694         TABLET_PostTabletMessage(context,
695             _WT_CTXOVERLAP(context->context.lcMsgBase),
696             (WPARAM)context->handle,
697             context->context.lcStatus, TRUE);
698     }
699     else if (!fToTop)
700     {
701         /* TODO: Move context to bottom of overlap order */
702         FIXME("Not moving context to bottom of overlap order\n");
703         context->context.lcStatus = CXS_OBSCURED;
704         TABLET_PostTabletMessage(context,
705             _WT_CTXOVERLAP(context->context.lcMsgBase),
706             (WPARAM)context->handle,
707             context->context.lcStatus, TRUE);
708     }
709     LeaveCriticalSection(&csTablet);
710
711     return TRUE;
712 }
713
714 /***********************************************************************
715  *              WTConfig (WINTAB32.61)
716  */
717 BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
718 {
719     FIXME("(%p, %p): stub\n", hCtx, hWnd);
720
721     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
722
723     return FALSE;
724 }
725
726 /***********************************************************************
727  *              WTGetA (WINTAB32.61)
728  */
729 BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
730 {
731     LPOPENCONTEXT context;
732
733     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
734
735     if (!hCtx) return 0;
736
737     EnterCriticalSection(&csTablet);
738     context = TABLET_FindOpenContext(hCtx);
739     LOGCONTEXTWtoA(&context->context, lpLogCtx);
740     LeaveCriticalSection(&csTablet);
741
742     return TRUE;
743 }
744
745 /***********************************************************************
746  *              WTGetW (WINTAB32.1061)
747  */
748 BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
749 {
750     LPOPENCONTEXT context;
751
752     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
753
754     if (!hCtx) return 0;
755
756     EnterCriticalSection(&csTablet);
757     context = TABLET_FindOpenContext(hCtx);
758     memmove(lpLogCtx,&context->context,sizeof(LOGCONTEXTW));
759     LeaveCriticalSection(&csTablet);
760
761     return TRUE;
762 }
763
764 /***********************************************************************
765  *              WTSetA (WINTAB32.62)
766  */
767 BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
768 {
769     LPOPENCONTEXT context;
770
771     TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
772
773     if (!hCtx || !lpLogCtx) return FALSE;
774
775     /* TODO: if cur process not owner of hCtx only modify
776      * attribs not locked by owner */
777
778     EnterCriticalSection(&csTablet);
779     context = TABLET_FindOpenContext(hCtx);
780     LOGCONTEXTAtoW(lpLogCtx, &context->context);
781     LeaveCriticalSection(&csTablet);
782
783     return TRUE;
784 }
785
786 /***********************************************************************
787  *              WTSetW (WINTAB32.1062)
788  */
789 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
790 {
791     LPOPENCONTEXT context;
792
793     TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
794
795     if (!hCtx || !lpLogCtx) return FALSE;
796
797     /* TODO: if cur process not hCtx owner only modify
798      * attribs not locked by owner */
799
800     EnterCriticalSection(&csTablet);
801     context = TABLET_FindOpenContext(hCtx);
802     memmove(&context->context, lpLogCtx, sizeof(LOGCONTEXTW));
803     LeaveCriticalSection(&csTablet);
804
805     return TRUE;
806 }
807
808 /***********************************************************************
809  *              WTExtGet (WINTAB32.63)
810  */
811 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
812 {
813     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
814
815     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
816
817     return FALSE;
818 }
819
820 /***********************************************************************
821  *              WTExtSet (WINTAB32.64)
822  */
823 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
824 {
825     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
826
827     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
828
829     return FALSE;
830 }
831
832 /***********************************************************************
833  *              WTSave (WINTAB32.65)
834  */
835 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
836 {
837     FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
838
839     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840
841     return FALSE;
842 }
843
844 /***********************************************************************
845  *              WTRestore (WINTAB32.66)
846  */
847 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
848 {
849     FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
850
851     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
852
853     return 0;
854 }
855
856 /***********************************************************************
857  *              WTPacketsPeek (WINTAB32.80)
858  */
859 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
860 {
861     int limit;
862     LPOPENCONTEXT context;
863     LPVOID ptr = lpPkts;
864
865     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
866
867     if (!hCtx || !lpPkts) return 0;
868
869     EnterCriticalSection(&csTablet);
870
871     context = TABLET_FindOpenContext(hCtx);
872
873     if (context->PacketsQueued == 0)
874     {
875         LeaveCriticalSection(&csTablet);
876         return 0;
877     }
878
879     for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
880         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
881
882     LeaveCriticalSection(&csTablet);
883     TRACE("Copied %i packets\n",limit);
884     return limit;
885 }
886
887 /***********************************************************************
888  *              WTDataGet (WINTAB32.81)
889  */
890 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
891                      int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
892 {
893     LPOPENCONTEXT context;
894     LPVOID ptr = lpPkts;
895     INT bgn = 0;
896     INT end = 0;
897     INT num = 0;
898
899     TRACE("(%p, %u, %u, %d, %p, %p)\n",
900           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
901
902     if (!hCtx) return 0;
903
904     EnterCriticalSection(&csTablet);
905
906     context = TABLET_FindOpenContext(hCtx);
907
908     if (context->PacketsQueued == 0)
909     {
910         LeaveCriticalSection(&csTablet);
911         return 0;
912     }
913
914     while (bgn < context->PacketsQueued &&
915            context->PacketQueue[bgn].pkSerialNumber != wBegin)
916         bgn++;
917
918     end = bgn;
919     while (end < context->PacketsQueued &&
920            context->PacketQueue[end].pkSerialNumber != wEnd)
921         end++;
922
923     if ((bgn == end) && (end == context->PacketsQueued))
924     {
925         LeaveCriticalSection(&csTablet);
926         return 0;
927     }
928
929     for (num = bgn; num <= end; num++)
930         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
931
932     /* remove read packets */
933     if ((end+1) < context->PacketsQueued)
934         memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
935                 (context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
936
937     context->PacketsQueued -= ((end-bgn)+1);
938     *lpNPkts = ((end-bgn)+1);
939
940     LeaveCriticalSection(&csTablet);
941     TRACE("Copied %i packets\n",*lpNPkts);
942     return (end - bgn)+1;
943 }
944
945 /***********************************************************************
946  *              WTDataPeek (WINTAB32.82)
947  */
948 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
949                       int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
950 {
951     LPOPENCONTEXT context;
952     LPVOID ptr = lpPkts;
953     INT bgn = 0;
954     INT end = 0;
955     INT num = 0;
956
957     TRACE("(%p, %u, %u, %d, %p, %p)\n",
958           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
959
960     if (!hCtx || !lpPkts) return 0;
961
962     EnterCriticalSection(&csTablet);
963
964     context = TABLET_FindOpenContext(hCtx);
965
966     if (context->PacketsQueued == 0)
967     {
968         LeaveCriticalSection(&csTablet);
969         return 0;
970     }
971
972     while (bgn < context->PacketsQueued &&
973            context->PacketQueue[bgn].pkSerialNumber != wBegin)
974         bgn++;
975
976     end = bgn;
977     while (end < context->PacketsQueued &&
978            context->PacketQueue[end].pkSerialNumber != wEnd)
979         end++;
980
981     if (bgn == context->PacketsQueued ||  end == context->PacketsQueued)
982     {
983         TRACE("%i %i %i\n", bgn, end, context->PacketsQueued);
984         LeaveCriticalSection(&csTablet);
985         return 0;
986     }
987
988     for (num = bgn; num <= end; num++)
989         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
990
991     *lpNPkts = ((end-bgn)+1);
992     LeaveCriticalSection(&csTablet);
993
994     TRACE("Copied %i packets\n",*lpNPkts);
995     return (end - bgn)+1;
996 }
997
998 /***********************************************************************
999  *              WTQueuePacketsEx (WINTAB32.200)
1000  */
1001 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
1002 {
1003     LPOPENCONTEXT context;
1004
1005     TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
1006
1007     if (!hCtx) return 0;
1008
1009     EnterCriticalSection(&csTablet);
1010
1011     context = TABLET_FindOpenContext(hCtx);
1012
1013     if (context->PacketsQueued)
1014     {
1015         *lpOld = context->PacketQueue[0].pkSerialNumber;
1016         *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
1017     }
1018     else
1019     {
1020         TRACE("No packets\n");
1021         LeaveCriticalSection(&csTablet);
1022         return FALSE;
1023     }
1024     LeaveCriticalSection(&csTablet);
1025
1026     return TRUE;
1027 }
1028
1029 /***********************************************************************
1030  *              WTQueueSizeGet (WINTAB32.84)
1031  */
1032 int WINAPI WTQueueSizeGet(HCTX hCtx)
1033 {
1034     LPOPENCONTEXT context;
1035     TRACE("(%p)\n", hCtx);
1036
1037     if (!hCtx) return 0;
1038
1039     EnterCriticalSection(&csTablet);
1040     context = TABLET_FindOpenContext(hCtx);
1041     LeaveCriticalSection(&csTablet);
1042     return context->QueueSize;
1043 }
1044
1045 /***********************************************************************
1046  *              WTQueueSizeSet (WINTAB32.85)
1047  */
1048 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
1049 {
1050     LPOPENCONTEXT context;
1051
1052     TRACE("(%p, %d)\n", hCtx, nPkts);
1053
1054     if (!hCtx) return 0;
1055
1056     EnterCriticalSection(&csTablet);
1057
1058     context = TABLET_FindOpenContext(hCtx);
1059
1060     context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
1061                         context->PacketQueue, sizeof(WTPACKET)*nPkts);
1062
1063     context->QueueSize = nPkts;
1064     LeaveCriticalSection(&csTablet);
1065
1066     return nPkts;
1067 }