xref: /reactos/dll/win32/msctf/threadmgr.c (revision 84ccccab)
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 "msctf_internal.h"
22 
23 typedef struct tagPreservedKey
24 {
25     struct list     entry;
26     GUID            guid;
27     TF_PRESERVEDKEY prekey;
28     LPWSTR          description;
29     TfClientId      tid;
30 } PreservedKey;
31 
32 typedef struct tagDocumentMgrs
33 {
34     struct list     entry;
35     ITfDocumentMgr  *docmgr;
36 } DocumentMgrEntry;
37 
38 typedef struct tagAssociatedWindow
39 {
40     struct list     entry;
41     HWND            hwnd;
42     ITfDocumentMgr  *docmgr;
43 } AssociatedWindow;
44 
45 typedef struct tagACLMulti {
46     ITfThreadMgrEx ITfThreadMgrEx_iface;
47     ITfSource ITfSource_iface;
48     ITfKeystrokeMgr ITfKeystrokeMgr_iface;
49     ITfMessagePump ITfMessagePump_iface;
50     ITfClientId ITfClientId_iface;
51     /* const ITfThreadMgrExVtbl *ThreadMgrExVtbl; */
52     /* const ITfConfigureSystemKeystrokeFeedVtbl *ConfigureSystemKeystrokeFeedVtbl; */
53     /* const ITfLangBarItemMgrVtbl *LangBarItemMgrVtbl; */
54     ITfUIElementMgr ITfUIElementMgr_iface;
55     ITfSourceSingle ITfSourceSingle_iface;
56     LONG refCount;
57 
58     /* Aggregation */
59     ITfCompartmentMgr  *CompartmentMgr;
60 
61     ITfThreadMgrEventSink ITfThreadMgrEventSink_iface; /* internal */
62 
63     ITfDocumentMgr *focus;
64     LONG activationCount;
65 
66     ITfKeyEventSink *foregroundKeyEventSink;
67     CLSID foregroundTextService;
68 
69     struct list CurrentPreservedKeys;
70     struct list CreatedDocumentMgrs;
71 
72     struct list AssociatedFocusWindows;
73     HHOOK  focusHook;
74 
75     /* kept as separate lists to reduce unnecessary iterations */
76     struct list     ActiveLanguageProfileNotifySink;
77     struct list     DisplayAttributeNotifySink;
78     struct list     KeyTraceEventSink;
79     struct list     PreservedKeyNotifySink;
80     struct list     ThreadFocusSink;
81     struct list     ThreadMgrEventSink;
82 } ThreadMgr;
83 
84 typedef struct tagEnumTfDocumentMgr {
85     IEnumTfDocumentMgrs IEnumTfDocumentMgrs_iface;
86     LONG refCount;
87 
88     struct list *index;
89     struct list *head;
90 } EnumTfDocumentMgr;
91 
92 static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut);
93 
94 static inline ThreadMgr *impl_from_ITfThreadMgrEx(ITfThreadMgrEx *iface)
95 {
96     return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface);
97 }
98 
99 static inline ThreadMgr *impl_from_ITfSource(ITfSource *iface)
100 {
101     return CONTAINING_RECORD(iface, ThreadMgr, ITfSource_iface);
102 }
103 
104 static inline ThreadMgr *impl_from_ITfKeystrokeMgr(ITfKeystrokeMgr *iface)
105 {
106     return CONTAINING_RECORD(iface, ThreadMgr, ITfKeystrokeMgr_iface);
107 }
108 
109 static inline ThreadMgr *impl_from_ITfMessagePump(ITfMessagePump *iface)
110 {
111     return CONTAINING_RECORD(iface, ThreadMgr, ITfMessagePump_iface);
112 }
113 
114 static inline ThreadMgr *impl_from_ITfClientId(ITfClientId *iface)
115 {
116     return CONTAINING_RECORD(iface, ThreadMgr, ITfClientId_iface);
117 }
118 
119 static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *iface)
120 {
121     return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEventSink_iface);
122 }
123 
124 static inline ThreadMgr *impl_from_ITfUIElementMgr(ITfUIElementMgr *iface)
125 {
126     return CONTAINING_RECORD(iface, ThreadMgr, ITfUIElementMgr_iface);
127 }
128 
129 static inline ThreadMgr *impl_from_ITfSourceSingle(ITfSourceSingle *iface)
130 {
131     return CONTAINING_RECORD(iface, ThreadMgr, ITfSourceSingle_iface);
132 }
133 
134 static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMgrs *iface)
135 {
136     return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface);
137 }
138 
139 static void ThreadMgr_Destructor(ThreadMgr *This)
140 {
141     struct list *cursor, *cursor2;
142 
143     /* unhook right away */
144     if (This->focusHook)
145         UnhookWindowsHookEx(This->focusHook);
146 
147     TlsSetValue(tlsIndex,NULL);
148     TRACE("destroying %p\n", This);
149     if (This->focus)
150         ITfDocumentMgr_Release(This->focus);
151 
152     free_sinks(&This->ActiveLanguageProfileNotifySink);
153     free_sinks(&This->DisplayAttributeNotifySink);
154     free_sinks(&This->KeyTraceEventSink);
155     free_sinks(&This->PreservedKeyNotifySink);
156     free_sinks(&This->ThreadFocusSink);
157     free_sinks(&This->ThreadMgrEventSink);
158 
159     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CurrentPreservedKeys)
160     {
161         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
162         list_remove(cursor);
163         HeapFree(GetProcessHeap(),0,key->description);
164         HeapFree(GetProcessHeap(),0,key);
165     }
166 
167     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CreatedDocumentMgrs)
168     {
169         DocumentMgrEntry *mgr = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
170         list_remove(cursor);
171         FIXME("Left Over ITfDocumentMgr.  Should we do something with it?\n");
172         HeapFree(GetProcessHeap(),0,mgr);
173     }
174 
175     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->AssociatedFocusWindows)
176     {
177         AssociatedWindow *wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
178         list_remove(cursor);
179         HeapFree(GetProcessHeap(),0,wnd);
180     }
181 
182     CompartmentMgr_Destructor(This->CompartmentMgr);
183 
184     HeapFree(GetProcessHeap(),0,This);
185 }
186 
187 static HRESULT WINAPI ThreadMgr_QueryInterface(ITfThreadMgrEx *iface, REFIID iid, LPVOID *ppvOut)
188 {
189     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
190     *ppvOut = NULL;
191 
192     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgr)
193         || IsEqualIID(iid, &IID_ITfThreadMgrEx))
194     {
195         *ppvOut = &This->ITfThreadMgrEx_iface;
196     }
197     else if (IsEqualIID(iid, &IID_ITfSource))
198     {
199         *ppvOut = &This->ITfSource_iface;
200     }
201     else if (IsEqualIID(iid, &IID_ITfKeystrokeMgr))
202     {
203         *ppvOut = &This->ITfKeystrokeMgr_iface;
204     }
205     else if (IsEqualIID(iid, &IID_ITfMessagePump))
206     {
207         *ppvOut = &This->ITfMessagePump_iface;
208     }
209     else if (IsEqualIID(iid, &IID_ITfClientId))
210     {
211         *ppvOut = &This->ITfClientId_iface;
212     }
213     else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
214     {
215         *ppvOut = This->CompartmentMgr;
216     }
217     else if (IsEqualIID(iid, &IID_ITfUIElementMgr))
218     {
219         *ppvOut = &This->ITfUIElementMgr_iface;
220     }
221     else if (IsEqualIID(iid, &IID_ITfSourceSingle))
222     {
223         *ppvOut = &This->ITfSourceSingle_iface;
224     }
225 
226     if (*ppvOut)
227     {
228         ITfThreadMgrEx_AddRef(iface);
229         return S_OK;
230     }
231 
232     WARN("unsupported interface: %s\n", debugstr_guid(iid));
233     return E_NOINTERFACE;
234 }
235 
236 static ULONG WINAPI ThreadMgr_AddRef(ITfThreadMgrEx *iface)
237 {
238     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
239     return InterlockedIncrement(&This->refCount);
240 }
241 
242 static ULONG WINAPI ThreadMgr_Release(ITfThreadMgrEx *iface)
243 {
244     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
245     ULONG ret;
246 
247     ret = InterlockedDecrement(&This->refCount);
248     if (ret == 0)
249         ThreadMgr_Destructor(This);
250     return ret;
251 }
252 
253 /*****************************************************
254  * ITfThreadMgr functions
255  *****************************************************/
256 
257 static HRESULT WINAPI ThreadMgr_Activate(ITfThreadMgrEx *iface, TfClientId *id)
258 {
259     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
260 
261     TRACE("(%p) %p\n", This, id);
262     return ITfThreadMgrEx_ActivateEx(iface, id, 0);
263 }
264 
265 static HRESULT WINAPI ThreadMgr_Deactivate(ITfThreadMgrEx *iface)
266 {
267     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
268     TRACE("(%p)\n",This);
269 
270     if (This->activationCount == 0)
271         return E_UNEXPECTED;
272 
273     This->activationCount --;
274 
275     if (This->activationCount == 0)
276     {
277         if (This->focus)
278         {
279             ITfThreadMgrEventSink_OnSetFocus(&This->ITfThreadMgrEventSink_iface, 0, This->focus);
280             ITfDocumentMgr_Release(This->focus);
281             This->focus = 0;
282         }
283     }
284 
285     deactivate_textservices();
286 
287     return S_OK;
288 }
289 
290 static HRESULT WINAPI ThreadMgr_CreateDocumentMgr(ITfThreadMgrEx *iface, ITfDocumentMgr **ppdim)
291 {
292     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
293     DocumentMgrEntry *mgrentry;
294     HRESULT hr;
295 
296     TRACE("(%p)\n",iface);
297     mgrentry = HeapAlloc(GetProcessHeap(),0,sizeof(DocumentMgrEntry));
298     if (mgrentry == NULL)
299         return E_OUTOFMEMORY;
300 
301     hr = DocumentMgr_Constructor(&This->ITfThreadMgrEventSink_iface, ppdim);
302 
303     if (SUCCEEDED(hr))
304     {
305         mgrentry->docmgr = *ppdim;
306         list_add_head(&This->CreatedDocumentMgrs,&mgrentry->entry);
307     }
308     else
309         HeapFree(GetProcessHeap(),0,mgrentry);
310 
311     return hr;
312 }
313 
314 static HRESULT WINAPI ThreadMgr_EnumDocumentMgrs(ITfThreadMgrEx *iface, IEnumTfDocumentMgrs **ppEnum)
315 {
316     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
317     TRACE("(%p) %p\n",This,ppEnum);
318 
319     if (!ppEnum)
320         return E_INVALIDARG;
321 
322     return EnumTfDocumentMgr_Constructor(&This->CreatedDocumentMgrs, ppEnum);
323 }
324 
325 static HRESULT WINAPI ThreadMgr_GetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr **ppdimFocus)
326 {
327     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
328     TRACE("(%p)\n",This);
329 
330     if (!ppdimFocus)
331         return E_INVALIDARG;
332 
333     *ppdimFocus = This->focus;
334 
335     TRACE("->%p\n",This->focus);
336 
337     if (This->focus == NULL)
338         return S_FALSE;
339 
340     ITfDocumentMgr_AddRef(This->focus);
341 
342     return S_OK;
343 }
344 
345 static HRESULT WINAPI ThreadMgr_SetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr *pdimFocus)
346 {
347     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
348     ITfDocumentMgr *check;
349 
350     TRACE("(%p) %p\n",This,pdimFocus);
351 
352     if (!pdimFocus)
353         check = NULL;
354     else if (FAILED(ITfDocumentMgr_QueryInterface(pdimFocus,&IID_ITfDocumentMgr,(LPVOID*) &check)))
355         return E_INVALIDARG;
356 
357     ITfThreadMgrEventSink_OnSetFocus(&This->ITfThreadMgrEventSink_iface, check, This->focus);
358 
359     if (This->focus)
360         ITfDocumentMgr_Release(This->focus);
361 
362     This->focus = check;
363     return S_OK;
364 }
365 
366 static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam)
367 {
368     ThreadMgr *This;
369 
370     This = TlsGetValue(tlsIndex);
371     if (!This)
372     {
373         ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n");
374         return 0;
375     }
376     if (!This->focusHook)
377     {
378         ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n");
379         return 0;
380     }
381 
382     if (nCode == HCBT_SETFOCUS) /* focus change within our thread */
383     {
384         struct list *cursor;
385 
386         LIST_FOR_EACH(cursor, &This->AssociatedFocusWindows)
387         {
388             AssociatedWindow *wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
389             if (wnd->hwnd == (HWND)wParam)
390             {
391                 TRACE("Triggering Associated window focus\n");
392                 if (This->focus != wnd->docmgr)
393                     ThreadMgr_SetFocus(&This->ITfThreadMgrEx_iface, wnd->docmgr);
394                 break;
395             }
396         }
397     }
398 
399     return CallNextHookEx(This->focusHook, nCode, wParam, lParam);
400 }
401 
402 static HRESULT SetupWindowsHook(ThreadMgr *This)
403 {
404     if (!This->focusHook)
405     {
406         This->focusHook = SetWindowsHookExW(WH_CBT, ThreadFocusHookProc, 0,
407                              GetCurrentThreadId());
408         if (!This->focusHook)
409         {
410             ERR("Unable to set focus hook\n");
411             return E_FAIL;
412         }
413         return S_OK;
414     }
415     return S_FALSE;
416 }
417 
418 static HRESULT WINAPI ThreadMgr_AssociateFocus(ITfThreadMgrEx *iface, HWND hwnd,
419 ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev)
420 {
421     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
422     struct list *cursor, *cursor2;
423     AssociatedWindow *wnd;
424 
425     TRACE("(%p) %p %p %p\n",This,hwnd,pdimNew,ppdimPrev);
426 
427     if (!ppdimPrev)
428         return E_INVALIDARG;
429 
430     *ppdimPrev = NULL;
431 
432     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->AssociatedFocusWindows)
433     {
434         wnd = LIST_ENTRY(cursor,AssociatedWindow,entry);
435         if (wnd->hwnd == hwnd)
436         {
437             if (wnd->docmgr)
438                 ITfDocumentMgr_AddRef(wnd->docmgr);
439             *ppdimPrev = wnd->docmgr;
440             wnd->docmgr = pdimNew;
441             if (GetFocus() == hwnd)
442                 ThreadMgr_SetFocus(iface,pdimNew);
443             return S_OK;
444         }
445     }
446 
447     wnd = HeapAlloc(GetProcessHeap(),0,sizeof(AssociatedWindow));
448     wnd->hwnd = hwnd;
449     wnd->docmgr = pdimNew;
450     list_add_head(&This->AssociatedFocusWindows,&wnd->entry);
451 
452     if (GetFocus() == hwnd)
453         ThreadMgr_SetFocus(iface,pdimNew);
454 
455     SetupWindowsHook(This);
456 
457     return S_OK;
458 }
459 
460 static HRESULT WINAPI ThreadMgr_IsThreadFocus(ITfThreadMgrEx *iface, BOOL *pfThreadFocus)
461 {
462     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
463     HWND focus;
464 
465     TRACE("(%p) %p\n",This,pfThreadFocus);
466     focus = GetFocus();
467     *pfThreadFocus = (focus == NULL);
468     return S_OK;
469 }
470 
471 static HRESULT WINAPI ThreadMgr_GetFunctionProvider(ITfThreadMgrEx *iface, REFCLSID clsid,
472 ITfFunctionProvider **ppFuncProv)
473 {
474     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
475     FIXME("STUB:(%p)\n",This);
476     return E_NOTIMPL;
477 }
478 
479 static HRESULT WINAPI ThreadMgr_EnumFunctionProviders(ITfThreadMgrEx *iface,
480 IEnumTfFunctionProviders **ppEnum)
481 {
482     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
483     FIXME("STUB:(%p)\n",This);
484     return E_NOTIMPL;
485 }
486 
487 static HRESULT WINAPI ThreadMgr_GetGlobalCompartment(ITfThreadMgrEx *iface,
488 ITfCompartmentMgr **ppCompMgr)
489 {
490     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
491     HRESULT hr;
492     TRACE("(%p) %p\n",This, ppCompMgr);
493 
494     if (!ppCompMgr)
495         return E_INVALIDARG;
496 
497     if (!globalCompartmentMgr)
498     {
499         hr = CompartmentMgr_Constructor(NULL,&IID_ITfCompartmentMgr,(IUnknown**)&globalCompartmentMgr);
500         if (FAILED(hr))
501             return hr;
502     }
503 
504     ITfCompartmentMgr_AddRef(globalCompartmentMgr);
505     *ppCompMgr = globalCompartmentMgr;
506     return S_OK;
507 }
508 
509 static HRESULT WINAPI ThreadMgr_ActivateEx(ITfThreadMgrEx *iface, TfClientId *id, DWORD flags)
510 {
511     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
512 
513     TRACE("(%p) %p, %#x\n", This, id, flags);
514 
515     if (!id)
516         return E_INVALIDARG;
517 
518     if (flags)
519         FIXME("Unimplemented flags %#x\n", flags);
520 
521     if (!processId)
522     {
523         GUID guid;
524         CoCreateGuid(&guid);
525         ITfClientId_GetClientId(&This->ITfClientId_iface, &guid, &processId);
526     }
527 
528     activate_textservices(iface);
529     This->activationCount++;
530     *id = processId;
531     return S_OK;
532 }
533 
534 static HRESULT WINAPI ThreadMgr_GetActiveFlags(ITfThreadMgrEx *iface, DWORD *flags)
535 {
536     ThreadMgr *This = impl_from_ITfThreadMgrEx(iface);
537 
538     FIXME("STUB:(%p)\n", This);
539     return E_NOTIMPL;
540 }
541 
542 static const ITfThreadMgrExVtbl ThreadMgrExVtbl =
543 {
544     ThreadMgr_QueryInterface,
545     ThreadMgr_AddRef,
546     ThreadMgr_Release,
547     ThreadMgr_Activate,
548     ThreadMgr_Deactivate,
549     ThreadMgr_CreateDocumentMgr,
550     ThreadMgr_EnumDocumentMgrs,
551     ThreadMgr_GetFocus,
552     ThreadMgr_SetFocus,
553     ThreadMgr_AssociateFocus,
554     ThreadMgr_IsThreadFocus,
555     ThreadMgr_GetFunctionProvider,
556     ThreadMgr_EnumFunctionProviders,
557     ThreadMgr_GetGlobalCompartment,
558 
559     ThreadMgr_ActivateEx,
560     ThreadMgr_GetActiveFlags
561 };
562 
563 static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
564 {
565     ThreadMgr *This = impl_from_ITfSource(iface);
566     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
567 }
568 
569 static ULONG WINAPI Source_AddRef(ITfSource *iface)
570 {
571     ThreadMgr *This = impl_from_ITfSource(iface);
572     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
573 }
574 
575 static ULONG WINAPI Source_Release(ITfSource *iface)
576 {
577     ThreadMgr *This = impl_from_ITfSource(iface);
578     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
579 }
580 
581 /*****************************************************
582  * ITfSource functions
583  *****************************************************/
584 static HRESULT WINAPI ThreadMgrSource_AdviseSink(ITfSource *iface,
585         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
586 {
587     ThreadMgr *This = impl_from_ITfSource(iface);
588 
589     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
590 
591     if (!riid || !punk || !pdwCookie)
592         return E_INVALIDARG;
593 
594     if (IsEqualIID(riid, &IID_ITfThreadMgrEventSink))
595         return advise_sink(&This->ThreadMgrEventSink, &IID_ITfThreadMgrEventSink, COOKIE_MAGIC_TMSINK, punk, pdwCookie);
596 
597     if (IsEqualIID(riid, &IID_ITfThreadFocusSink))
598     {
599         WARN("semi-stub for ITfThreadFocusSink: sink won't be used.\n");
600         return advise_sink(&This->ThreadFocusSink, &IID_ITfThreadFocusSink, COOKIE_MAGIC_THREADFOCUSSINK, punk, pdwCookie);
601     }
602 
603     FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
604     return E_NOTIMPL;
605 }
606 
607 static HRESULT WINAPI ThreadMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
608 {
609     ThreadMgr *This = impl_from_ITfSource(iface);
610 
611     TRACE("(%p) %x\n",This,pdwCookie);
612 
613     if (get_Cookie_magic(pdwCookie) != COOKIE_MAGIC_TMSINK && get_Cookie_magic(pdwCookie) != COOKIE_MAGIC_THREADFOCUSSINK)
614         return E_INVALIDARG;
615 
616     return unadvise_sink(pdwCookie);
617 }
618 
619 static const ITfSourceVtbl ThreadMgrSourceVtbl =
620 {
621     Source_QueryInterface,
622     Source_AddRef,
623     Source_Release,
624     ThreadMgrSource_AdviseSink,
625     ThreadMgrSource_UnadviseSink,
626 };
627 
628 /*****************************************************
629  * ITfKeystrokeMgr functions
630  *****************************************************/
631 
632 static HRESULT WINAPI KeystrokeMgr_QueryInterface(ITfKeystrokeMgr *iface, REFIID iid, LPVOID *ppvOut)
633 {
634     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
635     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
636 }
637 
638 static ULONG WINAPI KeystrokeMgr_AddRef(ITfKeystrokeMgr *iface)
639 {
640     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
641     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
642 }
643 
644 static ULONG WINAPI KeystrokeMgr_Release(ITfKeystrokeMgr *iface)
645 {
646     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
647     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
648 }
649 
650 static HRESULT WINAPI KeystrokeMgr_AdviseKeyEventSink(ITfKeystrokeMgr *iface,
651         TfClientId tid, ITfKeyEventSink *pSink, BOOL fForeground)
652 {
653     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
654     CLSID textservice;
655     ITfKeyEventSink *check = NULL;
656 
657     TRACE("(%p) %x %p %i\n",This,tid,pSink,fForeground);
658 
659     if (!tid || !pSink)
660         return E_INVALIDARG;
661 
662     textservice = get_textservice_clsid(tid);
663     if (IsEqualCLSID(&GUID_NULL,&textservice))
664         return E_INVALIDARG;
665 
666     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
667     if (check != NULL)
668         return CONNECT_E_ADVISELIMIT;
669 
670     if (FAILED(ITfKeyEventSink_QueryInterface(pSink,&IID_ITfKeyEventSink,(LPVOID*) &check)))
671         return E_INVALIDARG;
672 
673     set_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown*)check);
674 
675     if (fForeground)
676     {
677         if (This->foregroundKeyEventSink)
678         {
679             ITfKeyEventSink_OnSetFocus(This->foregroundKeyEventSink, FALSE);
680             ITfKeyEventSink_Release(This->foregroundKeyEventSink);
681         }
682         ITfKeyEventSink_AddRef(check);
683         ITfKeyEventSink_OnSetFocus(check, TRUE);
684         This->foregroundKeyEventSink = check;
685         This->foregroundTextService = textservice;
686     }
687     return S_OK;
688 }
689 
690 static HRESULT WINAPI KeystrokeMgr_UnadviseKeyEventSink(ITfKeystrokeMgr *iface,
691         TfClientId tid)
692 {
693     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
694     CLSID textservice;
695     ITfKeyEventSink *check = NULL;
696     TRACE("(%p) %x\n",This,tid);
697 
698     if (!tid)
699         return E_INVALIDARG;
700 
701     textservice = get_textservice_clsid(tid);
702     if (IsEqualCLSID(&GUID_NULL,&textservice))
703         return E_INVALIDARG;
704 
705     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
706 
707     if (!check)
708         return CONNECT_E_NOCONNECTION;
709 
710     set_textservice_sink(tid, &IID_ITfKeyEventSink, NULL);
711     ITfKeyEventSink_Release(check);
712 
713     if (This->foregroundKeyEventSink == check)
714     {
715         ITfKeyEventSink_Release(This->foregroundKeyEventSink);
716         This->foregroundKeyEventSink = NULL;
717         This->foregroundTextService = GUID_NULL;
718     }
719     return S_OK;
720 }
721 
722 static HRESULT WINAPI KeystrokeMgr_GetForeground(ITfKeystrokeMgr *iface,
723         CLSID *pclsid)
724 {
725     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
726     TRACE("(%p) %p\n",This,pclsid);
727     if (!pclsid)
728         return E_INVALIDARG;
729 
730     if (IsEqualCLSID(&This->foregroundTextService,&GUID_NULL))
731         return S_FALSE;
732 
733     *pclsid = This->foregroundTextService;
734     return S_OK;
735 }
736 
737 static HRESULT WINAPI KeystrokeMgr_TestKeyDown(ITfKeystrokeMgr *iface,
738         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
739 {
740     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
741     FIXME("STUB:(%p)\n",This);
742     *pfEaten = FALSE;
743     return S_OK;
744 }
745 
746 static HRESULT WINAPI KeystrokeMgr_TestKeyUp(ITfKeystrokeMgr *iface,
747         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
748 {
749     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
750     FIXME("STUB:(%p)\n",This);
751     *pfEaten = FALSE;
752     return S_OK;
753 }
754 
755 static HRESULT WINAPI KeystrokeMgr_KeyDown(ITfKeystrokeMgr *iface,
756         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
757 {
758     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
759     FIXME("STUB:(%p)\n",This);
760     return E_NOTIMPL;
761 }
762 
763 static HRESULT WINAPI KeystrokeMgr_KeyUp(ITfKeystrokeMgr *iface,
764         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
765 {
766     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
767     FIXME("STUB:(%p)\n",This);
768     return E_NOTIMPL;
769 }
770 
771 static HRESULT WINAPI KeystrokeMgr_GetPreservedKey(ITfKeystrokeMgr *iface,
772         ITfContext *pic, const TF_PRESERVEDKEY *pprekey, GUID *pguid)
773 {
774     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
775     FIXME("STUB:(%p)\n",This);
776     return E_NOTIMPL;
777 }
778 
779 static HRESULT WINAPI KeystrokeMgr_IsPreservedKey(ITfKeystrokeMgr *iface,
780         REFGUID rguid, const TF_PRESERVEDKEY *pprekey, BOOL *pfRegistered)
781 {
782     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
783     struct list *cursor;
784 
785     TRACE("(%p) %s (%x %x) %p\n",This,debugstr_guid(rguid), (pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0, pfRegistered);
786 
787     if (!rguid || !pprekey || !pfRegistered)
788         return E_INVALIDARG;
789 
790     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
791     {
792         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
793         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
794         {
795             *pfRegistered = TRUE;
796             return S_OK;
797         }
798     }
799 
800     *pfRegistered = FALSE;
801     return S_FALSE;
802 }
803 
804 static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface,
805         TfClientId tid, REFGUID rguid, const TF_PRESERVEDKEY *prekey,
806         const WCHAR *pchDesc, ULONG cchDesc)
807 {
808     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
809     struct list *cursor;
810     PreservedKey *newkey;
811 
812     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));
813 
814     if (!tid || ! rguid || !prekey || (cchDesc && !pchDesc))
815         return E_INVALIDARG;
816 
817     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
818     {
819         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
820         if (IsEqualGUID(rguid,&key->guid) && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers)
821             return TF_E_ALREADY_EXISTS;
822     }
823 
824     newkey = HeapAlloc(GetProcessHeap(),0,sizeof(PreservedKey));
825     if (!newkey)
826         return E_OUTOFMEMORY;
827 
828     newkey->guid  = *rguid;
829     newkey->prekey = *prekey;
830     newkey->tid = tid;
831     newkey->description = NULL;
832     if (cchDesc)
833     {
834         newkey->description = HeapAlloc(GetProcessHeap(),0,cchDesc * sizeof(WCHAR));
835         if (!newkey->description)
836         {
837             HeapFree(GetProcessHeap(),0,newkey);
838             return E_OUTOFMEMORY;
839         }
840         memcpy(newkey->description, pchDesc, cchDesc*sizeof(WCHAR));
841     }
842 
843     list_add_head(&This->CurrentPreservedKeys,&newkey->entry);
844 
845     return S_OK;
846 }
847 
848 static HRESULT WINAPI KeystrokeMgr_UnpreserveKey(ITfKeystrokeMgr *iface,
849         REFGUID rguid, const TF_PRESERVEDKEY *pprekey)
850 {
851     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
852     PreservedKey* key = NULL;
853     struct list *cursor;
854     TRACE("(%p) %s (%x %x)\n",This,debugstr_guid(rguid),(pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0);
855 
856     if (!pprekey || !rguid)
857         return E_INVALIDARG;
858 
859     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
860     {
861         key = LIST_ENTRY(cursor,PreservedKey,entry);
862         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
863             break;
864         key = NULL;
865     }
866 
867     if (!key)
868         return CONNECT_E_NOCONNECTION;
869 
870     list_remove(&key->entry);
871     HeapFree(GetProcessHeap(),0,key->description);
872     HeapFree(GetProcessHeap(),0,key);
873 
874     return S_OK;
875 }
876 
877 static HRESULT WINAPI KeystrokeMgr_SetPreservedKeyDescription(ITfKeystrokeMgr *iface,
878         REFGUID rguid, const WCHAR *pchDesc, ULONG cchDesc)
879 {
880     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
881     FIXME("STUB:(%p)\n",This);
882     return E_NOTIMPL;
883 }
884 
885 static HRESULT WINAPI KeystrokeMgr_GetPreservedKeyDescription(ITfKeystrokeMgr *iface,
886         REFGUID rguid, BSTR *pbstrDesc)
887 {
888     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
889     FIXME("STUB:(%p)\n",This);
890     return E_NOTIMPL;
891 }
892 
893 static HRESULT WINAPI KeystrokeMgr_SimulatePreservedKey(ITfKeystrokeMgr *iface,
894         ITfContext *pic, REFGUID rguid, BOOL *pfEaten)
895 {
896     ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface);
897     FIXME("STUB:(%p)\n",This);
898     return E_NOTIMPL;
899 }
900 
901 static const ITfKeystrokeMgrVtbl KeystrokeMgrVtbl =
902 {
903     KeystrokeMgr_QueryInterface,
904     KeystrokeMgr_AddRef,
905     KeystrokeMgr_Release,
906     KeystrokeMgr_AdviseKeyEventSink,
907     KeystrokeMgr_UnadviseKeyEventSink,
908     KeystrokeMgr_GetForeground,
909     KeystrokeMgr_TestKeyDown,
910     KeystrokeMgr_TestKeyUp,
911     KeystrokeMgr_KeyDown,
912     KeystrokeMgr_KeyUp,
913     KeystrokeMgr_GetPreservedKey,
914     KeystrokeMgr_IsPreservedKey,
915     KeystrokeMgr_PreserveKey,
916     KeystrokeMgr_UnpreserveKey,
917     KeystrokeMgr_SetPreservedKeyDescription,
918     KeystrokeMgr_GetPreservedKeyDescription,
919     KeystrokeMgr_SimulatePreservedKey
920 };
921 
922 /*****************************************************
923  * ITfMessagePump functions
924  *****************************************************/
925 
926 static HRESULT WINAPI MessagePump_QueryInterface(ITfMessagePump *iface, REFIID iid, LPVOID *ppvOut)
927 {
928     ThreadMgr *This = impl_from_ITfMessagePump(iface);
929     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
930 }
931 
932 static ULONG WINAPI MessagePump_AddRef(ITfMessagePump *iface)
933 {
934     ThreadMgr *This = impl_from_ITfMessagePump(iface);
935     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
936 }
937 
938 static ULONG WINAPI MessagePump_Release(ITfMessagePump *iface)
939 {
940     ThreadMgr *This = impl_from_ITfMessagePump(iface);
941     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
942 }
943 
944 static HRESULT WINAPI MessagePump_PeekMessageA(ITfMessagePump *iface,
945         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
946         UINT wRemoveMsg, BOOL *pfResult)
947 {
948     if (!pfResult)
949         return E_INVALIDARG;
950     *pfResult = PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
951     return S_OK;
952 }
953 
954 static HRESULT WINAPI MessagePump_GetMessageA(ITfMessagePump *iface,
955         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
956         BOOL *pfResult)
957 {
958     if (!pfResult)
959         return E_INVALIDARG;
960     *pfResult = GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
961     return S_OK;
962 }
963 
964 static HRESULT WINAPI MessagePump_PeekMessageW(ITfMessagePump *iface,
965         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
966         UINT wRemoveMsg, BOOL *pfResult)
967 {
968     if (!pfResult)
969         return E_INVALIDARG;
970     *pfResult = PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
971     return S_OK;
972 }
973 
974 static HRESULT WINAPI MessagePump_GetMessageW(ITfMessagePump *iface,
975         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
976         BOOL *pfResult)
977 {
978     if (!pfResult)
979         return E_INVALIDARG;
980     *pfResult = GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
981     return S_OK;
982 }
983 
984 static const ITfMessagePumpVtbl MessagePumpVtbl =
985 {
986     MessagePump_QueryInterface,
987     MessagePump_AddRef,
988     MessagePump_Release,
989     MessagePump_PeekMessageA,
990     MessagePump_GetMessageA,
991     MessagePump_PeekMessageW,
992     MessagePump_GetMessageW
993 };
994 
995 /*****************************************************
996  * ITfClientId functions
997  *****************************************************/
998 
999 static HRESULT WINAPI ClientId_QueryInterface(ITfClientId *iface, REFIID iid, LPVOID *ppvOut)
1000 {
1001     ThreadMgr *This = impl_from_ITfClientId(iface);
1002     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1003 }
1004 
1005 static ULONG WINAPI ClientId_AddRef(ITfClientId *iface)
1006 {
1007     ThreadMgr *This = impl_from_ITfClientId(iface);
1008     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1009 }
1010 
1011 static ULONG WINAPI ClientId_Release(ITfClientId *iface)
1012 {
1013     ThreadMgr *This = impl_from_ITfClientId(iface);
1014     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1015 }
1016 
1017 static HRESULT WINAPI ClientId_GetClientId(ITfClientId *iface,
1018     REFCLSID rclsid, TfClientId *ptid)
1019 
1020 {
1021     ThreadMgr *This = impl_from_ITfClientId(iface);
1022     HRESULT hr;
1023     ITfCategoryMgr *catmgr;
1024 
1025     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
1026 
1027     CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
1028     hr = ITfCategoryMgr_RegisterGUID(catmgr,rclsid,ptid);
1029     ITfCategoryMgr_Release(catmgr);
1030 
1031     return hr;
1032 }
1033 
1034 static const ITfClientIdVtbl ClientIdVtbl =
1035 {
1036     ClientId_QueryInterface,
1037     ClientId_AddRef,
1038     ClientId_Release,
1039     ClientId_GetClientId
1040 };
1041 
1042 /*****************************************************
1043  * ITfThreadMgrEventSink functions  (internal)
1044  *****************************************************/
1045 static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut)
1046 {
1047     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1048     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1049 }
1050 
1051 static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface)
1052 {
1053     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1054     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1055 }
1056 
1057 static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface)
1058 {
1059     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1060     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1061 }
1062 
1063 
1064 static HRESULT WINAPI ThreadMgrEventSink_OnInitDocumentMgr(
1065         ITfThreadMgrEventSink *iface,ITfDocumentMgr *pdim)
1066 {
1067     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1068     ITfThreadMgrEventSink *sink;
1069     struct list *cursor;
1070 
1071     TRACE("(%p) %p\n",This,pdim);
1072 
1073     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1074     {
1075         ITfThreadMgrEventSink_OnInitDocumentMgr(sink, pdim);
1076     }
1077 
1078     return S_OK;
1079 }
1080 
1081 static HRESULT WINAPI ThreadMgrEventSink_OnUninitDocumentMgr(
1082         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdim)
1083 {
1084     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1085     ITfThreadMgrEventSink *sink;
1086     struct list *cursor;
1087 
1088     TRACE("(%p) %p\n",This,pdim);
1089 
1090     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1091     {
1092         ITfThreadMgrEventSink_OnUninitDocumentMgr(sink, pdim);
1093     }
1094 
1095     return S_OK;
1096 }
1097 
1098 static HRESULT WINAPI ThreadMgrEventSink_OnSetFocus(
1099         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdimFocus,
1100         ITfDocumentMgr *pdimPrevFocus)
1101 {
1102     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1103     ITfThreadMgrEventSink *sink;
1104     struct list *cursor;
1105 
1106     TRACE("(%p) %p %p\n",This,pdimFocus, pdimPrevFocus);
1107 
1108     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1109     {
1110         ITfThreadMgrEventSink_OnSetFocus(sink, pdimFocus, pdimPrevFocus);
1111     }
1112 
1113     return S_OK;
1114 }
1115 
1116 static HRESULT WINAPI ThreadMgrEventSink_OnPushContext(
1117         ITfThreadMgrEventSink *iface, ITfContext *pic)
1118 {
1119     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1120     ITfThreadMgrEventSink *sink;
1121     struct list *cursor;
1122 
1123     TRACE("(%p) %p\n",This,pic);
1124 
1125     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1126     {
1127         ITfThreadMgrEventSink_OnPushContext(sink, pic);
1128     }
1129 
1130     return S_OK;
1131 }
1132 
1133 static HRESULT WINAPI ThreadMgrEventSink_OnPopContext(
1134         ITfThreadMgrEventSink *iface, ITfContext *pic)
1135 {
1136     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
1137     ITfThreadMgrEventSink *sink;
1138     struct list *cursor;
1139 
1140     TRACE("(%p) %p\n",This,pic);
1141 
1142     SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink)
1143     {
1144         ITfThreadMgrEventSink_OnPopContext(sink, pic);
1145     }
1146 
1147     return S_OK;
1148 }
1149 
1150 static const ITfThreadMgrEventSinkVtbl ThreadMgrEventSinkVtbl =
1151 {
1152     ThreadMgrEventSink_QueryInterface,
1153     ThreadMgrEventSink_AddRef,
1154     ThreadMgrEventSink_Release,
1155     ThreadMgrEventSink_OnInitDocumentMgr,
1156     ThreadMgrEventSink_OnUninitDocumentMgr,
1157     ThreadMgrEventSink_OnSetFocus,
1158     ThreadMgrEventSink_OnPushContext,
1159     ThreadMgrEventSink_OnPopContext
1160 };
1161 
1162 /*****************************************************
1163  * ITfUIElementMgr functions
1164  *****************************************************/
1165 static HRESULT WINAPI UIElementMgr_QueryInterface(ITfUIElementMgr *iface, REFIID iid, void **ppvOut)
1166 {
1167     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1168 
1169     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1170 }
1171 
1172 static ULONG WINAPI UIElementMgr_AddRef(ITfUIElementMgr *iface)
1173 {
1174     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1175 
1176     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1177 }
1178 
1179 static ULONG WINAPI UIElementMgr_Release(ITfUIElementMgr *iface)
1180 {
1181     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1182 
1183     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1184 }
1185 
1186 static HRESULT WINAPI UIElementMgr_BeginUIElement(ITfUIElementMgr *iface, ITfUIElement *element,
1187                                                   BOOL *show, DWORD *id)
1188 {
1189     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1190 
1191     FIXME("STUB:(%p)\n", This);
1192     return E_NOTIMPL;
1193 }
1194 
1195 static HRESULT WINAPI UIElementMgr_UpdateUIElement(ITfUIElementMgr *iface, DWORD id)
1196 {
1197     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1198 
1199     FIXME("STUB:(%p)\n", This);
1200     return E_NOTIMPL;
1201 }
1202 
1203 static HRESULT WINAPI UIElementMgr_EndUIElement(ITfUIElementMgr *iface, DWORD id)
1204 {
1205     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1206 
1207     FIXME("STUB:(%p)\n", This);
1208     return E_NOTIMPL;
1209 }
1210 
1211 static HRESULT WINAPI UIElementMgr_GetUIElement(ITfUIElementMgr *iface, DWORD id,
1212                                                 ITfUIElement **element)
1213 {
1214     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1215 
1216     FIXME("STUB:(%p)\n", This);
1217     return E_NOTIMPL;
1218 }
1219 
1220 static HRESULT WINAPI UIElementMgr_EnumUIElements(ITfUIElementMgr *iface,
1221                                                   IEnumTfUIElements **enum_elements)
1222 {
1223     ThreadMgr *This = impl_from_ITfUIElementMgr(iface);
1224 
1225     FIXME("STUB:(%p)\n", This);
1226     return E_NOTIMPL;
1227 }
1228 
1229 static const ITfUIElementMgrVtbl ThreadMgrUIElementMgrVtbl =
1230 {
1231     UIElementMgr_QueryInterface,
1232     UIElementMgr_AddRef,
1233     UIElementMgr_Release,
1234 
1235     UIElementMgr_BeginUIElement,
1236     UIElementMgr_UpdateUIElement,
1237     UIElementMgr_EndUIElement,
1238     UIElementMgr_GetUIElement,
1239     UIElementMgr_EnumUIElements
1240 };
1241 
1242 /*****************************************************
1243  * ITfSourceSingle functions
1244  *****************************************************/
1245 static HRESULT WINAPI ThreadMgrSourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut)
1246 {
1247     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1248     return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut);
1249 }
1250 
1251 static ULONG WINAPI ThreadMgrSourceSingle_AddRef(ITfSourceSingle *iface)
1252 {
1253     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1254     return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface);
1255 }
1256 
1257 static ULONG WINAPI ThreadMgrSourceSingle_Release(ITfSourceSingle *iface)
1258 {
1259     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1260     return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface);
1261 }
1262 
1263 static HRESULT WINAPI ThreadMgrSourceSingle_AdviseSingleSink( ITfSourceSingle *iface,
1264     TfClientId tid, REFIID riid, IUnknown *punk)
1265 {
1266     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1267     FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk);
1268     return E_NOTIMPL;
1269 }
1270 
1271 static HRESULT WINAPI ThreadMgrSourceSingle_UnadviseSingleSink( ITfSourceSingle *iface,
1272     TfClientId tid, REFIID riid)
1273 {
1274     ThreadMgr *This = impl_from_ITfSourceSingle(iface);
1275     FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid));
1276     return E_NOTIMPL;
1277 }
1278 
1279 static const ITfSourceSingleVtbl SourceSingleVtbl =
1280 {
1281     ThreadMgrSourceSingle_QueryInterface,
1282     ThreadMgrSourceSingle_AddRef,
1283     ThreadMgrSourceSingle_Release,
1284     ThreadMgrSourceSingle_AdviseSingleSink,
1285     ThreadMgrSourceSingle_UnadviseSingleSink
1286 };
1287 
1288 HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
1289 {
1290     ThreadMgr *This;
1291     if (pUnkOuter)
1292         return CLASS_E_NOAGGREGATION;
1293 
1294     /* Only 1 ThreadMgr is created per thread */
1295     This = TlsGetValue(tlsIndex);
1296     if (This)
1297     {
1298         ThreadMgr_AddRef(&This->ITfThreadMgrEx_iface);
1299         *ppOut = (IUnknown*)&This->ITfThreadMgrEx_iface;
1300         return S_OK;
1301     }
1302 
1303     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr));
1304     if (This == NULL)
1305         return E_OUTOFMEMORY;
1306 
1307     This->ITfThreadMgrEx_iface.lpVtbl = &ThreadMgrExVtbl;
1308     This->ITfSource_iface.lpVtbl = &ThreadMgrSourceVtbl;
1309     This->ITfKeystrokeMgr_iface.lpVtbl = &KeystrokeMgrVtbl;
1310     This->ITfMessagePump_iface.lpVtbl = &MessagePumpVtbl;
1311     This->ITfClientId_iface.lpVtbl = &ClientIdVtbl;
1312     This->ITfThreadMgrEventSink_iface.lpVtbl = &ThreadMgrEventSinkVtbl;
1313     This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl;
1314     This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl;
1315     This->refCount = 1;
1316     TlsSetValue(tlsIndex,This);
1317 
1318     CompartmentMgr_Constructor((IUnknown*)&This->ITfThreadMgrEx_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
1319 
1320     list_init(&This->CurrentPreservedKeys);
1321     list_init(&This->CreatedDocumentMgrs);
1322     list_init(&This->AssociatedFocusWindows);
1323 
1324     list_init(&This->ActiveLanguageProfileNotifySink);
1325     list_init(&This->DisplayAttributeNotifySink);
1326     list_init(&This->KeyTraceEventSink);
1327     list_init(&This->PreservedKeyNotifySink);
1328     list_init(&This->ThreadFocusSink);
1329     list_init(&This->ThreadMgrEventSink);
1330 
1331     TRACE("returning %p\n", This);
1332     *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface;
1333     return S_OK;
1334 }
1335 
1336 /**************************************************
1337  * IEnumTfDocumentMgrs implementation
1338  **************************************************/
1339 static void EnumTfDocumentMgr_Destructor(EnumTfDocumentMgr *This)
1340 {
1341     TRACE("destroying %p\n", This);
1342     HeapFree(GetProcessHeap(),0,This);
1343 }
1344 
1345 static HRESULT WINAPI EnumTfDocumentMgr_QueryInterface(IEnumTfDocumentMgrs *iface, REFIID iid, LPVOID *ppvOut)
1346 {
1347     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1348     *ppvOut = NULL;
1349 
1350     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfDocumentMgrs))
1351     {
1352         *ppvOut = &This->IEnumTfDocumentMgrs_iface;
1353     }
1354 
1355     if (*ppvOut)
1356     {
1357         IEnumTfDocumentMgrs_AddRef(iface);
1358         return S_OK;
1359     }
1360 
1361     WARN("unsupported interface: %s\n", debugstr_guid(iid));
1362     return E_NOINTERFACE;
1363 }
1364 
1365 static ULONG WINAPI EnumTfDocumentMgr_AddRef(IEnumTfDocumentMgrs *iface)
1366 {
1367     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1368     return InterlockedIncrement(&This->refCount);
1369 }
1370 
1371 static ULONG WINAPI EnumTfDocumentMgr_Release(IEnumTfDocumentMgrs *iface)
1372 {
1373     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1374     ULONG ret;
1375 
1376     ret = InterlockedDecrement(&This->refCount);
1377     if (ret == 0)
1378         EnumTfDocumentMgr_Destructor(This);
1379     return ret;
1380 }
1381 
1382 static HRESULT WINAPI EnumTfDocumentMgr_Next(IEnumTfDocumentMgrs *iface,
1383     ULONG ulCount, ITfDocumentMgr **rgDocumentMgr, ULONG *pcFetched)
1384 {
1385     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1386     ULONG fetched = 0;
1387 
1388     TRACE("(%p)\n",This);
1389 
1390     if (rgDocumentMgr == NULL) return E_POINTER;
1391 
1392     while (fetched < ulCount)
1393     {
1394         DocumentMgrEntry *mgrentry;
1395         if (This->index == NULL)
1396             break;
1397 
1398         mgrentry = LIST_ENTRY(This->index,DocumentMgrEntry,entry);
1399         if (mgrentry == NULL)
1400             break;
1401 
1402         *rgDocumentMgr = mgrentry->docmgr;
1403         ITfDocumentMgr_AddRef(*rgDocumentMgr);
1404 
1405         This->index = list_next(This->head, This->index);
1406         ++fetched;
1407         ++rgDocumentMgr;
1408     }
1409 
1410     if (pcFetched) *pcFetched = fetched;
1411     return fetched == ulCount ? S_OK : S_FALSE;
1412 }
1413 
1414 static HRESULT WINAPI EnumTfDocumentMgr_Skip( IEnumTfDocumentMgrs* iface, ULONG celt)
1415 {
1416     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1417     ULONG i;
1418 
1419     TRACE("(%p)\n",This);
1420     for(i = 0; i < celt && This->index != NULL; i++)
1421         This->index = list_next(This->head, This->index);
1422     return S_OK;
1423 }
1424 
1425 static HRESULT WINAPI EnumTfDocumentMgr_Reset( IEnumTfDocumentMgrs* iface)
1426 {
1427     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1428     TRACE("(%p)\n",This);
1429     This->index = list_head(This->head);
1430     return S_OK;
1431 }
1432 
1433 static HRESULT WINAPI EnumTfDocumentMgr_Clone( IEnumTfDocumentMgrs *iface,
1434     IEnumTfDocumentMgrs **ppenum)
1435 {
1436     EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface);
1437     HRESULT res;
1438 
1439     TRACE("(%p)\n",This);
1440 
1441     if (ppenum == NULL) return E_POINTER;
1442 
1443     res = EnumTfDocumentMgr_Constructor(This->head, ppenum);
1444     if (SUCCEEDED(res))
1445     {
1446         EnumTfDocumentMgr *new_This = impl_from_IEnumTfDocumentMgrs(*ppenum);
1447         new_This->index = This->index;
1448     }
1449     return res;
1450 }
1451 
1452 static const IEnumTfDocumentMgrsVtbl EnumTfDocumentMgrsVtbl =
1453 {
1454     EnumTfDocumentMgr_QueryInterface,
1455     EnumTfDocumentMgr_AddRef,
1456     EnumTfDocumentMgr_Release,
1457     EnumTfDocumentMgr_Clone,
1458     EnumTfDocumentMgr_Next,
1459     EnumTfDocumentMgr_Reset,
1460     EnumTfDocumentMgr_Skip
1461 };
1462 
1463 static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut)
1464 {
1465     EnumTfDocumentMgr *This;
1466 
1467     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfDocumentMgr));
1468     if (This == NULL)
1469         return E_OUTOFMEMORY;
1470 
1471     This->IEnumTfDocumentMgrs_iface.lpVtbl= &EnumTfDocumentMgrsVtbl;
1472     This->refCount = 1;
1473     This->head = head;
1474     This->index = list_head(This->head);
1475 
1476     TRACE("returning %p\n", &This->IEnumTfDocumentMgrs_iface);
1477     *ppOut = &This->IEnumTfDocumentMgrs_iface;
1478     return S_OK;
1479 }
1480 
1481 void ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *iface, ITfDocumentMgr *mgr)
1482 {
1483     ThreadMgr *This = impl_from_ITfThreadMgrEx((ITfThreadMgrEx *)iface);
1484     struct list *cursor;
1485     LIST_FOR_EACH(cursor, &This->CreatedDocumentMgrs)
1486     {
1487         DocumentMgrEntry *mgrentry = LIST_ENTRY(cursor,DocumentMgrEntry,entry);
1488         if (mgrentry->docmgr == mgr)
1489         {
1490             list_remove(cursor);
1491             HeapFree(GetProcessHeap(),0,mgrentry);
1492             return;
1493         }
1494     }
1495     FIXME("ITfDocumentMgr %p not found in this thread\n",mgr);
1496 }
1497