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