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