hlink/tests: Sign compare fix.
[wine] / dlls / msctf / threadmgr.c
1 /*
2  *  ITfThreadMgr implementation
3  *
4  *  Copyright 2008 Aric Stewart, CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #define COBJMACROS
26
27 #include "wine/debug.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #include "shlwapi.h"
33 #include "winerror.h"
34 #include "objbase.h"
35 #include "olectl.h"
36
37 #include "wine/unicode.h"
38 #include "wine/list.h"
39
40 #include "msctf.h"
41 #include "msctf_internal.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
44
45 typedef struct tagThreadMgrSink {
46     struct list         entry;
47     union {
48         /* ThreadMgr Sinks */
49         IUnknown            *pIUnknown;
50         /* ITfActiveLanguageProfileNotifySink *pITfActiveLanguageProfileNotifySink; */
51         /* ITfDisplayAttributeNotifySink *pITfDisplayAttributeNotifySink; */
52         /* ITfKeyTraceEventSink *pITfKeyTraceEventSink; */
53         /* ITfPreservedKeyNotifySink *pITfPreservedKeyNotifySink; */
54         /* ITfThreadFocusSink *pITfThreadFocusSink; */
55         ITfThreadMgrEventSink *pITfThreadMgrEventSink;
56     } interfaces;
57 } ThreadMgrSink;
58
59 typedef struct tagPreservedKey
60 {
61     struct list     entry;
62     GUID            guid;
63     TF_PRESERVEDKEY prekey;
64     LPWSTR          description;
65     TfClientId      tid;
66 } PreservedKey;
67
68 typedef struct tagACLMulti {
69     const ITfThreadMgrVtbl *ThreadMgrVtbl;
70     const ITfSourceVtbl *SourceVtbl;
71     const ITfKeystrokeMgrVtbl *KeystrokeMgrVtbl;
72     const ITfMessagePumpVtbl *MessagePumpVtbl;
73     const ITfClientIdVtbl *ClientIdVtbl;
74     LONG refCount;
75
76     const ITfThreadMgrEventSinkVtbl *ThreadMgrEventSinkVtbl; /* internal */
77
78     ITfDocumentMgr *focus;
79     LONG activationCount;
80
81     struct list CurrentPreservedKeys;
82
83     /* kept as separate lists to reduce unnecessary iterations */
84     struct list     ActiveLanguageProfileNotifySink;
85     struct list     DisplayAttributeNotifySink;
86     struct list     KeyTraceEventSink;
87     struct list     PreservedKeyNotifySink;
88     struct list     ThreadFocusSink;
89     struct list     ThreadMgrEventSink;
90 } ThreadMgr;
91
92 static inline ThreadMgr *impl_from_ITfSourceVtbl(ITfSource *iface)
93 {
94     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,SourceVtbl));
95 }
96
97 static inline ThreadMgr *impl_from_ITfKeystrokeMgrVtbl(ITfKeystrokeMgr *iface)
98 {
99     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,KeystrokeMgrVtbl));
100 }
101
102 static inline ThreadMgr *impl_from_ITfMessagePumpVtbl(ITfMessagePump *iface)
103 {
104     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,MessagePumpVtbl));
105 }
106
107 static inline ThreadMgr *impl_from_ITfClientIdVtbl(ITfClientId *iface)
108 {
109     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ClientIdVtbl));
110 }
111
112 static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *iface)
113 {
114     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ThreadMgrEventSinkVtbl));
115 }
116
117 static void free_sink(ThreadMgrSink *sink)
118 {
119         IUnknown_Release(sink->interfaces.pIUnknown);
120         HeapFree(GetProcessHeap(),0,sink);
121 }
122
123 static void ThreadMgr_Destructor(ThreadMgr *This)
124 {
125     struct list *cursor, *cursor2;
126
127     TlsSetValue(tlsIndex,NULL);
128     TRACE("destroying %p\n", This);
129     if (This->focus)
130         ITfDocumentMgr_Release(This->focus);
131
132     /* free sinks */
133     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ActiveLanguageProfileNotifySink)
134     {
135         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
136         list_remove(cursor);
137         free_sink(sink);
138     }
139     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->DisplayAttributeNotifySink)
140     {
141         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
142         list_remove(cursor);
143         free_sink(sink);
144     }
145     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->KeyTraceEventSink)
146     {
147         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
148         list_remove(cursor);
149         free_sink(sink);
150     }
151     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->PreservedKeyNotifySink)
152     {
153         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
154         list_remove(cursor);
155         free_sink(sink);
156     }
157     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ThreadFocusSink)
158     {
159         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
160         list_remove(cursor);
161         free_sink(sink);
162     }
163     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ThreadMgrEventSink)
164     {
165         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
166         list_remove(cursor);
167         free_sink(sink);
168     }
169
170     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CurrentPreservedKeys)
171     {
172         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
173         list_remove(cursor);
174         HeapFree(GetProcessHeap(),0,key->description);
175         HeapFree(GetProcessHeap(),0,key);
176     }
177
178     HeapFree(GetProcessHeap(),0,This);
179 }
180
181 static HRESULT WINAPI ThreadMgr_QueryInterface(ITfThreadMgr *iface, REFIID iid, LPVOID *ppvOut)
182 {
183     ThreadMgr *This = (ThreadMgr *)iface;
184     *ppvOut = NULL;
185
186     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgr))
187     {
188         *ppvOut = This;
189     }
190     else if (IsEqualIID(iid, &IID_ITfSource))
191     {
192         *ppvOut = &This->SourceVtbl;
193     }
194     else if (IsEqualIID(iid, &IID_ITfKeystrokeMgr))
195     {
196         *ppvOut = &This->KeystrokeMgrVtbl;
197     }
198     else if (IsEqualIID(iid, &IID_ITfMessagePump))
199     {
200         *ppvOut = &This->MessagePumpVtbl;
201     }
202     else if (IsEqualIID(iid, &IID_ITfClientId))
203     {
204         *ppvOut = &This->ClientIdVtbl;
205     }
206
207     if (*ppvOut)
208     {
209         IUnknown_AddRef(iface);
210         return S_OK;
211     }
212
213     WARN("unsupported interface: %s\n", debugstr_guid(iid));
214     return E_NOINTERFACE;
215 }
216
217 static ULONG WINAPI ThreadMgr_AddRef(ITfThreadMgr *iface)
218 {
219     ThreadMgr *This = (ThreadMgr *)iface;
220     return InterlockedIncrement(&This->refCount);
221 }
222
223 static ULONG WINAPI ThreadMgr_Release(ITfThreadMgr *iface)
224 {
225     ThreadMgr *This = (ThreadMgr *)iface;
226     ULONG ret;
227
228     ret = InterlockedDecrement(&This->refCount);
229     if (ret == 0)
230         ThreadMgr_Destructor(This);
231     return ret;
232 }
233
234 /*****************************************************
235  * ITfThreadMgr functions
236  *****************************************************/
237
238 static HRESULT WINAPI ThreadMgr_fnActivate( ITfThreadMgr* iface, TfClientId *ptid)
239 {
240     ThreadMgr *This = (ThreadMgr *)iface;
241
242     TRACE("(%p) %p\n",This, ptid);
243
244     if (!ptid)
245         return E_INVALIDARG;
246
247     if (!processId)
248     {
249         GUID guid;
250         CoCreateGuid(&guid);
251         ITfClientId_GetClientId((ITfClientId*)&This->ClientIdVtbl,&guid,&processId);
252     }
253
254     activate_textservices(iface);
255     This->activationCount++;
256     *ptid = processId;
257     return S_OK;
258 }
259
260 static HRESULT WINAPI ThreadMgr_fnDeactivate( ITfThreadMgr* iface)
261 {
262     ThreadMgr *This = (ThreadMgr *)iface;
263     TRACE("(%p)\n",This);
264
265     if (This->activationCount == 0)
266         return E_UNEXPECTED;
267
268     This->activationCount --;
269
270     if (This->activationCount == 0)
271     {
272         if (This->focus)
273         {
274             ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, 0, This->focus);
275             ITfDocumentMgr_Release(This->focus);
276             This->focus = 0;
277         }
278     }
279
280     deactivate_textservices();
281
282     return S_OK;
283 }
284
285 static HRESULT WINAPI ThreadMgr_CreateDocumentMgr( ITfThreadMgr* iface, ITfDocumentMgr
286 **ppdim)
287 {
288     ThreadMgr *This = (ThreadMgr *)iface;
289     TRACE("(%p)\n",iface);
290     return DocumentMgr_Constructor((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, ppdim);
291 }
292
293 static HRESULT WINAPI ThreadMgr_EnumDocumentMgrs( ITfThreadMgr* iface, IEnumTfDocumentMgrs
294 **ppEnum)
295 {
296     ThreadMgr *This = (ThreadMgr *)iface;
297     FIXME("STUB:(%p)\n",This);
298     return E_NOTIMPL;
299 }
300
301 static HRESULT WINAPI ThreadMgr_GetFocus( ITfThreadMgr* iface, ITfDocumentMgr
302 **ppdimFocus)
303 {
304     ThreadMgr *This = (ThreadMgr *)iface;
305     TRACE("(%p)\n",This);
306
307     if (!ppdimFocus)
308         return E_INVALIDARG;
309
310     *ppdimFocus = This->focus;
311
312     TRACE("->%p\n",This->focus);
313
314     if (This->focus == NULL)
315         return S_FALSE;
316
317     ITfDocumentMgr_AddRef(This->focus);
318
319     return S_OK;
320 }
321
322 static HRESULT WINAPI ThreadMgr_SetFocus( ITfThreadMgr* iface, ITfDocumentMgr *pdimFocus)
323 {
324     ITfDocumentMgr *check;
325     ThreadMgr *This = (ThreadMgr *)iface;
326
327     TRACE("(%p) %p\n",This,pdimFocus);
328
329     if (!pdimFocus || FAILED(IUnknown_QueryInterface(pdimFocus,&IID_ITfDocumentMgr,(LPVOID*) &check)))
330         return E_INVALIDARG;
331
332     ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, check, This->focus);
333
334     if (This->focus)
335         ITfDocumentMgr_Release(This->focus);
336
337     This->focus = check;
338     return S_OK;
339 }
340
341 static HRESULT WINAPI ThreadMgr_AssociateFocus( ITfThreadMgr* iface, HWND hwnd,
342 ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev)
343 {
344     ThreadMgr *This = (ThreadMgr *)iface;
345     FIXME("STUB:(%p)\n",This);
346     return E_NOTIMPL;
347 }
348
349 static HRESULT WINAPI ThreadMgr_IsThreadFocus( ITfThreadMgr* iface, BOOL *pfThreadFocus)
350 {
351     ThreadMgr *This = (ThreadMgr *)iface;
352     FIXME("STUB:(%p)\n",This);
353     return E_NOTIMPL;
354 }
355
356 static HRESULT WINAPI ThreadMgr_GetFunctionProvider( ITfThreadMgr* iface, REFCLSID clsid,
357 ITfFunctionProvider **ppFuncProv)
358 {
359     ThreadMgr *This = (ThreadMgr *)iface;
360     FIXME("STUB:(%p)\n",This);
361     return E_NOTIMPL;
362 }
363
364 static HRESULT WINAPI ThreadMgr_EnumFunctionProviders( ITfThreadMgr* iface,
365 IEnumTfFunctionProviders **ppEnum)
366 {
367     ThreadMgr *This = (ThreadMgr *)iface;
368     FIXME("STUB:(%p)\n",This);
369     return E_NOTIMPL;
370 }
371
372 static HRESULT WINAPI ThreadMgr_GetGlobalCompartment( ITfThreadMgr* iface,
373 ITfCompartmentMgr **ppCompMgr)
374 {
375     ThreadMgr *This = (ThreadMgr *)iface;
376     FIXME("STUB:(%p)\n",This);
377     return E_NOTIMPL;
378 }
379
380 static const ITfThreadMgrVtbl ThreadMgr_ThreadMgrVtbl =
381 {
382     ThreadMgr_QueryInterface,
383     ThreadMgr_AddRef,
384     ThreadMgr_Release,
385
386     ThreadMgr_fnActivate,
387     ThreadMgr_fnDeactivate,
388     ThreadMgr_CreateDocumentMgr,
389     ThreadMgr_EnumDocumentMgrs,
390     ThreadMgr_GetFocus,
391     ThreadMgr_SetFocus,
392     ThreadMgr_AssociateFocus,
393     ThreadMgr_IsThreadFocus,
394     ThreadMgr_GetFunctionProvider,
395     ThreadMgr_EnumFunctionProviders,
396     ThreadMgr_GetGlobalCompartment
397 };
398
399
400 static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
401 {
402     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
403     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
404 }
405
406 static ULONG WINAPI Source_AddRef(ITfSource *iface)
407 {
408     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
409     return ThreadMgr_AddRef((ITfThreadMgr*)This);
410 }
411
412 static ULONG WINAPI Source_Release(ITfSource *iface)
413 {
414     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
415     return ThreadMgr_Release((ITfThreadMgr *)This);
416 }
417
418 /*****************************************************
419  * ITfSource functions
420  *****************************************************/
421 static WINAPI HRESULT ThreadMgrSource_AdviseSink(ITfSource *iface,
422         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
423 {
424     ThreadMgrSink *tms;
425     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
426
427     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
428
429     if (!riid || !punk || !pdwCookie)
430         return E_INVALIDARG;
431
432     if (IsEqualIID(riid, &IID_ITfThreadMgrEventSink))
433     {
434         tms = HeapAlloc(GetProcessHeap(),0,sizeof(ThreadMgrSink));
435         if (!tms)
436             return E_OUTOFMEMORY;
437         if (!SUCCEEDED(IUnknown_QueryInterface(punk, riid, (LPVOID*)&tms->interfaces.pITfThreadMgrEventSink)))
438         {
439             HeapFree(GetProcessHeap(),0,tms);
440             return CONNECT_E_CANNOTCONNECT;
441         }
442         list_add_head(&This->ThreadMgrEventSink,&tms->entry);
443         *pdwCookie = generate_Cookie(COOKIE_MAGIC_TMSINK, tms);
444     }
445     else
446     {
447         FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
448         return E_NOTIMPL;
449     }
450
451     TRACE("cookie %x\n",*pdwCookie);
452
453     return S_OK;
454 }
455
456 static WINAPI HRESULT ThreadMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
457 {
458     ThreadMgrSink *sink;
459     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
460
461     TRACE("(%p) %x\n",This,pdwCookie);
462
463     if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_TMSINK)
464         return E_INVALIDARG;
465
466     sink = (ThreadMgrSink*)remove_Cookie(pdwCookie);
467     if (!sink)
468         return CONNECT_E_NOCONNECTION;
469
470     list_remove(&sink->entry);
471     free_sink(sink);
472
473     return S_OK;
474 }
475
476 static const ITfSourceVtbl ThreadMgr_SourceVtbl =
477 {
478     Source_QueryInterface,
479     Source_AddRef,
480     Source_Release,
481
482     ThreadMgrSource_AdviseSink,
483     ThreadMgrSource_UnadviseSink,
484 };
485
486 /*****************************************************
487  * ITfKeystrokeMgr functions
488  *****************************************************/
489
490 static HRESULT WINAPI KeystrokeMgr_QueryInterface(ITfKeystrokeMgr *iface, REFIID iid, LPVOID *ppvOut)
491 {
492     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
493     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
494 }
495
496 static ULONG WINAPI KeystrokeMgr_AddRef(ITfKeystrokeMgr *iface)
497 {
498     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
499     return ThreadMgr_AddRef((ITfThreadMgr*)This);
500 }
501
502 static ULONG WINAPI KeystrokeMgr_Release(ITfKeystrokeMgr *iface)
503 {
504     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
505     return ThreadMgr_Release((ITfThreadMgr *)This);
506 }
507
508 static HRESULT WINAPI KeystrokeMgr_AdviseKeyEventSink(ITfKeystrokeMgr *iface,
509         TfClientId tid, ITfKeyEventSink *pSink, BOOL fForeground)
510 {
511     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
512     FIXME("STUB:(%p)\n",This);
513     return E_NOTIMPL;
514 }
515
516 static HRESULT WINAPI KeystrokeMgr_UnadviseKeyEventSink(ITfKeystrokeMgr *iface,
517         TfClientId tid)
518 {
519     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
520     FIXME("STUB:(%p)\n",This);
521     return E_NOTIMPL;
522 }
523
524 static HRESULT WINAPI KeystrokeMgr_GetForeground(ITfKeystrokeMgr *iface,
525         CLSID *pclsid)
526 {
527     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
528     FIXME("STUB:(%p)\n",This);
529     return E_NOTIMPL;
530 }
531
532 static HRESULT WINAPI KeystrokeMgr_TestKeyDown(ITfKeystrokeMgr *iface,
533         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
534 {
535     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
536     FIXME("STUB:(%p)\n",This);
537     return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI KeystrokeMgr_TestKeyUp(ITfKeystrokeMgr *iface,
541         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
542 {
543     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
544     FIXME("STUB:(%p)\n",This);
545     return E_NOTIMPL;
546 }
547
548 static HRESULT WINAPI KeystrokeMgr_KeyDown(ITfKeystrokeMgr *iface,
549         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
550 {
551     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
552     FIXME("STUB:(%p)\n",This);
553     return E_NOTIMPL;
554 }
555
556 static HRESULT WINAPI KeystrokeMgr_KeyUp(ITfKeystrokeMgr *iface,
557         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
558 {
559     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
560     FIXME("STUB:(%p)\n",This);
561     return E_NOTIMPL;
562 }
563
564 static HRESULT WINAPI KeystrokeMgr_GetPreservedKey(ITfKeystrokeMgr *iface,
565         ITfContext *pic, const TF_PRESERVEDKEY *pprekey, GUID *pguid)
566 {
567     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
568     FIXME("STUB:(%p)\n",This);
569     return E_NOTIMPL;
570 }
571
572 static HRESULT WINAPI KeystrokeMgr_IsPreservedKey(ITfKeystrokeMgr *iface,
573         REFGUID rguid, const TF_PRESERVEDKEY *pprekey, BOOL *pfRegistered)
574 {
575     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
576     struct list *cursor;
577
578     TRACE("(%p) %s (%x %x) %p\n",This,debugstr_guid(rguid), (pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0, pfRegistered);
579
580     if (!rguid || !pprekey || !pfRegistered)
581         return E_INVALIDARG;
582
583     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
584     {
585         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
586         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
587         {
588             *pfRegistered = TRUE;
589             return S_OK;
590         }
591     }
592
593     *pfRegistered = FALSE;
594     return S_FALSE;
595 }
596
597 static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface,
598         TfClientId tid, REFGUID rguid, const TF_PRESERVEDKEY *prekey,
599         const WCHAR *pchDesc, ULONG cchDesc)
600 {
601     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
602     struct list *cursor;
603     PreservedKey *newkey;
604
605     TRACE("(%p) %x %s (%x,%x) %s\n",This,tid, debugstr_guid(rguid),(prekey)?prekey->uVKey:0,(prekey)?prekey->uModifiers:0,debugstr_wn(pchDesc,cchDesc));
606
607     if (!tid || ! rguid || !prekey || (cchDesc && !pchDesc))
608         return E_INVALIDARG;
609
610     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
611     {
612         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
613         if (IsEqualGUID(rguid,&key->guid) && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers)
614             return TF_E_ALREADY_EXISTS;
615     }
616
617     newkey = HeapAlloc(GetProcessHeap(),0,sizeof(PreservedKey));
618     if (!newkey)
619         return E_OUTOFMEMORY;
620
621     newkey->guid  = *rguid;
622     newkey->prekey = *prekey;
623     newkey->tid = tid;
624     if (cchDesc)
625     {
626         newkey->description = HeapAlloc(GetProcessHeap(),0,cchDesc * sizeof(WCHAR));
627         if (!newkey->description)
628         {
629             HeapFree(GetProcessHeap(),0,newkey);
630             return E_OUTOFMEMORY;
631         }
632         memcpy(newkey->description, pchDesc, cchDesc*sizeof(WCHAR));
633     }
634
635     list_add_head(&This->CurrentPreservedKeys,&newkey->entry);
636
637     return S_OK;
638 }
639
640 static HRESULT WINAPI KeystrokeMgr_UnpreserveKey(ITfKeystrokeMgr *iface,
641         REFGUID rguid, const TF_PRESERVEDKEY *pprekey)
642 {
643     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
644     PreservedKey* key = NULL;
645     struct list *cursor;
646     TRACE("(%p) %s (%x %x)\n",This,debugstr_guid(rguid),(pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0);
647
648     if (!pprekey || !rguid)
649         return E_INVALIDARG;
650
651     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
652     {
653         key = LIST_ENTRY(cursor,PreservedKey,entry);
654         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
655             break;
656         key = NULL;
657     }
658
659     if (!key)
660         return CONNECT_E_NOCONNECTION;
661
662     list_remove(&key->entry);
663     HeapFree(GetProcessHeap(),0,key->description);
664     HeapFree(GetProcessHeap(),0,key);
665
666     return S_OK;
667 }
668
669 static HRESULT WINAPI KeystrokeMgr_SetPreservedKeyDescription(ITfKeystrokeMgr *iface,
670         REFGUID rguid, const WCHAR *pchDesc, ULONG cchDesc)
671 {
672     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
673     FIXME("STUB:(%p)\n",This);
674     return E_NOTIMPL;
675 }
676
677 static HRESULT WINAPI KeystrokeMgr_GetPreservedKeyDescription(ITfKeystrokeMgr *iface,
678         REFGUID rguid, BSTR *pbstrDesc)
679 {
680     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
681     FIXME("STUB:(%p)\n",This);
682     return E_NOTIMPL;
683 }
684
685 static HRESULT WINAPI KeystrokeMgr_SimulatePreservedKey(ITfKeystrokeMgr *iface,
686         ITfContext *pic, REFGUID rguid, BOOL *pfEaten)
687 {
688     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
689     FIXME("STUB:(%p)\n",This);
690     return E_NOTIMPL;
691 }
692
693 static const ITfKeystrokeMgrVtbl ThreadMgr_KeystrokeMgrVtbl =
694 {
695     KeystrokeMgr_QueryInterface,
696     KeystrokeMgr_AddRef,
697     KeystrokeMgr_Release,
698
699     KeystrokeMgr_AdviseKeyEventSink,
700     KeystrokeMgr_UnadviseKeyEventSink,
701     KeystrokeMgr_GetForeground,
702     KeystrokeMgr_TestKeyDown,
703     KeystrokeMgr_TestKeyUp,
704     KeystrokeMgr_KeyDown,
705     KeystrokeMgr_KeyUp,
706     KeystrokeMgr_GetPreservedKey,
707     KeystrokeMgr_IsPreservedKey,
708     KeystrokeMgr_PreserveKey,
709     KeystrokeMgr_UnpreserveKey,
710     KeystrokeMgr_SetPreservedKeyDescription,
711     KeystrokeMgr_GetPreservedKeyDescription,
712     KeystrokeMgr_SimulatePreservedKey
713 };
714
715 /*****************************************************
716  * ITfMessagePump functions
717  *****************************************************/
718
719 static HRESULT WINAPI MessagePump_QueryInterface(ITfMessagePump *iface, REFIID iid, LPVOID *ppvOut)
720 {
721     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
722     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
723 }
724
725 static ULONG WINAPI MessagePump_AddRef(ITfMessagePump *iface)
726 {
727     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
728     return ThreadMgr_AddRef((ITfThreadMgr*)This);
729 }
730
731 static ULONG WINAPI MessagePump_Release(ITfMessagePump *iface)
732 {
733     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
734     return ThreadMgr_Release((ITfThreadMgr *)This);
735 }
736
737 static HRESULT WINAPI MessagePump_PeekMessageA(ITfMessagePump *iface,
738         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
739         UINT wRemoveMsg, BOOL *pfResult)
740 {
741     if (!pfResult)
742         return E_INVALIDARG;
743     *pfResult = PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
744     return S_OK;
745 }
746
747 static HRESULT WINAPI MessagePump_GetMessageA(ITfMessagePump *iface,
748         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
749         BOOL *pfResult)
750 {
751     if (!pfResult)
752         return E_INVALIDARG;
753     *pfResult = GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
754     return S_OK;
755 }
756
757 static HRESULT WINAPI MessagePump_PeekMessageW(ITfMessagePump *iface,
758         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
759         UINT wRemoveMsg, BOOL *pfResult)
760 {
761     if (!pfResult)
762         return E_INVALIDARG;
763     *pfResult = PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
764     return S_OK;
765 }
766
767 static HRESULT WINAPI MessagePump_GetMessageW(ITfMessagePump *iface,
768         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
769         BOOL *pfResult)
770 {
771     if (!pfResult)
772         return E_INVALIDARG;
773     *pfResult = GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
774     return S_OK;
775 }
776
777 static const ITfMessagePumpVtbl ThreadMgr_MessagePumpVtbl =
778 {
779     MessagePump_QueryInterface,
780     MessagePump_AddRef,
781     MessagePump_Release,
782
783     MessagePump_PeekMessageA,
784     MessagePump_GetMessageA,
785     MessagePump_PeekMessageW,
786     MessagePump_GetMessageW
787 };
788
789 /*****************************************************
790  * ITfClientId functions
791  *****************************************************/
792
793 static HRESULT WINAPI ClientId_QueryInterface(ITfClientId *iface, REFIID iid, LPVOID *ppvOut)
794 {
795     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
796     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
797 }
798
799 static ULONG WINAPI ClientId_AddRef(ITfClientId *iface)
800 {
801     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
802     return ThreadMgr_AddRef((ITfThreadMgr*)This);
803 }
804
805 static ULONG WINAPI ClientId_Release(ITfClientId *iface)
806 {
807     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
808     return ThreadMgr_Release((ITfThreadMgr *)This);
809 }
810
811 static HRESULT WINAPI ClientId_GetClientId(ITfClientId *iface,
812     REFCLSID rclsid, TfClientId *ptid)
813
814 {
815     HRESULT hr;
816     ITfCategoryMgr *catmgr;
817     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
818
819     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
820
821     CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
822     hr = ITfCategoryMgr_RegisterGUID(catmgr,rclsid,ptid);
823     ITfCategoryMgr_Release(catmgr);
824
825     return hr;
826 }
827
828 static const ITfClientIdVtbl ThreadMgr_ClientIdVtbl =
829 {
830     ClientId_QueryInterface,
831     ClientId_AddRef,
832     ClientId_Release,
833
834     ClientId_GetClientId
835 };
836
837 /*****************************************************
838  * ITfThreadMgrEventSink functions  (internal)
839  *****************************************************/
840 static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut)
841 {
842     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
843     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
844 }
845
846 static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface)
847 {
848     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
849     return ThreadMgr_AddRef((ITfThreadMgr*)This);
850 }
851
852 static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface)
853 {
854     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
855     return ThreadMgr_Release((ITfThreadMgr *)This);
856 }
857
858
859 static WINAPI HRESULT ThreadMgrEventSink_OnInitDocumentMgr(
860         ITfThreadMgrEventSink *iface,ITfDocumentMgr *pdim)
861 {
862     struct list *cursor;
863     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
864
865     TRACE("(%p) %p\n",This,pdim);
866
867     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
868     {
869         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
870         ITfThreadMgrEventSink_OnInitDocumentMgr(sink->interfaces.pITfThreadMgrEventSink,pdim);
871     }
872
873     return S_OK;
874 }
875
876 static WINAPI HRESULT ThreadMgrEventSink_OnUninitDocumentMgr(
877         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdim)
878 {
879     struct list *cursor;
880     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
881
882     TRACE("(%p) %p\n",This,pdim);
883
884     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
885     {
886         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
887         ITfThreadMgrEventSink_OnUninitDocumentMgr(sink->interfaces.pITfThreadMgrEventSink,pdim);
888     }
889
890     return S_OK;
891 }
892
893 static WINAPI HRESULT ThreadMgrEventSink_OnSetFocus(
894         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdimFocus,
895         ITfDocumentMgr *pdimPrevFocus)
896 {
897     struct list *cursor;
898     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
899
900     TRACE("(%p) %p %p\n",This,pdimFocus, pdimPrevFocus);
901
902     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
903     {
904         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
905         ITfThreadMgrEventSink_OnSetFocus(sink->interfaces.pITfThreadMgrEventSink, pdimFocus, pdimPrevFocus);
906     }
907
908     return S_OK;
909 }
910
911 static WINAPI HRESULT ThreadMgrEventSink_OnPushContext(
912         ITfThreadMgrEventSink *iface, ITfContext *pic)
913 {
914     struct list *cursor;
915     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
916
917     TRACE("(%p) %p\n",This,pic);
918
919     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
920     {
921         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
922         ITfThreadMgrEventSink_OnPushContext(sink->interfaces.pITfThreadMgrEventSink,pic);
923     }
924
925     return S_OK;
926 }
927
928 static WINAPI HRESULT ThreadMgrEventSink_OnPopContext(
929         ITfThreadMgrEventSink *iface, ITfContext *pic)
930 {
931     struct list *cursor;
932     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
933
934     TRACE("(%p) %p\n",This,pic);
935
936     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
937     {
938         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
939         ITfThreadMgrEventSink_OnPopContext(sink->interfaces.pITfThreadMgrEventSink,pic);
940     }
941
942     return S_OK;
943 }
944
945 static const ITfThreadMgrEventSinkVtbl ThreadMgr_ThreadMgrEventSinkVtbl =
946 {
947     ThreadMgrEventSink_QueryInterface,
948     ThreadMgrEventSink_AddRef,
949     ThreadMgrEventSink_Release,
950
951     ThreadMgrEventSink_OnInitDocumentMgr,
952     ThreadMgrEventSink_OnUninitDocumentMgr,
953     ThreadMgrEventSink_OnSetFocus,
954     ThreadMgrEventSink_OnPushContext,
955     ThreadMgrEventSink_OnPopContext
956 };
957
958 HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
959 {
960     ThreadMgr *This;
961     if (pUnkOuter)
962         return CLASS_E_NOAGGREGATION;
963
964     /* Only 1 ThreadMgr is created per thread */
965     This = TlsGetValue(tlsIndex);
966     if (This)
967     {
968         ThreadMgr_AddRef((ITfThreadMgr*)This);
969         *ppOut = (IUnknown*)This;
970         return S_OK;
971     }
972
973     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr));
974     if (This == NULL)
975         return E_OUTOFMEMORY;
976
977     This->ThreadMgrVtbl= &ThreadMgr_ThreadMgrVtbl;
978     This->SourceVtbl = &ThreadMgr_SourceVtbl;
979     This->KeystrokeMgrVtbl= &ThreadMgr_KeystrokeMgrVtbl;
980     This->MessagePumpVtbl= &ThreadMgr_MessagePumpVtbl;
981     This->ClientIdVtbl = &ThreadMgr_ClientIdVtbl;
982     This->ThreadMgrEventSinkVtbl = &ThreadMgr_ThreadMgrEventSinkVtbl;
983     This->refCount = 1;
984     TlsSetValue(tlsIndex,This);
985
986     list_init(&This->CurrentPreservedKeys);
987
988     list_init(&This->ActiveLanguageProfileNotifySink);
989     list_init(&This->DisplayAttributeNotifySink);
990     list_init(&This->KeyTraceEventSink);
991     list_init(&This->PreservedKeyNotifySink);
992     list_init(&This->ThreadFocusSink);
993     list_init(&This->ThreadMgrEventSink);
994
995     TRACE("returning %p\n", This);
996     *ppOut = (IUnknown *)This;
997     return S_OK;
998 }