msctf: Add code to track created ITfDocumentMgrs.
[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 tagDocumentMgrs
69 {
70     struct list     entry;
71     ITfDocumentMgr  *docmgr;
72 } DocumentMgrEntry;
73
74 typedef struct tagACLMulti {
75     const ITfThreadMgrVtbl *ThreadMgrVtbl;
76     const ITfSourceVtbl *SourceVtbl;
77     const ITfKeystrokeMgrVtbl *KeystrokeMgrVtbl;
78     const ITfMessagePumpVtbl *MessagePumpVtbl;
79     const ITfClientIdVtbl *ClientIdVtbl;
80     /* const ITfThreadMgrExVtbl *ThreadMgrExVtbl; */
81     /* const ITfConfigureSystemKeystrokeFeedVtbl *ConfigureSystemKeystrokeFeedVtbl; */
82     /* const ITfLangBarItemMgrVtbl *LangBarItemMgrVtbl; */
83     /* const ITfUIElementMgrVtbl *UIElementMgrVtbl; */
84     /* const ITfSourceSingleVtbl *SourceSingleVtbl; */
85     LONG refCount;
86
87     /* Aggregation */
88     ITfCompartmentMgr  *CompartmentMgr;
89
90     const ITfThreadMgrEventSinkVtbl *ThreadMgrEventSinkVtbl; /* internal */
91
92     ITfDocumentMgr *focus;
93     LONG activationCount;
94
95     ITfKeyEventSink *forgroundKeyEventSink;
96     CLSID forgroundTextService;
97
98     struct list CurrentPreservedKeys;
99     struct list CreatedDocumentMgrs;
100
101     /* kept as separate lists to reduce unnecessary iterations */
102     struct list     ActiveLanguageProfileNotifySink;
103     struct list     DisplayAttributeNotifySink;
104     struct list     KeyTraceEventSink;
105     struct list     PreservedKeyNotifySink;
106     struct list     ThreadFocusSink;
107     struct list     ThreadMgrEventSink;
108 } ThreadMgr;
109
110 static inline ThreadMgr *impl_from_ITfSourceVtbl(ITfSource *iface)
111 {
112     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,SourceVtbl));
113 }
114
115 static inline ThreadMgr *impl_from_ITfKeystrokeMgrVtbl(ITfKeystrokeMgr *iface)
116 {
117     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,KeystrokeMgrVtbl));
118 }
119
120 static inline ThreadMgr *impl_from_ITfMessagePumpVtbl(ITfMessagePump *iface)
121 {
122     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,MessagePumpVtbl));
123 }
124
125 static inline ThreadMgr *impl_from_ITfClientIdVtbl(ITfClientId *iface)
126 {
127     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ClientIdVtbl));
128 }
129
130 static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *iface)
131 {
132     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ThreadMgrEventSinkVtbl));
133 }
134
135 static void free_sink(ThreadMgrSink *sink)
136 {
137         IUnknown_Release(sink->interfaces.pIUnknown);
138         HeapFree(GetProcessHeap(),0,sink);
139 }
140
141 static void ThreadMgr_Destructor(ThreadMgr *This)
142 {
143     struct list *cursor, *cursor2;
144
145     TlsSetValue(tlsIndex,NULL);
146     TRACE("destroying %p\n", This);
147     if (This->focus)
148         ITfDocumentMgr_Release(This->focus);
149
150     /* free sinks */
151     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ActiveLanguageProfileNotifySink)
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->DisplayAttributeNotifySink)
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->KeyTraceEventSink)
164     {
165         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
166         list_remove(cursor);
167         free_sink(sink);
168     }
169     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->PreservedKeyNotifySink)
170     {
171         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
172         list_remove(cursor);
173         free_sink(sink);
174     }
175     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ThreadFocusSink)
176     {
177         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
178         list_remove(cursor);
179         free_sink(sink);
180     }
181     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ThreadMgrEventSink)
182     {
183         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
184         list_remove(cursor);
185         free_sink(sink);
186     }
187
188     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CurrentPreservedKeys)
189     {
190         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
191         list_remove(cursor);
192         HeapFree(GetProcessHeap(),0,key->description);
193         HeapFree(GetProcessHeap(),0,key);
194     }
195
196     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CreatedDocumentMgrs)
197     {
198         DocumentMgrEntry *mgr = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
199         list_remove(cursor);
200         FIXME("Left Over ITfDocumentMgr.  Should we do something with it?\n");
201         HeapFree(GetProcessHeap(),0,mgr);
202     }
203
204     CompartmentMgr_Destructor(This->CompartmentMgr);
205
206     HeapFree(GetProcessHeap(),0,This);
207 }
208
209 static HRESULT WINAPI ThreadMgr_QueryInterface(ITfThreadMgr *iface, REFIID iid, LPVOID *ppvOut)
210 {
211     ThreadMgr *This = (ThreadMgr *)iface;
212     *ppvOut = NULL;
213
214     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgr))
215     {
216         *ppvOut = This;
217     }
218     else if (IsEqualIID(iid, &IID_ITfSource))
219     {
220         *ppvOut = &This->SourceVtbl;
221     }
222     else if (IsEqualIID(iid, &IID_ITfKeystrokeMgr))
223     {
224         *ppvOut = &This->KeystrokeMgrVtbl;
225     }
226     else if (IsEqualIID(iid, &IID_ITfMessagePump))
227     {
228         *ppvOut = &This->MessagePumpVtbl;
229     }
230     else if (IsEqualIID(iid, &IID_ITfClientId))
231     {
232         *ppvOut = &This->ClientIdVtbl;
233     }
234     else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
235     {
236         *ppvOut = This->CompartmentMgr;
237     }
238
239     if (*ppvOut)
240     {
241         IUnknown_AddRef(iface);
242         return S_OK;
243     }
244
245     WARN("unsupported interface: %s\n", debugstr_guid(iid));
246     return E_NOINTERFACE;
247 }
248
249 static ULONG WINAPI ThreadMgr_AddRef(ITfThreadMgr *iface)
250 {
251     ThreadMgr *This = (ThreadMgr *)iface;
252     return InterlockedIncrement(&This->refCount);
253 }
254
255 static ULONG WINAPI ThreadMgr_Release(ITfThreadMgr *iface)
256 {
257     ThreadMgr *This = (ThreadMgr *)iface;
258     ULONG ret;
259
260     ret = InterlockedDecrement(&This->refCount);
261     if (ret == 0)
262         ThreadMgr_Destructor(This);
263     return ret;
264 }
265
266 /*****************************************************
267  * ITfThreadMgr functions
268  *****************************************************/
269
270 static HRESULT WINAPI ThreadMgr_fnActivate( ITfThreadMgr* iface, TfClientId *ptid)
271 {
272     ThreadMgr *This = (ThreadMgr *)iface;
273
274     TRACE("(%p) %p\n",This, ptid);
275
276     if (!ptid)
277         return E_INVALIDARG;
278
279     if (!processId)
280     {
281         GUID guid;
282         CoCreateGuid(&guid);
283         ITfClientId_GetClientId((ITfClientId*)&This->ClientIdVtbl,&guid,&processId);
284     }
285
286     activate_textservices(iface);
287     This->activationCount++;
288     *ptid = processId;
289     return S_OK;
290 }
291
292 static HRESULT WINAPI ThreadMgr_fnDeactivate( ITfThreadMgr* iface)
293 {
294     ThreadMgr *This = (ThreadMgr *)iface;
295     TRACE("(%p)\n",This);
296
297     if (This->activationCount == 0)
298         return E_UNEXPECTED;
299
300     This->activationCount --;
301
302     if (This->activationCount == 0)
303     {
304         if (This->focus)
305         {
306             ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, 0, This->focus);
307             ITfDocumentMgr_Release(This->focus);
308             This->focus = 0;
309         }
310     }
311
312     deactivate_textservices();
313
314     return S_OK;
315 }
316
317 static HRESULT WINAPI ThreadMgr_CreateDocumentMgr( ITfThreadMgr* iface, ITfDocumentMgr
318 **ppdim)
319 {
320     ThreadMgr *This = (ThreadMgr *)iface;
321     DocumentMgrEntry *mgrentry;
322     HRESULT hr;
323
324     TRACE("(%p)\n",iface);
325     mgrentry = HeapAlloc(GetProcessHeap(),0,sizeof(DocumentMgrEntry));
326     if (mgrentry == NULL)
327         return E_OUTOFMEMORY;
328
329     hr = DocumentMgr_Constructor((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, ppdim);
330
331     if (SUCCEEDED(hr))
332     {
333         mgrentry->docmgr = *ppdim;
334         list_add_head(&This->CreatedDocumentMgrs,&mgrentry->entry);
335     }
336     else
337         HeapFree(GetProcessHeap(),0,mgrentry);
338
339     return hr;
340 }
341
342 static HRESULT WINAPI ThreadMgr_EnumDocumentMgrs( ITfThreadMgr* iface, IEnumTfDocumentMgrs
343 **ppEnum)
344 {
345     ThreadMgr *This = (ThreadMgr *)iface;
346     FIXME("STUB:(%p)\n",This);
347     return E_NOTIMPL;
348 }
349
350 static HRESULT WINAPI ThreadMgr_GetFocus( ITfThreadMgr* iface, ITfDocumentMgr
351 **ppdimFocus)
352 {
353     ThreadMgr *This = (ThreadMgr *)iface;
354     TRACE("(%p)\n",This);
355
356     if (!ppdimFocus)
357         return E_INVALIDARG;
358
359     *ppdimFocus = This->focus;
360
361     TRACE("->%p\n",This->focus);
362
363     if (This->focus == NULL)
364         return S_FALSE;
365
366     ITfDocumentMgr_AddRef(This->focus);
367
368     return S_OK;
369 }
370
371 static HRESULT WINAPI ThreadMgr_SetFocus( ITfThreadMgr* iface, ITfDocumentMgr *pdimFocus)
372 {
373     ITfDocumentMgr *check;
374     ThreadMgr *This = (ThreadMgr *)iface;
375
376     TRACE("(%p) %p\n",This,pdimFocus);
377
378     if (!pdimFocus || FAILED(IUnknown_QueryInterface(pdimFocus,&IID_ITfDocumentMgr,(LPVOID*) &check)))
379         return E_INVALIDARG;
380
381     ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, check, This->focus);
382
383     if (This->focus)
384         ITfDocumentMgr_Release(This->focus);
385
386     This->focus = check;
387     return S_OK;
388 }
389
390 static HRESULT WINAPI ThreadMgr_AssociateFocus( ITfThreadMgr* iface, HWND hwnd,
391 ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev)
392 {
393     ThreadMgr *This = (ThreadMgr *)iface;
394     FIXME("STUB:(%p)\n",This);
395     return E_NOTIMPL;
396 }
397
398 static HRESULT WINAPI ThreadMgr_IsThreadFocus( ITfThreadMgr* iface, BOOL *pfThreadFocus)
399 {
400     HWND focus;
401     ThreadMgr *This = (ThreadMgr *)iface;
402     TRACE("(%p) %p\n",This,pfThreadFocus);
403     focus = GetFocus();
404     *pfThreadFocus = (focus == NULL);
405     return S_OK;
406 }
407
408 static HRESULT WINAPI ThreadMgr_GetFunctionProvider( ITfThreadMgr* iface, REFCLSID clsid,
409 ITfFunctionProvider **ppFuncProv)
410 {
411     ThreadMgr *This = (ThreadMgr *)iface;
412     FIXME("STUB:(%p)\n",This);
413     return E_NOTIMPL;
414 }
415
416 static HRESULT WINAPI ThreadMgr_EnumFunctionProviders( ITfThreadMgr* iface,
417 IEnumTfFunctionProviders **ppEnum)
418 {
419     ThreadMgr *This = (ThreadMgr *)iface;
420     FIXME("STUB:(%p)\n",This);
421     return E_NOTIMPL;
422 }
423
424 static HRESULT WINAPI ThreadMgr_GetGlobalCompartment( ITfThreadMgr* iface,
425 ITfCompartmentMgr **ppCompMgr)
426 {
427     ThreadMgr *This = (ThreadMgr *)iface;
428     HRESULT hr;
429     TRACE("(%p) %p\n",This, ppCompMgr);
430
431     if (!ppCompMgr)
432         return E_INVALIDARG;
433
434     if (!globalCompartmentMgr)
435     {
436         hr = CompartmentMgr_Constructor(NULL,&IID_ITfCompartmentMgr,(IUnknown**)&globalCompartmentMgr);
437         if (FAILED(hr))
438             return hr;
439     }
440
441     ITfCompartmentMgr_AddRef(globalCompartmentMgr);
442     *ppCompMgr = globalCompartmentMgr;
443     return S_OK;
444 }
445
446 static const ITfThreadMgrVtbl ThreadMgr_ThreadMgrVtbl =
447 {
448     ThreadMgr_QueryInterface,
449     ThreadMgr_AddRef,
450     ThreadMgr_Release,
451
452     ThreadMgr_fnActivate,
453     ThreadMgr_fnDeactivate,
454     ThreadMgr_CreateDocumentMgr,
455     ThreadMgr_EnumDocumentMgrs,
456     ThreadMgr_GetFocus,
457     ThreadMgr_SetFocus,
458     ThreadMgr_AssociateFocus,
459     ThreadMgr_IsThreadFocus,
460     ThreadMgr_GetFunctionProvider,
461     ThreadMgr_EnumFunctionProviders,
462     ThreadMgr_GetGlobalCompartment
463 };
464
465
466 static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
467 {
468     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
469     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
470 }
471
472 static ULONG WINAPI Source_AddRef(ITfSource *iface)
473 {
474     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
475     return ThreadMgr_AddRef((ITfThreadMgr*)This);
476 }
477
478 static ULONG WINAPI Source_Release(ITfSource *iface)
479 {
480     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
481     return ThreadMgr_Release((ITfThreadMgr *)This);
482 }
483
484 /*****************************************************
485  * ITfSource functions
486  *****************************************************/
487 static WINAPI HRESULT ThreadMgrSource_AdviseSink(ITfSource *iface,
488         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
489 {
490     ThreadMgrSink *tms;
491     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
492
493     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
494
495     if (!riid || !punk || !pdwCookie)
496         return E_INVALIDARG;
497
498     if (IsEqualIID(riid, &IID_ITfThreadMgrEventSink))
499     {
500         tms = HeapAlloc(GetProcessHeap(),0,sizeof(ThreadMgrSink));
501         if (!tms)
502             return E_OUTOFMEMORY;
503         if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&tms->interfaces.pITfThreadMgrEventSink)))
504         {
505             HeapFree(GetProcessHeap(),0,tms);
506             return CONNECT_E_CANNOTCONNECT;
507         }
508         list_add_head(&This->ThreadMgrEventSink,&tms->entry);
509         *pdwCookie = generate_Cookie(COOKIE_MAGIC_TMSINK, tms);
510     }
511     else
512     {
513         FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
514         return E_NOTIMPL;
515     }
516
517     TRACE("cookie %x\n",*pdwCookie);
518
519     return S_OK;
520 }
521
522 static WINAPI HRESULT ThreadMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
523 {
524     ThreadMgrSink *sink;
525     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
526
527     TRACE("(%p) %x\n",This,pdwCookie);
528
529     if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_TMSINK)
530         return E_INVALIDARG;
531
532     sink = (ThreadMgrSink*)remove_Cookie(pdwCookie);
533     if (!sink)
534         return CONNECT_E_NOCONNECTION;
535
536     list_remove(&sink->entry);
537     free_sink(sink);
538
539     return S_OK;
540 }
541
542 static const ITfSourceVtbl ThreadMgr_SourceVtbl =
543 {
544     Source_QueryInterface,
545     Source_AddRef,
546     Source_Release,
547
548     ThreadMgrSource_AdviseSink,
549     ThreadMgrSource_UnadviseSink,
550 };
551
552 /*****************************************************
553  * ITfKeystrokeMgr functions
554  *****************************************************/
555
556 static HRESULT WINAPI KeystrokeMgr_QueryInterface(ITfKeystrokeMgr *iface, REFIID iid, LPVOID *ppvOut)
557 {
558     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
559     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
560 }
561
562 static ULONG WINAPI KeystrokeMgr_AddRef(ITfKeystrokeMgr *iface)
563 {
564     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
565     return ThreadMgr_AddRef((ITfThreadMgr*)This);
566 }
567
568 static ULONG WINAPI KeystrokeMgr_Release(ITfKeystrokeMgr *iface)
569 {
570     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
571     return ThreadMgr_Release((ITfThreadMgr *)This);
572 }
573
574 static HRESULT WINAPI KeystrokeMgr_AdviseKeyEventSink(ITfKeystrokeMgr *iface,
575         TfClientId tid, ITfKeyEventSink *pSink, BOOL fForeground)
576 {
577     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
578     CLSID textservice;
579     ITfKeyEventSink *check = NULL;
580
581     TRACE("(%p) %x %p %i\n",This,tid,pSink,fForeground);
582
583     if (!tid || !pSink)
584         return E_INVALIDARG;
585
586     textservice = get_textservice_clsid(tid);
587     if (IsEqualCLSID(&GUID_NULL,&textservice))
588         return E_INVALIDARG;
589
590     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
591     if (check != NULL)
592         return CONNECT_E_ADVISELIMIT;
593
594     if (FAILED(IUnknown_QueryInterface(pSink,&IID_ITfKeyEventSink,(LPVOID*) &check)))
595         return E_INVALIDARG;
596
597     set_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown*)check);
598
599     if (fForeground)
600     {
601         if (This->forgroundKeyEventSink)
602         {
603             ITfKeyEventSink_OnSetFocus(This->forgroundKeyEventSink, FALSE);
604             ITfKeyEventSink_Release(This->forgroundKeyEventSink);
605         }
606         ITfKeyEventSink_AddRef(check);
607         ITfKeyEventSink_OnSetFocus(check, TRUE);
608         This->forgroundKeyEventSink = check;
609         This->forgroundTextService = textservice;
610     }
611     return S_OK;
612 }
613
614 static HRESULT WINAPI KeystrokeMgr_UnadviseKeyEventSink(ITfKeystrokeMgr *iface,
615         TfClientId tid)
616 {
617     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
618     CLSID textservice;
619     ITfKeyEventSink *check = NULL;
620     TRACE("(%p) %x\n",This,tid);
621
622     if (!tid)
623         return E_INVALIDARG;
624
625     textservice = get_textservice_clsid(tid);
626     if (IsEqualCLSID(&GUID_NULL,&textservice))
627         return E_INVALIDARG;
628
629     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
630
631     if (!check)
632         return CONNECT_E_NOCONNECTION;
633
634     set_textservice_sink(tid, &IID_ITfKeyEventSink, NULL);
635     ITfKeyEventSink_Release(check);
636
637     if (This->forgroundKeyEventSink == check)
638     {
639         ITfKeyEventSink_Release(This->forgroundKeyEventSink);
640         This->forgroundKeyEventSink = NULL;
641         This->forgroundTextService = GUID_NULL;
642     }
643     return S_OK;
644 }
645
646 static HRESULT WINAPI KeystrokeMgr_GetForeground(ITfKeystrokeMgr *iface,
647         CLSID *pclsid)
648 {
649     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
650     TRACE("(%p) %p\n",This,pclsid);
651     if (!pclsid)
652         return E_INVALIDARG;
653
654     if (IsEqualCLSID(&This->forgroundTextService,&GUID_NULL))
655         return S_FALSE;
656
657     *pclsid = This->forgroundTextService;
658     return S_OK;
659 }
660
661 static HRESULT WINAPI KeystrokeMgr_TestKeyDown(ITfKeystrokeMgr *iface,
662         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
663 {
664     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
665     FIXME("STUB:(%p)\n",This);
666     return E_NOTIMPL;
667 }
668
669 static HRESULT WINAPI KeystrokeMgr_TestKeyUp(ITfKeystrokeMgr *iface,
670         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
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_KeyDown(ITfKeystrokeMgr *iface,
678         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
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_KeyUp(ITfKeystrokeMgr *iface,
686         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
687 {
688     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
689     FIXME("STUB:(%p)\n",This);
690     return E_NOTIMPL;
691 }
692
693 static HRESULT WINAPI KeystrokeMgr_GetPreservedKey(ITfKeystrokeMgr *iface,
694         ITfContext *pic, const TF_PRESERVEDKEY *pprekey, GUID *pguid)
695 {
696     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
697     FIXME("STUB:(%p)\n",This);
698     return E_NOTIMPL;
699 }
700
701 static HRESULT WINAPI KeystrokeMgr_IsPreservedKey(ITfKeystrokeMgr *iface,
702         REFGUID rguid, const TF_PRESERVEDKEY *pprekey, BOOL *pfRegistered)
703 {
704     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
705     struct list *cursor;
706
707     TRACE("(%p) %s (%x %x) %p\n",This,debugstr_guid(rguid), (pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0, pfRegistered);
708
709     if (!rguid || !pprekey || !pfRegistered)
710         return E_INVALIDARG;
711
712     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
713     {
714         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
715         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
716         {
717             *pfRegistered = TRUE;
718             return S_OK;
719         }
720     }
721
722     *pfRegistered = FALSE;
723     return S_FALSE;
724 }
725
726 static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface,
727         TfClientId tid, REFGUID rguid, const TF_PRESERVEDKEY *prekey,
728         const WCHAR *pchDesc, ULONG cchDesc)
729 {
730     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
731     struct list *cursor;
732     PreservedKey *newkey;
733
734     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));
735
736     if (!tid || ! rguid || !prekey || (cchDesc && !pchDesc))
737         return E_INVALIDARG;
738
739     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
740     {
741         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
742         if (IsEqualGUID(rguid,&key->guid) && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers)
743             return TF_E_ALREADY_EXISTS;
744     }
745
746     newkey = HeapAlloc(GetProcessHeap(),0,sizeof(PreservedKey));
747     if (!newkey)
748         return E_OUTOFMEMORY;
749
750     newkey->guid  = *rguid;
751     newkey->prekey = *prekey;
752     newkey->tid = tid;
753     if (cchDesc)
754     {
755         newkey->description = HeapAlloc(GetProcessHeap(),0,cchDesc * sizeof(WCHAR));
756         if (!newkey->description)
757         {
758             HeapFree(GetProcessHeap(),0,newkey);
759             return E_OUTOFMEMORY;
760         }
761         memcpy(newkey->description, pchDesc, cchDesc*sizeof(WCHAR));
762     }
763
764     list_add_head(&This->CurrentPreservedKeys,&newkey->entry);
765
766     return S_OK;
767 }
768
769 static HRESULT WINAPI KeystrokeMgr_UnpreserveKey(ITfKeystrokeMgr *iface,
770         REFGUID rguid, const TF_PRESERVEDKEY *pprekey)
771 {
772     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
773     PreservedKey* key = NULL;
774     struct list *cursor;
775     TRACE("(%p) %s (%x %x)\n",This,debugstr_guid(rguid),(pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0);
776
777     if (!pprekey || !rguid)
778         return E_INVALIDARG;
779
780     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
781     {
782         key = LIST_ENTRY(cursor,PreservedKey,entry);
783         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
784             break;
785         key = NULL;
786     }
787
788     if (!key)
789         return CONNECT_E_NOCONNECTION;
790
791     list_remove(&key->entry);
792     HeapFree(GetProcessHeap(),0,key->description);
793     HeapFree(GetProcessHeap(),0,key);
794
795     return S_OK;
796 }
797
798 static HRESULT WINAPI KeystrokeMgr_SetPreservedKeyDescription(ITfKeystrokeMgr *iface,
799         REFGUID rguid, const WCHAR *pchDesc, ULONG cchDesc)
800 {
801     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
802     FIXME("STUB:(%p)\n",This);
803     return E_NOTIMPL;
804 }
805
806 static HRESULT WINAPI KeystrokeMgr_GetPreservedKeyDescription(ITfKeystrokeMgr *iface,
807         REFGUID rguid, BSTR *pbstrDesc)
808 {
809     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
810     FIXME("STUB:(%p)\n",This);
811     return E_NOTIMPL;
812 }
813
814 static HRESULT WINAPI KeystrokeMgr_SimulatePreservedKey(ITfKeystrokeMgr *iface,
815         ITfContext *pic, REFGUID rguid, BOOL *pfEaten)
816 {
817     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
818     FIXME("STUB:(%p)\n",This);
819     return E_NOTIMPL;
820 }
821
822 static const ITfKeystrokeMgrVtbl ThreadMgr_KeystrokeMgrVtbl =
823 {
824     KeystrokeMgr_QueryInterface,
825     KeystrokeMgr_AddRef,
826     KeystrokeMgr_Release,
827
828     KeystrokeMgr_AdviseKeyEventSink,
829     KeystrokeMgr_UnadviseKeyEventSink,
830     KeystrokeMgr_GetForeground,
831     KeystrokeMgr_TestKeyDown,
832     KeystrokeMgr_TestKeyUp,
833     KeystrokeMgr_KeyDown,
834     KeystrokeMgr_KeyUp,
835     KeystrokeMgr_GetPreservedKey,
836     KeystrokeMgr_IsPreservedKey,
837     KeystrokeMgr_PreserveKey,
838     KeystrokeMgr_UnpreserveKey,
839     KeystrokeMgr_SetPreservedKeyDescription,
840     KeystrokeMgr_GetPreservedKeyDescription,
841     KeystrokeMgr_SimulatePreservedKey
842 };
843
844 /*****************************************************
845  * ITfMessagePump functions
846  *****************************************************/
847
848 static HRESULT WINAPI MessagePump_QueryInterface(ITfMessagePump *iface, REFIID iid, LPVOID *ppvOut)
849 {
850     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
851     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
852 }
853
854 static ULONG WINAPI MessagePump_AddRef(ITfMessagePump *iface)
855 {
856     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
857     return ThreadMgr_AddRef((ITfThreadMgr*)This);
858 }
859
860 static ULONG WINAPI MessagePump_Release(ITfMessagePump *iface)
861 {
862     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
863     return ThreadMgr_Release((ITfThreadMgr *)This);
864 }
865
866 static HRESULT WINAPI MessagePump_PeekMessageA(ITfMessagePump *iface,
867         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
868         UINT wRemoveMsg, BOOL *pfResult)
869 {
870     if (!pfResult)
871         return E_INVALIDARG;
872     *pfResult = PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
873     return S_OK;
874 }
875
876 static HRESULT WINAPI MessagePump_GetMessageA(ITfMessagePump *iface,
877         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
878         BOOL *pfResult)
879 {
880     if (!pfResult)
881         return E_INVALIDARG;
882     *pfResult = GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
883     return S_OK;
884 }
885
886 static HRESULT WINAPI MessagePump_PeekMessageW(ITfMessagePump *iface,
887         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
888         UINT wRemoveMsg, BOOL *pfResult)
889 {
890     if (!pfResult)
891         return E_INVALIDARG;
892     *pfResult = PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
893     return S_OK;
894 }
895
896 static HRESULT WINAPI MessagePump_GetMessageW(ITfMessagePump *iface,
897         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
898         BOOL *pfResult)
899 {
900     if (!pfResult)
901         return E_INVALIDARG;
902     *pfResult = GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
903     return S_OK;
904 }
905
906 static const ITfMessagePumpVtbl ThreadMgr_MessagePumpVtbl =
907 {
908     MessagePump_QueryInterface,
909     MessagePump_AddRef,
910     MessagePump_Release,
911
912     MessagePump_PeekMessageA,
913     MessagePump_GetMessageA,
914     MessagePump_PeekMessageW,
915     MessagePump_GetMessageW
916 };
917
918 /*****************************************************
919  * ITfClientId functions
920  *****************************************************/
921
922 static HRESULT WINAPI ClientId_QueryInterface(ITfClientId *iface, REFIID iid, LPVOID *ppvOut)
923 {
924     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
925     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
926 }
927
928 static ULONG WINAPI ClientId_AddRef(ITfClientId *iface)
929 {
930     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
931     return ThreadMgr_AddRef((ITfThreadMgr*)This);
932 }
933
934 static ULONG WINAPI ClientId_Release(ITfClientId *iface)
935 {
936     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
937     return ThreadMgr_Release((ITfThreadMgr *)This);
938 }
939
940 static HRESULT WINAPI ClientId_GetClientId(ITfClientId *iface,
941     REFCLSID rclsid, TfClientId *ptid)
942
943 {
944     HRESULT hr;
945     ITfCategoryMgr *catmgr;
946     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
947
948     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
949
950     CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
951     hr = ITfCategoryMgr_RegisterGUID(catmgr,rclsid,ptid);
952     ITfCategoryMgr_Release(catmgr);
953
954     return hr;
955 }
956
957 static const ITfClientIdVtbl ThreadMgr_ClientIdVtbl =
958 {
959     ClientId_QueryInterface,
960     ClientId_AddRef,
961     ClientId_Release,
962
963     ClientId_GetClientId
964 };
965
966 /*****************************************************
967  * ITfThreadMgrEventSink functions  (internal)
968  *****************************************************/
969 static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut)
970 {
971     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
972     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
973 }
974
975 static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface)
976 {
977     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
978     return ThreadMgr_AddRef((ITfThreadMgr*)This);
979 }
980
981 static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface)
982 {
983     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
984     return ThreadMgr_Release((ITfThreadMgr *)This);
985 }
986
987
988 static WINAPI HRESULT ThreadMgrEventSink_OnInitDocumentMgr(
989         ITfThreadMgrEventSink *iface,ITfDocumentMgr *pdim)
990 {
991     struct list *cursor;
992     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
993
994     TRACE("(%p) %p\n",This,pdim);
995
996     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
997     {
998         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
999         ITfThreadMgrEventSink_OnInitDocumentMgr(sink->interfaces.pITfThreadMgrEventSink,pdim);
1000     }
1001
1002     return S_OK;
1003 }
1004
1005 static WINAPI HRESULT ThreadMgrEventSink_OnUninitDocumentMgr(
1006         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdim)
1007 {
1008     struct list *cursor;
1009     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1010
1011     TRACE("(%p) %p\n",This,pdim);
1012
1013     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
1014     {
1015         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
1016         ITfThreadMgrEventSink_OnUninitDocumentMgr(sink->interfaces.pITfThreadMgrEventSink,pdim);
1017     }
1018
1019     return S_OK;
1020 }
1021
1022 static WINAPI HRESULT ThreadMgrEventSink_OnSetFocus(
1023         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdimFocus,
1024         ITfDocumentMgr *pdimPrevFocus)
1025 {
1026     struct list *cursor;
1027     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1028
1029     TRACE("(%p) %p %p\n",This,pdimFocus, pdimPrevFocus);
1030
1031     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
1032     {
1033         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
1034         ITfThreadMgrEventSink_OnSetFocus(sink->interfaces.pITfThreadMgrEventSink, pdimFocus, pdimPrevFocus);
1035     }
1036
1037     return S_OK;
1038 }
1039
1040 static WINAPI HRESULT ThreadMgrEventSink_OnPushContext(
1041         ITfThreadMgrEventSink *iface, ITfContext *pic)
1042 {
1043     struct list *cursor;
1044     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1045
1046     TRACE("(%p) %p\n",This,pic);
1047
1048     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
1049     {
1050         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
1051         ITfThreadMgrEventSink_OnPushContext(sink->interfaces.pITfThreadMgrEventSink,pic);
1052     }
1053
1054     return S_OK;
1055 }
1056
1057 static WINAPI HRESULT ThreadMgrEventSink_OnPopContext(
1058         ITfThreadMgrEventSink *iface, ITfContext *pic)
1059 {
1060     struct list *cursor;
1061     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1062
1063     TRACE("(%p) %p\n",This,pic);
1064
1065     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
1066     {
1067         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
1068         ITfThreadMgrEventSink_OnPopContext(sink->interfaces.pITfThreadMgrEventSink,pic);
1069     }
1070
1071     return S_OK;
1072 }
1073
1074 static const ITfThreadMgrEventSinkVtbl ThreadMgr_ThreadMgrEventSinkVtbl =
1075 {
1076     ThreadMgrEventSink_QueryInterface,
1077     ThreadMgrEventSink_AddRef,
1078     ThreadMgrEventSink_Release,
1079
1080     ThreadMgrEventSink_OnInitDocumentMgr,
1081     ThreadMgrEventSink_OnUninitDocumentMgr,
1082     ThreadMgrEventSink_OnSetFocus,
1083     ThreadMgrEventSink_OnPushContext,
1084     ThreadMgrEventSink_OnPopContext
1085 };
1086
1087 HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
1088 {
1089     ThreadMgr *This;
1090     if (pUnkOuter)
1091         return CLASS_E_NOAGGREGATION;
1092
1093     /* Only 1 ThreadMgr is created per thread */
1094     This = TlsGetValue(tlsIndex);
1095     if (This)
1096     {
1097         ThreadMgr_AddRef((ITfThreadMgr*)This);
1098         *ppOut = (IUnknown*)This;
1099         return S_OK;
1100     }
1101
1102     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr));
1103     if (This == NULL)
1104         return E_OUTOFMEMORY;
1105
1106     This->ThreadMgrVtbl= &ThreadMgr_ThreadMgrVtbl;
1107     This->SourceVtbl = &ThreadMgr_SourceVtbl;
1108     This->KeystrokeMgrVtbl= &ThreadMgr_KeystrokeMgrVtbl;
1109     This->MessagePumpVtbl= &ThreadMgr_MessagePumpVtbl;
1110     This->ClientIdVtbl = &ThreadMgr_ClientIdVtbl;
1111     This->ThreadMgrEventSinkVtbl = &ThreadMgr_ThreadMgrEventSinkVtbl;
1112     This->refCount = 1;
1113     TlsSetValue(tlsIndex,This);
1114
1115     CompartmentMgr_Constructor((IUnknown*)This, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
1116
1117     list_init(&This->CurrentPreservedKeys);
1118     list_init(&This->CreatedDocumentMgrs);
1119
1120     list_init(&This->ActiveLanguageProfileNotifySink);
1121     list_init(&This->DisplayAttributeNotifySink);
1122     list_init(&This->KeyTraceEventSink);
1123     list_init(&This->PreservedKeyNotifySink);
1124     list_init(&This->ThreadFocusSink);
1125     list_init(&This->ThreadMgrEventSink);
1126
1127     TRACE("returning %p\n", This);
1128     *ppOut = (IUnknown *)This;
1129     return S_OK;
1130 }
1131
1132 void ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *tm, ITfDocumentMgr *mgr)
1133 {
1134     ThreadMgr *This = (ThreadMgr *)tm;
1135     struct list *cursor;
1136     LIST_FOR_EACH(cursor, &This->CreatedDocumentMgrs)
1137     {
1138         DocumentMgrEntry *mgrentry = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
1139         if (mgrentry->docmgr == mgr)
1140         {
1141             list_remove(cursor);
1142             HeapFree(GetProcessHeap(),0,mgrentry);
1143             return;
1144         }
1145     }
1146     FIXME("ITfDocumenMgr %p not found in this thread\n",mgr);
1147 }