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