wined3d: Support YUV formats with GL_APPLE_ycbcr_422.
[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     LPOPENCONTEXT context;
696
697     TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
698
699     if (!hCtx || !lpLogCtx) return FALSE;
700
701     /* TODO: if cur process not owner of hCtx only modify
702      * attribs not locked by owner */
703
704     EnterCriticalSection(&csTablet);
705     context = TABLET_FindOpenContext(hCtx);
706     LOGCONTEXTAtoW(lpLogCtx, &context->context);
707     LeaveCriticalSection(&csTablet);
708
709     return TRUE;
710 }
711
712 /***********************************************************************
713  *              WTSetW (WINTAB32.1062)
714  */
715 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
716 {
717     LPOPENCONTEXT context;
718
719     TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
720
721     if (!hCtx || !lpLogCtx) return FALSE;
722
723     /* TODO: if cur process not hCtx owner only modify
724      * attribs not locked by owner */
725
726     EnterCriticalSection(&csTablet);
727     context = TABLET_FindOpenContext(hCtx);
728     memmove(&context->context, lpLogCtx, sizeof(LOGCONTEXTW));
729     LeaveCriticalSection(&csTablet);
730
731     return TRUE;
732 }
733
734 /***********************************************************************
735  *              WTExtGet (WINTAB32.63)
736  */
737 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
738 {
739     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
740
741     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
742
743     return FALSE;
744 }
745
746 /***********************************************************************
747  *              WTExtSet (WINTAB32.64)
748  */
749 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
750 {
751     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
752
753     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
754
755     return FALSE;
756 }
757
758 /***********************************************************************
759  *              WTSave (WINTAB32.65)
760  */
761 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
762 {
763     FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
764
765     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
766
767     return FALSE;
768 }
769
770 /***********************************************************************
771  *              WTRestore (WINTAB32.66)
772  */
773 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
774 {
775     FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
776
777     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
778
779     return 0;
780 }
781
782 /***********************************************************************
783  *              WTPacketsPeek (WINTAB32.80)
784  */
785 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
786 {
787     int limit;
788     LPOPENCONTEXT context;
789     LPVOID ptr = lpPkts;
790
791     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
792
793     if (!hCtx || !lpPkts) return 0;
794
795     EnterCriticalSection(&csTablet);
796
797     context = TABLET_FindOpenContext(hCtx);
798
799     if (context->PacketsQueued == 0)
800     {
801         LeaveCriticalSection(&csTablet);
802         return 0;
803     }
804
805     for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
806         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
807
808     LeaveCriticalSection(&csTablet);
809     TRACE("Copied %i packets\n",limit);
810     return limit;
811 }
812
813 /***********************************************************************
814  *              WTDataGet (WINTAB32.81)
815  */
816 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
817                      int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
818 {
819     LPOPENCONTEXT context;
820     LPVOID ptr = lpPkts;
821     INT bgn = 0;
822     INT end = 0;
823     INT num = 0;
824
825     TRACE("(%p, %u, %u, %d, %p, %p)\n",
826           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
827
828     if (!hCtx) return 0;
829
830     EnterCriticalSection(&csTablet);
831
832     context = TABLET_FindOpenContext(hCtx);
833
834     if (context->PacketsQueued == 0)
835     {
836         LeaveCriticalSection(&csTablet);
837         return 0;
838     }
839
840     while (bgn < context->PacketsQueued &&
841            context->PacketQueue[bgn].pkSerialNumber != wBegin)
842         bgn++;
843
844     end = bgn;
845     while (end < context->PacketsQueued &&
846            context->PacketQueue[end].pkSerialNumber != wEnd)
847         end++;
848
849     if ((bgn == end) && (end == context->PacketsQueued))
850     {
851         LeaveCriticalSection(&csTablet);
852         return 0;
853     }
854
855     for (num = bgn; num <= end; num++)
856         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
857
858     /* remove read packets */
859     if ((end+1) < context->PacketsQueued)
860         memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
861                 (context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
862
863     context->PacketsQueued -= ((end-bgn)+1);
864     *lpNPkts = ((end-bgn)+1);
865
866     LeaveCriticalSection(&csTablet);
867     TRACE("Copied %i packets\n",*lpNPkts);
868     return (end - bgn)+1;
869 }
870
871 /***********************************************************************
872  *              WTDataPeek (WINTAB32.82)
873  */
874 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
875                       int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
876 {
877     LPOPENCONTEXT context;
878     LPVOID ptr = lpPkts;
879     INT bgn = 0;
880     INT end = 0;
881     INT num = 0;
882
883     TRACE("(%p, %u, %u, %d, %p, %p)\n",
884           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
885
886     if (!hCtx || !lpPkts) return 0;
887
888     EnterCriticalSection(&csTablet);
889
890     context = TABLET_FindOpenContext(hCtx);
891
892     if (context->PacketsQueued == 0)
893     {
894         LeaveCriticalSection(&csTablet);
895         return 0;
896     }
897
898     while (bgn < context->PacketsQueued &&
899            context->PacketQueue[bgn].pkSerialNumber != wBegin)
900         bgn++;
901
902     end = bgn;
903     while (end < context->PacketsQueued &&
904            context->PacketQueue[end].pkSerialNumber != wEnd)
905         end++;
906
907     if (bgn == context->PacketsQueued ||  end == context->PacketsQueued)
908     {
909         TRACE("%i %i %i\n", bgn, end, context->PacketsQueued);
910         LeaveCriticalSection(&csTablet);
911         return 0;
912     }
913
914     for (num = bgn; num <= end; num++)
915         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
916
917     *lpNPkts = ((end-bgn)+1);
918     LeaveCriticalSection(&csTablet);
919
920     TRACE("Copied %i packets\n",*lpNPkts);
921     return (end - bgn)+1;
922 }
923
924 /***********************************************************************
925  *              WTQueuePacketsEx (WINTAB32.200)
926  */
927 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
928 {
929     LPOPENCONTEXT context;
930
931     TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
932
933     if (!hCtx) return 0;
934
935     EnterCriticalSection(&csTablet);
936
937     context = TABLET_FindOpenContext(hCtx);
938
939     if (context->PacketsQueued)
940     {
941         *lpOld = context->PacketQueue[0].pkSerialNumber;
942         *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
943     }
944     else
945     {
946         TRACE("No packets\n");
947         LeaveCriticalSection(&csTablet);
948         return FALSE;
949     }
950     LeaveCriticalSection(&csTablet);
951
952     return TRUE;
953 }
954
955 /***********************************************************************
956  *              WTQueueSizeGet (WINTAB32.84)
957  */
958 int WINAPI WTQueueSizeGet(HCTX hCtx)
959 {
960     LPOPENCONTEXT context;
961     TRACE("(%p)\n", hCtx);
962
963     if (!hCtx) return 0;
964
965     EnterCriticalSection(&csTablet);
966     context = TABLET_FindOpenContext(hCtx);
967     LeaveCriticalSection(&csTablet);
968     return context->QueueSize;
969 }
970
971 /***********************************************************************
972  *              WTQueueSizeSet (WINTAB32.85)
973  */
974 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
975 {
976     LPOPENCONTEXT context;
977
978     TRACE("(%p, %d)\n", hCtx, nPkts);
979
980     if (!hCtx) return 0;
981
982     EnterCriticalSection(&csTablet);
983
984     context = TABLET_FindOpenContext(hCtx);
985
986     context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
987                         context->PacketQueue, sizeof(WTPACKET)*nPkts);
988
989     context->QueueSize = nPkts;
990     LeaveCriticalSection(&csTablet);
991
992     return nPkts;
993 }