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