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