| /* |
| * ITfThreadMgr implementation |
| * |
| * Copyright 2008 Aric Stewart, CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| |
| #define COBJMACROS |
| |
| #include "wine/debug.h" |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winreg.h" |
| #include "winuser.h" |
| #include "shlwapi.h" |
| #include "winerror.h" |
| #include "objbase.h" |
| #include "olectl.h" |
| |
| #include "wine/unicode.h" |
| |
| #include "msctf.h" |
| #include "msctf_internal.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msctf); |
| |
| typedef struct tagPreservedKey |
| { |
| struct list entry; |
| GUID guid; |
| TF_PRESERVEDKEY prekey; |
| LPWSTR description; |
| TfClientId tid; |
| } PreservedKey; |
| |
| typedef struct tagDocumentMgrs |
| { |
| struct list entry; |
| ITfDocumentMgr *docmgr; |
| } DocumentMgrEntry; |
| |
| typedef struct tagAssociatedWindow |
| { |
| struct list entry; |
| HWND hwnd; |
| ITfDocumentMgr *docmgr; |
| } AssociatedWindow; |
| |
| typedef struct tagACLMulti { |
| ITfThreadMgrEx ITfThreadMgrEx_iface; |
| ITfSource ITfSource_iface; |
| ITfKeystrokeMgr ITfKeystrokeMgr_iface; |
| ITfMessagePump ITfMessagePump_iface; |
| ITfClientId ITfClientId_iface; |
| /* const ITfThreadMgrExVtbl *ThreadMgrExVtbl; */ |
| /* const ITfConfigureSystemKeystrokeFeedVtbl *ConfigureSystemKeystrokeFeedVtbl; */ |
| /* const ITfLangBarItemMgrVtbl *LangBarItemMgrVtbl; */ |
| ITfUIElementMgr ITfUIElementMgr_iface; |
| ITfSourceSingle ITfSourceSingle_iface; |
| LONG refCount; |
| |
| /* Aggregation */ |
| ITfCompartmentMgr *CompartmentMgr; |
| |
| ITfThreadMgrEventSink ITfThreadMgrEventSink_iface; /* internal */ |
| |
| ITfDocumentMgr *focus; |
| LONG activationCount; |
| |
| ITfKeyEventSink *foregroundKeyEventSink; |
| CLSID foregroundTextService; |
| |
| struct list CurrentPreservedKeys; |
| struct list CreatedDocumentMgrs; |
| |
| struct list AssociatedFocusWindows; |
| HHOOK focusHook; |
| |
| /* kept as separate lists to reduce unnecessary iterations */ |
| struct list ActiveLanguageProfileNotifySink; |
| struct list DisplayAttributeNotifySink; |
| struct list KeyTraceEventSink; |
| struct list PreservedKeyNotifySink; |
| struct list ThreadFocusSink; |
| struct list ThreadMgrEventSink; |
| } ThreadMgr; |
| |
| typedef struct tagEnumTfDocumentMgr { |
| IEnumTfDocumentMgrs IEnumTfDocumentMgrs_iface; |
| LONG refCount; |
| |
| struct list *index; |
| struct list *head; |
| } EnumTfDocumentMgr; |
| |
| static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut); |
| |
| static inline ThreadMgr *impl_from_ITfThreadMgrEx(ITfThreadMgrEx *iface) |
| { |
| return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); |
| } |
| |
| static inline ThreadMgr *impl_from_ITfSource(ITfSource *iface) |
| { |
| return CONTAINING_RECORD(iface, ThreadMgr, ITfSource_iface); |
| } |
| |
| static inline ThreadMgr *impl_from_ITfKeystrokeMgr(ITfKeystrokeMgr *iface) |
| { |
| return CONTAINING_RECORD(iface, ThreadMgr, ITfKeystrokeMgr_iface); |
| } |
| |
| static inline ThreadMgr *impl_from_ITfMessagePump(ITfMessagePump *iface) |
| { |
| return CONTAINING_RECORD(iface, ThreadMgr, ITfMessagePump_iface); |
| } |
| |
| static inline ThreadMgr *impl_from_ITfClientId(ITfClientId *iface) |
| { |
| return CONTAINING_RECORD(iface, ThreadMgr, ITfClientId_iface); |
| } |
| |
| static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *iface) |
| { |
| return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEventSink_iface); |
| } |
| |
| static inline ThreadMgr *impl_from_ITfUIElementMgr(ITfUIElementMgr *iface) |
| { |
| return CONTAINING_RECORD(iface, ThreadMgr, ITfUIElementMgr_iface); |
| } |
| |
| static inline ThreadMgr *impl_from_ITfSourceSingle(ITfSourceSingle *iface) |
| { |
| return CONTAINING_RECORD(iface, ThreadMgr, ITfSourceSingle_iface); |
| } |
| |
| static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMgrs *iface) |
| { |
| return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface); |
| } |
| |
| static void ThreadMgr_Destructor(ThreadMgr *This) |
| { |
| struct list *cursor, *cursor2; |
| |
| /* unhook right away */ |
| if (This->focusHook) |
| UnhookWindowsHookEx(This->focusHook); |
| |
| TlsSetValue(tlsIndex,NULL); |
| TRACE("destroying %p\n", This); |
| if (This->focus) |
| ITfDocumentMgr_Release(This->focus); |
| |
| free_sinks(&This->ActiveLanguageProfileNotifySink); |
| free_sinks(&This->DisplayAttributeNotifySink); |
| free_sinks(&This->KeyTraceEventSink); |
| free_sinks(&This->PreservedKeyNotifySink); |
| free_sinks(&This->ThreadFocusSink); |
| free_sinks(&This->ThreadMgrEventSink); |
| |
| LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CurrentPreservedKeys) |
| { |
| PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry); |
| list_remove(cursor); |
| HeapFree(GetProcessHeap(),0,key->description); |
| HeapFree(GetProcessHeap(),0,key); |
| } |
| |
| LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CreatedDocumentMgrs) |
| { |
| DocumentMgrEntry *mgr = LIST_ENTRY(cursor,DocumentMgrEntry,entry); |
| list_remove(cursor); |
| FIXME("Left Over ITfDocumentMgr. Should we do something with it?\n"); |
| HeapFree(GetProcessHeap(),0,mgr); |
| } |
| |
| LIST_FOR_EACH_SAFE(cursor, cursor2, &This->AssociatedFocusWindows) |
| { |
| AssociatedWindow *wnd = LIST_ENTRY(cursor,AssociatedWindow,entry); |
| list_remove(cursor); |
| HeapFree(GetProcessHeap(),0,wnd); |
| } |
| |
| CompartmentMgr_Destructor(This->CompartmentMgr); |
| |
| HeapFree(GetProcessHeap(),0,This); |
| } |
| |
| static HRESULT WINAPI ThreadMgr_QueryInterface(ITfThreadMgrEx *iface, REFIID iid, LPVOID *ppvOut) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| *ppvOut = NULL; |
| |
| if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgr) |
| || IsEqualIID(iid, &IID_ITfThreadMgrEx)) |
| { |
| *ppvOut = &This->ITfThreadMgrEx_iface; |
| } |
| else if (IsEqualIID(iid, &IID_ITfSource)) |
| { |
| *ppvOut = &This->ITfSource_iface; |
| } |
| else if (IsEqualIID(iid, &IID_ITfKeystrokeMgr)) |
| { |
| *ppvOut = &This->ITfKeystrokeMgr_iface; |
| } |
| else if (IsEqualIID(iid, &IID_ITfMessagePump)) |
| { |
| *ppvOut = &This->ITfMessagePump_iface; |
| } |
| else if (IsEqualIID(iid, &IID_ITfClientId)) |
| { |
| *ppvOut = &This->ITfClientId_iface; |
| } |
| else if (IsEqualIID(iid, &IID_ITfCompartmentMgr)) |
| { |
| *ppvOut = This->CompartmentMgr; |
| } |
| else if (IsEqualIID(iid, &IID_ITfUIElementMgr)) |
| { |
| *ppvOut = &This->ITfUIElementMgr_iface; |
| } |
| else if (IsEqualIID(iid, &IID_ITfSourceSingle)) |
| { |
| *ppvOut = &This->ITfSourceSingle_iface; |
| } |
| |
| if (*ppvOut) |
| { |
| ITfThreadMgrEx_AddRef(iface); |
| return S_OK; |
| } |
| |
| WARN("unsupported interface: %s\n", debugstr_guid(iid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI ThreadMgr_AddRef(ITfThreadMgrEx *iface) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| return InterlockedIncrement(&This->refCount); |
| } |
| |
| static ULONG WINAPI ThreadMgr_Release(ITfThreadMgrEx *iface) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| ULONG ret; |
| |
| ret = InterlockedDecrement(&This->refCount); |
| if (ret == 0) |
| ThreadMgr_Destructor(This); |
| return ret; |
| } |
| |
| /***************************************************** |
| * ITfThreadMgr functions |
| *****************************************************/ |
| |
| static HRESULT WINAPI ThreadMgr_Activate(ITfThreadMgrEx *iface, TfClientId *id) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| |
| TRACE("(%p) %p\n", This, id); |
| return ITfThreadMgrEx_ActivateEx(iface, id, 0); |
| } |
| |
| static HRESULT WINAPI ThreadMgr_Deactivate(ITfThreadMgrEx *iface) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| TRACE("(%p)\n",This); |
| |
| if (This->activationCount == 0) |
| return E_UNEXPECTED; |
| |
| This->activationCount --; |
| |
| if (This->activationCount == 0) |
| { |
| if (This->focus) |
| { |
| ITfThreadMgrEventSink_OnSetFocus(&This->ITfThreadMgrEventSink_iface, 0, This->focus); |
| ITfDocumentMgr_Release(This->focus); |
| This->focus = 0; |
| } |
| } |
| |
| deactivate_textservices(); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_CreateDocumentMgr(ITfThreadMgrEx *iface, ITfDocumentMgr **ppdim) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| DocumentMgrEntry *mgrentry; |
| HRESULT hr; |
| |
| TRACE("(%p)\n",iface); |
| mgrentry = HeapAlloc(GetProcessHeap(),0,sizeof(DocumentMgrEntry)); |
| if (mgrentry == NULL) |
| return E_OUTOFMEMORY; |
| |
| hr = DocumentMgr_Constructor(&This->ITfThreadMgrEventSink_iface, ppdim); |
| |
| if (SUCCEEDED(hr)) |
| { |
| mgrentry->docmgr = *ppdim; |
| list_add_head(&This->CreatedDocumentMgrs,&mgrentry->entry); |
| } |
| else |
| HeapFree(GetProcessHeap(),0,mgrentry); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_EnumDocumentMgrs(ITfThreadMgrEx *iface, IEnumTfDocumentMgrs **ppEnum) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| TRACE("(%p) %p\n",This,ppEnum); |
| |
| if (!ppEnum) |
| return E_INVALIDARG; |
| |
| return EnumTfDocumentMgr_Constructor(&This->CreatedDocumentMgrs, ppEnum); |
| } |
| |
| static HRESULT WINAPI ThreadMgr_GetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr **ppdimFocus) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| TRACE("(%p)\n",This); |
| |
| if (!ppdimFocus) |
| return E_INVALIDARG; |
| |
| *ppdimFocus = This->focus; |
| |
| TRACE("->%p\n",This->focus); |
| |
| if (This->focus == NULL) |
| return S_FALSE; |
| |
| ITfDocumentMgr_AddRef(This->focus); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_SetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr *pdimFocus) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| ITfDocumentMgr *check; |
| |
| TRACE("(%p) %p\n",This,pdimFocus); |
| |
| if (!pdimFocus) |
| check = NULL; |
| else if (FAILED(ITfDocumentMgr_QueryInterface(pdimFocus,&IID_ITfDocumentMgr,(LPVOID*) &check))) |
| return E_INVALIDARG; |
| |
| ITfThreadMgrEventSink_OnSetFocus(&This->ITfThreadMgrEventSink_iface, check, This->focus); |
| |
| if (This->focus) |
| ITfDocumentMgr_Release(This->focus); |
| |
| This->focus = check; |
| return S_OK; |
| } |
| |
| static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam) |
| { |
| ThreadMgr *This; |
| |
| This = TlsGetValue(tlsIndex); |
| if (!This) |
| { |
| ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n"); |
| return 0; |
| } |
| if (!This->focusHook) |
| { |
| ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n"); |
| return 0; |
| } |
| |
| if (nCode == HCBT_SETFOCUS) /* focus change within our thread */ |
| { |
| struct list *cursor; |
| |
| LIST_FOR_EACH(cursor, &This->AssociatedFocusWindows) |
| { |
| AssociatedWindow *wnd = LIST_ENTRY(cursor,AssociatedWindow,entry); |
| if (wnd->hwnd == (HWND)wParam) |
| { |
| TRACE("Triggering Associated window focus\n"); |
| if (This->focus != wnd->docmgr) |
| ThreadMgr_SetFocus(&This->ITfThreadMgrEx_iface, wnd->docmgr); |
| break; |
| } |
| } |
| } |
| |
| return CallNextHookEx(This->focusHook, nCode, wParam, lParam); |
| } |
| |
| static HRESULT SetupWindowsHook(ThreadMgr *This) |
| { |
| if (!This->focusHook) |
| { |
| This->focusHook = SetWindowsHookExW(WH_CBT, ThreadFocusHookProc, 0, |
| GetCurrentThreadId()); |
| if (!This->focusHook) |
| { |
| ERR("Unable to set focus hook\n"); |
| return E_FAIL; |
| } |
| return S_OK; |
| } |
| return S_FALSE; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_AssociateFocus(ITfThreadMgrEx *iface, HWND hwnd, |
| ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| struct list *cursor, *cursor2; |
| AssociatedWindow *wnd; |
| |
| TRACE("(%p) %p %p %p\n",This,hwnd,pdimNew,ppdimPrev); |
| |
| if (!ppdimPrev) |
| return E_INVALIDARG; |
| |
| *ppdimPrev = NULL; |
| |
| LIST_FOR_EACH_SAFE(cursor, cursor2, &This->AssociatedFocusWindows) |
| { |
| wnd = LIST_ENTRY(cursor,AssociatedWindow,entry); |
| if (wnd->hwnd == hwnd) |
| { |
| if (wnd->docmgr) |
| ITfDocumentMgr_AddRef(wnd->docmgr); |
| *ppdimPrev = wnd->docmgr; |
| wnd->docmgr = pdimNew; |
| if (GetFocus() == hwnd) |
| ThreadMgr_SetFocus(iface,pdimNew); |
| return S_OK; |
| } |
| } |
| |
| wnd = HeapAlloc(GetProcessHeap(),0,sizeof(AssociatedWindow)); |
| wnd->hwnd = hwnd; |
| wnd->docmgr = pdimNew; |
| list_add_head(&This->AssociatedFocusWindows,&wnd->entry); |
| |
| if (GetFocus() == hwnd) |
| ThreadMgr_SetFocus(iface,pdimNew); |
| |
| SetupWindowsHook(This); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_IsThreadFocus(ITfThreadMgrEx *iface, BOOL *pfThreadFocus) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| HWND focus; |
| |
| TRACE("(%p) %p\n",This,pfThreadFocus); |
| focus = GetFocus(); |
| *pfThreadFocus = (focus == NULL); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_GetFunctionProvider(ITfThreadMgrEx *iface, REFCLSID clsid, |
| ITfFunctionProvider **ppFuncProv) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| FIXME("STUB:(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_EnumFunctionProviders(ITfThreadMgrEx *iface, |
| IEnumTfFunctionProviders **ppEnum) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| FIXME("STUB:(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_GetGlobalCompartment(ITfThreadMgrEx *iface, |
| ITfCompartmentMgr **ppCompMgr) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| HRESULT hr; |
| TRACE("(%p) %p\n",This, ppCompMgr); |
| |
| if (!ppCompMgr) |
| return E_INVALIDARG; |
| |
| if (!globalCompartmentMgr) |
| { |
| hr = CompartmentMgr_Constructor(NULL,&IID_ITfCompartmentMgr,(IUnknown**)&globalCompartmentMgr); |
| if (FAILED(hr)) |
| return hr; |
| } |
| |
| ITfCompartmentMgr_AddRef(globalCompartmentMgr); |
| *ppCompMgr = globalCompartmentMgr; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_ActivateEx(ITfThreadMgrEx *iface, TfClientId *id, DWORD flags) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| |
| TRACE("(%p) %p, %#x\n", This, id, flags); |
| |
| if (!id) |
| return E_INVALIDARG; |
| |
| if (flags) |
| FIXME("Unimplemented flags %#x\n", flags); |
| |
| if (!processId) |
| { |
| GUID guid; |
| CoCreateGuid(&guid); |
| ITfClientId_GetClientId(&This->ITfClientId_iface, &guid, &processId); |
| } |
| |
| activate_textservices(iface); |
| This->activationCount++; |
| *id = processId; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgr_GetActiveFlags(ITfThreadMgrEx *iface, DWORD *flags) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx(iface); |
| |
| FIXME("STUB:(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static const ITfThreadMgrExVtbl ThreadMgrExVtbl = |
| { |
| ThreadMgr_QueryInterface, |
| ThreadMgr_AddRef, |
| ThreadMgr_Release, |
| ThreadMgr_Activate, |
| ThreadMgr_Deactivate, |
| ThreadMgr_CreateDocumentMgr, |
| ThreadMgr_EnumDocumentMgrs, |
| ThreadMgr_GetFocus, |
| ThreadMgr_SetFocus, |
| ThreadMgr_AssociateFocus, |
| ThreadMgr_IsThreadFocus, |
| ThreadMgr_GetFunctionProvider, |
| ThreadMgr_EnumFunctionProviders, |
| ThreadMgr_GetGlobalCompartment, |
| |
| ThreadMgr_ActivateEx, |
| ThreadMgr_GetActiveFlags |
| }; |
| |
| static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut) |
| { |
| ThreadMgr *This = impl_from_ITfSource(iface); |
| return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut); |
| } |
| |
| static ULONG WINAPI Source_AddRef(ITfSource *iface) |
| { |
| ThreadMgr *This = impl_from_ITfSource(iface); |
| return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static ULONG WINAPI Source_Release(ITfSource *iface) |
| { |
| ThreadMgr *This = impl_from_ITfSource(iface); |
| return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface); |
| } |
| |
| /***************************************************** |
| * ITfSource functions |
| *****************************************************/ |
| static HRESULT WINAPI ThreadMgrSource_AdviseSink(ITfSource *iface, |
| REFIID riid, IUnknown *punk, DWORD *pdwCookie) |
| { |
| ThreadMgr *This = impl_from_ITfSource(iface); |
| |
| TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie); |
| |
| if (!riid || !punk || !pdwCookie) |
| return E_INVALIDARG; |
| |
| if (IsEqualIID(riid, &IID_ITfThreadMgrEventSink)) |
| return advise_sink(&This->ThreadMgrEventSink, &IID_ITfThreadMgrEventSink, COOKIE_MAGIC_TMSINK, punk, pdwCookie); |
| |
| if (IsEqualIID(riid, &IID_ITfThreadFocusSink)) |
| { |
| WARN("semi-stub for ITfThreadFocusSink: sink won't be used.\n"); |
| return advise_sink(&This->ThreadFocusSink, &IID_ITfThreadFocusSink, COOKIE_MAGIC_THREADFOCUSSINK, punk, pdwCookie); |
| } |
| |
| FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ThreadMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie) |
| { |
| ThreadMgr *This = impl_from_ITfSource(iface); |
| |
| TRACE("(%p) %x\n",This,pdwCookie); |
| |
| if (get_Cookie_magic(pdwCookie) != COOKIE_MAGIC_TMSINK && get_Cookie_magic(pdwCookie) != COOKIE_MAGIC_THREADFOCUSSINK) |
| return E_INVALIDARG; |
| |
| return unadvise_sink(pdwCookie); |
| } |
| |
| static const ITfSourceVtbl ThreadMgrSourceVtbl = |
| { |
| Source_QueryInterface, |
| Source_AddRef, |
| Source_Release, |
| ThreadMgrSource_AdviseSink, |
| ThreadMgrSource_UnadviseSink, |
| }; |
| |
| /***************************************************** |
| * ITfKeystrokeMgr functions |
| *****************************************************/ |
| |
| static HRESULT WINAPI KeystrokeMgr_QueryInterface(ITfKeystrokeMgr *iface, REFIID iid, LPVOID *ppvOut) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut); |
| } |
| |
| static ULONG WINAPI KeystrokeMgr_AddRef(ITfKeystrokeMgr *iface) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static ULONG WINAPI KeystrokeMgr_Release(ITfKeystrokeMgr *iface) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_AdviseKeyEventSink(ITfKeystrokeMgr *iface, |
| TfClientId tid, ITfKeyEventSink *pSink, BOOL fForeground) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| CLSID textservice; |
| ITfKeyEventSink *check = NULL; |
| |
| TRACE("(%p) %x %p %i\n",This,tid,pSink,fForeground); |
| |
| if (!tid || !pSink) |
| return E_INVALIDARG; |
| |
| textservice = get_textservice_clsid(tid); |
| if (IsEqualCLSID(&GUID_NULL,&textservice)) |
| return E_INVALIDARG; |
| |
| get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check); |
| if (check != NULL) |
| return CONNECT_E_ADVISELIMIT; |
| |
| if (FAILED(ITfKeyEventSink_QueryInterface(pSink,&IID_ITfKeyEventSink,(LPVOID*) &check))) |
| return E_INVALIDARG; |
| |
| set_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown*)check); |
| |
| if (fForeground) |
| { |
| if (This->foregroundKeyEventSink) |
| { |
| ITfKeyEventSink_OnSetFocus(This->foregroundKeyEventSink, FALSE); |
| ITfKeyEventSink_Release(This->foregroundKeyEventSink); |
| } |
| ITfKeyEventSink_AddRef(check); |
| ITfKeyEventSink_OnSetFocus(check, TRUE); |
| This->foregroundKeyEventSink = check; |
| This->foregroundTextService = textservice; |
| } |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_UnadviseKeyEventSink(ITfKeystrokeMgr *iface, |
| TfClientId tid) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| CLSID textservice; |
| ITfKeyEventSink *check = NULL; |
| TRACE("(%p) %x\n",This,tid); |
| |
| if (!tid) |
| return E_INVALIDARG; |
| |
| textservice = get_textservice_clsid(tid); |
| if (IsEqualCLSID(&GUID_NULL,&textservice)) |
| return E_INVALIDARG; |
| |
| get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check); |
| |
| if (!check) |
| return CONNECT_E_NOCONNECTION; |
| |
| set_textservice_sink(tid, &IID_ITfKeyEventSink, NULL); |
| ITfKeyEventSink_Release(check); |
| |
| if (This->foregroundKeyEventSink == check) |
| { |
| ITfKeyEventSink_Release(This->foregroundKeyEventSink); |
| This->foregroundKeyEventSink = NULL; |
| This->foregroundTextService = GUID_NULL; |
| } |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_GetForeground(ITfKeystrokeMgr *iface, |
| CLSID *pclsid) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| TRACE("(%p) %p\n",This,pclsid); |
| if (!pclsid) |
| return E_INVALIDARG; |
| |
| if (IsEqualCLSID(&This->foregroundTextService,&GUID_NULL)) |
| return S_FALSE; |
| |
| *pclsid = This->foregroundTextService; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_TestKeyDown(ITfKeystrokeMgr *iface, |
| WPARAM wParam, LPARAM lParam, BOOL *pfEaten) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| FIXME("STUB:(%p)\n",This); |
| *pfEaten = FALSE; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_TestKeyUp(ITfKeystrokeMgr *iface, |
| WPARAM wParam, LPARAM lParam, BOOL *pfEaten) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| FIXME("STUB:(%p)\n",This); |
| *pfEaten = FALSE; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_KeyDown(ITfKeystrokeMgr *iface, |
| WPARAM wParam, LPARAM lParam, BOOL *pfEaten) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| FIXME("STUB:(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_KeyUp(ITfKeystrokeMgr *iface, |
| WPARAM wParam, LPARAM lParam, BOOL *pfEaten) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| FIXME("STUB:(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_GetPreservedKey(ITfKeystrokeMgr *iface, |
| ITfContext *pic, const TF_PRESERVEDKEY *pprekey, GUID *pguid) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| FIXME("STUB:(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_IsPreservedKey(ITfKeystrokeMgr *iface, |
| REFGUID rguid, const TF_PRESERVEDKEY *pprekey, BOOL *pfRegistered) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| struct list *cursor; |
| |
| TRACE("(%p) %s (%x %x) %p\n",This,debugstr_guid(rguid), (pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0, pfRegistered); |
| |
| if (!rguid || !pprekey || !pfRegistered) |
| return E_INVALIDARG; |
| |
| LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys) |
| { |
| PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry); |
| if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers) |
| { |
| *pfRegistered = TRUE; |
| return S_OK; |
| } |
| } |
| |
| *pfRegistered = FALSE; |
| return S_FALSE; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface, |
| TfClientId tid, REFGUID rguid, const TF_PRESERVEDKEY *prekey, |
| const WCHAR *pchDesc, ULONG cchDesc) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| struct list *cursor; |
| PreservedKey *newkey; |
| |
| 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)); |
| |
| if (!tid || ! rguid || !prekey || (cchDesc && !pchDesc)) |
| return E_INVALIDARG; |
| |
| LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys) |
| { |
| PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry); |
| if (IsEqualGUID(rguid,&key->guid) && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers) |
| return TF_E_ALREADY_EXISTS; |
| } |
| |
| newkey = HeapAlloc(GetProcessHeap(),0,sizeof(PreservedKey)); |
| if (!newkey) |
| return E_OUTOFMEMORY; |
| |
| newkey->guid = *rguid; |
| newkey->prekey = *prekey; |
| newkey->tid = tid; |
| newkey->description = NULL; |
| if (cchDesc) |
| { |
| newkey->description = HeapAlloc(GetProcessHeap(),0,cchDesc * sizeof(WCHAR)); |
| if (!newkey->description) |
| { |
| HeapFree(GetProcessHeap(),0,newkey); |
| return E_OUTOFMEMORY; |
| } |
| memcpy(newkey->description, pchDesc, cchDesc*sizeof(WCHAR)); |
| } |
| |
| list_add_head(&This->CurrentPreservedKeys,&newkey->entry); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_UnpreserveKey(ITfKeystrokeMgr *iface, |
| REFGUID rguid, const TF_PRESERVEDKEY *pprekey) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| PreservedKey* key = NULL; |
| struct list *cursor; |
| TRACE("(%p) %s (%x %x)\n",This,debugstr_guid(rguid),(pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0); |
| |
| if (!pprekey || !rguid) |
| return E_INVALIDARG; |
| |
| LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys) |
| { |
| key = LIST_ENTRY(cursor,PreservedKey,entry); |
| if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers) |
| break; |
| key = NULL; |
| } |
| |
| if (!key) |
| return CONNECT_E_NOCONNECTION; |
| |
| list_remove(&key->entry); |
| HeapFree(GetProcessHeap(),0,key->description); |
| HeapFree(GetProcessHeap(),0,key); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_SetPreservedKeyDescription(ITfKeystrokeMgr *iface, |
| REFGUID rguid, const WCHAR *pchDesc, ULONG cchDesc) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| FIXME("STUB:(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_GetPreservedKeyDescription(ITfKeystrokeMgr *iface, |
| REFGUID rguid, BSTR *pbstrDesc) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| FIXME("STUB:(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI KeystrokeMgr_SimulatePreservedKey(ITfKeystrokeMgr *iface, |
| ITfContext *pic, REFGUID rguid, BOOL *pfEaten) |
| { |
| ThreadMgr *This = impl_from_ITfKeystrokeMgr(iface); |
| FIXME("STUB:(%p)\n",This); |
| return E_NOTIMPL; |
| } |
| |
| static const ITfKeystrokeMgrVtbl KeystrokeMgrVtbl = |
| { |
| KeystrokeMgr_QueryInterface, |
| KeystrokeMgr_AddRef, |
| KeystrokeMgr_Release, |
| KeystrokeMgr_AdviseKeyEventSink, |
| KeystrokeMgr_UnadviseKeyEventSink, |
| KeystrokeMgr_GetForeground, |
| KeystrokeMgr_TestKeyDown, |
| KeystrokeMgr_TestKeyUp, |
| KeystrokeMgr_KeyDown, |
| KeystrokeMgr_KeyUp, |
| KeystrokeMgr_GetPreservedKey, |
| KeystrokeMgr_IsPreservedKey, |
| KeystrokeMgr_PreserveKey, |
| KeystrokeMgr_UnpreserveKey, |
| KeystrokeMgr_SetPreservedKeyDescription, |
| KeystrokeMgr_GetPreservedKeyDescription, |
| KeystrokeMgr_SimulatePreservedKey |
| }; |
| |
| /***************************************************** |
| * ITfMessagePump functions |
| *****************************************************/ |
| |
| static HRESULT WINAPI MessagePump_QueryInterface(ITfMessagePump *iface, REFIID iid, LPVOID *ppvOut) |
| { |
| ThreadMgr *This = impl_from_ITfMessagePump(iface); |
| return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut); |
| } |
| |
| static ULONG WINAPI MessagePump_AddRef(ITfMessagePump *iface) |
| { |
| ThreadMgr *This = impl_from_ITfMessagePump(iface); |
| return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static ULONG WINAPI MessagePump_Release(ITfMessagePump *iface) |
| { |
| ThreadMgr *This = impl_from_ITfMessagePump(iface); |
| return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static HRESULT WINAPI MessagePump_PeekMessageA(ITfMessagePump *iface, |
| LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, |
| UINT wRemoveMsg, BOOL *pfResult) |
| { |
| if (!pfResult) |
| return E_INVALIDARG; |
| *pfResult = PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI MessagePump_GetMessageA(ITfMessagePump *iface, |
| LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, |
| BOOL *pfResult) |
| { |
| if (!pfResult) |
| return E_INVALIDARG; |
| *pfResult = GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI MessagePump_PeekMessageW(ITfMessagePump *iface, |
| LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, |
| UINT wRemoveMsg, BOOL *pfResult) |
| { |
| if (!pfResult) |
| return E_INVALIDARG; |
| *pfResult = PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI MessagePump_GetMessageW(ITfMessagePump *iface, |
| LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax, |
| BOOL *pfResult) |
| { |
| if (!pfResult) |
| return E_INVALIDARG; |
| *pfResult = GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax); |
| return S_OK; |
| } |
| |
| static const ITfMessagePumpVtbl MessagePumpVtbl = |
| { |
| MessagePump_QueryInterface, |
| MessagePump_AddRef, |
| MessagePump_Release, |
| MessagePump_PeekMessageA, |
| MessagePump_GetMessageA, |
| MessagePump_PeekMessageW, |
| MessagePump_GetMessageW |
| }; |
| |
| /***************************************************** |
| * ITfClientId functions |
| *****************************************************/ |
| |
| static HRESULT WINAPI ClientId_QueryInterface(ITfClientId *iface, REFIID iid, LPVOID *ppvOut) |
| { |
| ThreadMgr *This = impl_from_ITfClientId(iface); |
| return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut); |
| } |
| |
| static ULONG WINAPI ClientId_AddRef(ITfClientId *iface) |
| { |
| ThreadMgr *This = impl_from_ITfClientId(iface); |
| return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static ULONG WINAPI ClientId_Release(ITfClientId *iface) |
| { |
| ThreadMgr *This = impl_from_ITfClientId(iface); |
| return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static HRESULT WINAPI ClientId_GetClientId(ITfClientId *iface, |
| REFCLSID rclsid, TfClientId *ptid) |
| |
| { |
| ThreadMgr *This = impl_from_ITfClientId(iface); |
| HRESULT hr; |
| ITfCategoryMgr *catmgr; |
| |
| TRACE("(%p) %s\n",This,debugstr_guid(rclsid)); |
| |
| CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr); |
| hr = ITfCategoryMgr_RegisterGUID(catmgr,rclsid,ptid); |
| ITfCategoryMgr_Release(catmgr); |
| |
| return hr; |
| } |
| |
| static const ITfClientIdVtbl ClientIdVtbl = |
| { |
| ClientId_QueryInterface, |
| ClientId_AddRef, |
| ClientId_Release, |
| ClientId_GetClientId |
| }; |
| |
| /***************************************************** |
| * ITfThreadMgrEventSink functions (internal) |
| *****************************************************/ |
| static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface); |
| return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut); |
| } |
| |
| static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface); |
| return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface); |
| return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface); |
| } |
| |
| |
| static HRESULT WINAPI ThreadMgrEventSink_OnInitDocumentMgr( |
| ITfThreadMgrEventSink *iface,ITfDocumentMgr *pdim) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface); |
| ITfThreadMgrEventSink *sink; |
| struct list *cursor; |
| |
| TRACE("(%p) %p\n",This,pdim); |
| |
| SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink) |
| { |
| ITfThreadMgrEventSink_OnInitDocumentMgr(sink, pdim); |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgrEventSink_OnUninitDocumentMgr( |
| ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdim) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface); |
| ITfThreadMgrEventSink *sink; |
| struct list *cursor; |
| |
| TRACE("(%p) %p\n",This,pdim); |
| |
| SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink) |
| { |
| ITfThreadMgrEventSink_OnUninitDocumentMgr(sink, pdim); |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgrEventSink_OnSetFocus( |
| ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdimFocus, |
| ITfDocumentMgr *pdimPrevFocus) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface); |
| ITfThreadMgrEventSink *sink; |
| struct list *cursor; |
| |
| TRACE("(%p) %p %p\n",This,pdimFocus, pdimPrevFocus); |
| |
| SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink) |
| { |
| ITfThreadMgrEventSink_OnSetFocus(sink, pdimFocus, pdimPrevFocus); |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgrEventSink_OnPushContext( |
| ITfThreadMgrEventSink *iface, ITfContext *pic) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface); |
| ITfThreadMgrEventSink *sink; |
| struct list *cursor; |
| |
| TRACE("(%p) %p\n",This,pic); |
| |
| SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink) |
| { |
| ITfThreadMgrEventSink_OnPushContext(sink, pic); |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ThreadMgrEventSink_OnPopContext( |
| ITfThreadMgrEventSink *iface, ITfContext *pic) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface); |
| ITfThreadMgrEventSink *sink; |
| struct list *cursor; |
| |
| TRACE("(%p) %p\n",This,pic); |
| |
| SINK_FOR_EACH(cursor, &This->ThreadMgrEventSink, ITfThreadMgrEventSink, sink) |
| { |
| ITfThreadMgrEventSink_OnPopContext(sink, pic); |
| } |
| |
| return S_OK; |
| } |
| |
| static const ITfThreadMgrEventSinkVtbl ThreadMgrEventSinkVtbl = |
| { |
| ThreadMgrEventSink_QueryInterface, |
| ThreadMgrEventSink_AddRef, |
| ThreadMgrEventSink_Release, |
| ThreadMgrEventSink_OnInitDocumentMgr, |
| ThreadMgrEventSink_OnUninitDocumentMgr, |
| ThreadMgrEventSink_OnSetFocus, |
| ThreadMgrEventSink_OnPushContext, |
| ThreadMgrEventSink_OnPopContext |
| }; |
| |
| /***************************************************** |
| * ITfUIElementMgr functions |
| *****************************************************/ |
| static HRESULT WINAPI UIElementMgr_QueryInterface(ITfUIElementMgr *iface, REFIID iid, void **ppvOut) |
| { |
| ThreadMgr *This = impl_from_ITfUIElementMgr(iface); |
| |
| return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut); |
| } |
| |
| static ULONG WINAPI UIElementMgr_AddRef(ITfUIElementMgr *iface) |
| { |
| ThreadMgr *This = impl_from_ITfUIElementMgr(iface); |
| |
| return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static ULONG WINAPI UIElementMgr_Release(ITfUIElementMgr *iface) |
| { |
| ThreadMgr *This = impl_from_ITfUIElementMgr(iface); |
| |
| return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static HRESULT WINAPI UIElementMgr_BeginUIElement(ITfUIElementMgr *iface, ITfUIElement *element, |
| BOOL *show, DWORD *id) |
| { |
| ThreadMgr *This = impl_from_ITfUIElementMgr(iface); |
| |
| FIXME("STUB:(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI UIElementMgr_UpdateUIElement(ITfUIElementMgr *iface, DWORD id) |
| { |
| ThreadMgr *This = impl_from_ITfUIElementMgr(iface); |
| |
| FIXME("STUB:(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI UIElementMgr_EndUIElement(ITfUIElementMgr *iface, DWORD id) |
| { |
| ThreadMgr *This = impl_from_ITfUIElementMgr(iface); |
| |
| FIXME("STUB:(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI UIElementMgr_GetUIElement(ITfUIElementMgr *iface, DWORD id, |
| ITfUIElement **element) |
| { |
| ThreadMgr *This = impl_from_ITfUIElementMgr(iface); |
| |
| FIXME("STUB:(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI UIElementMgr_EnumUIElements(ITfUIElementMgr *iface, |
| IEnumTfUIElements **enum_elements) |
| { |
| ThreadMgr *This = impl_from_ITfUIElementMgr(iface); |
| |
| FIXME("STUB:(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static const ITfUIElementMgrVtbl ThreadMgrUIElementMgrVtbl = |
| { |
| UIElementMgr_QueryInterface, |
| UIElementMgr_AddRef, |
| UIElementMgr_Release, |
| |
| UIElementMgr_BeginUIElement, |
| UIElementMgr_UpdateUIElement, |
| UIElementMgr_EndUIElement, |
| UIElementMgr_GetUIElement, |
| UIElementMgr_EnumUIElements |
| }; |
| |
| /***************************************************** |
| * ITfSourceSingle functions |
| *****************************************************/ |
| static HRESULT WINAPI ThreadMgrSourceSingle_QueryInterface(ITfSourceSingle *iface, REFIID iid, LPVOID *ppvOut) |
| { |
| ThreadMgr *This = impl_from_ITfSourceSingle(iface); |
| return ITfThreadMgrEx_QueryInterface(&This->ITfThreadMgrEx_iface, iid, ppvOut); |
| } |
| |
| static ULONG WINAPI ThreadMgrSourceSingle_AddRef(ITfSourceSingle *iface) |
| { |
| ThreadMgr *This = impl_from_ITfSourceSingle(iface); |
| return ITfThreadMgrEx_AddRef(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static ULONG WINAPI ThreadMgrSourceSingle_Release(ITfSourceSingle *iface) |
| { |
| ThreadMgr *This = impl_from_ITfSourceSingle(iface); |
| return ITfThreadMgrEx_Release(&This->ITfThreadMgrEx_iface); |
| } |
| |
| static HRESULT WINAPI ThreadMgrSourceSingle_AdviseSingleSink( ITfSourceSingle *iface, |
| TfClientId tid, REFIID riid, IUnknown *punk) |
| { |
| ThreadMgr *This = impl_from_ITfSourceSingle(iface); |
| FIXME("STUB:(%p) %i %s %p\n",This, tid, debugstr_guid(riid),punk); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ThreadMgrSourceSingle_UnadviseSingleSink( ITfSourceSingle *iface, |
| TfClientId tid, REFIID riid) |
| { |
| ThreadMgr *This = impl_from_ITfSourceSingle(iface); |
| FIXME("STUB:(%p) %i %s\n",This, tid, debugstr_guid(riid)); |
| return E_NOTIMPL; |
| } |
| |
| static const ITfSourceSingleVtbl SourceSingleVtbl = |
| { |
| ThreadMgrSourceSingle_QueryInterface, |
| ThreadMgrSourceSingle_AddRef, |
| ThreadMgrSourceSingle_Release, |
| ThreadMgrSourceSingle_AdviseSingleSink, |
| ThreadMgrSourceSingle_UnadviseSingleSink |
| }; |
| |
| HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) |
| { |
| ThreadMgr *This; |
| if (pUnkOuter) |
| return CLASS_E_NOAGGREGATION; |
| |
| /* Only 1 ThreadMgr is created per thread */ |
| This = TlsGetValue(tlsIndex); |
| if (This) |
| { |
| ThreadMgr_AddRef(&This->ITfThreadMgrEx_iface); |
| *ppOut = (IUnknown*)&This->ITfThreadMgrEx_iface; |
| return S_OK; |
| } |
| |
| This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr)); |
| if (This == NULL) |
| return E_OUTOFMEMORY; |
| |
| This->ITfThreadMgrEx_iface.lpVtbl = &ThreadMgrExVtbl; |
| This->ITfSource_iface.lpVtbl = &ThreadMgrSourceVtbl; |
| This->ITfKeystrokeMgr_iface.lpVtbl = &KeystrokeMgrVtbl; |
| This->ITfMessagePump_iface.lpVtbl = &MessagePumpVtbl; |
| This->ITfClientId_iface.lpVtbl = &ClientIdVtbl; |
| This->ITfThreadMgrEventSink_iface.lpVtbl = &ThreadMgrEventSinkVtbl; |
| This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl; |
| This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl; |
| This->refCount = 1; |
| TlsSetValue(tlsIndex,This); |
| |
| CompartmentMgr_Constructor((IUnknown*)&This->ITfThreadMgrEx_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); |
| |
| list_init(&This->CurrentPreservedKeys); |
| list_init(&This->CreatedDocumentMgrs); |
| list_init(&This->AssociatedFocusWindows); |
| |
| list_init(&This->ActiveLanguageProfileNotifySink); |
| list_init(&This->DisplayAttributeNotifySink); |
| list_init(&This->KeyTraceEventSink); |
| list_init(&This->PreservedKeyNotifySink); |
| list_init(&This->ThreadFocusSink); |
| list_init(&This->ThreadMgrEventSink); |
| |
| TRACE("returning %p\n", This); |
| *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface; |
| return S_OK; |
| } |
| |
| /************************************************** |
| * IEnumTfDocumentMgrs implementation |
| **************************************************/ |
| static void EnumTfDocumentMgr_Destructor(EnumTfDocumentMgr *This) |
| { |
| TRACE("destroying %p\n", This); |
| HeapFree(GetProcessHeap(),0,This); |
| } |
| |
| static HRESULT WINAPI EnumTfDocumentMgr_QueryInterface(IEnumTfDocumentMgrs *iface, REFIID iid, LPVOID *ppvOut) |
| { |
| EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface); |
| *ppvOut = NULL; |
| |
| if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfDocumentMgrs)) |
| { |
| *ppvOut = &This->IEnumTfDocumentMgrs_iface; |
| } |
| |
| if (*ppvOut) |
| { |
| IEnumTfDocumentMgrs_AddRef(iface); |
| return S_OK; |
| } |
| |
| WARN("unsupported interface: %s\n", debugstr_guid(iid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI EnumTfDocumentMgr_AddRef(IEnumTfDocumentMgrs *iface) |
| { |
| EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface); |
| return InterlockedIncrement(&This->refCount); |
| } |
| |
| static ULONG WINAPI EnumTfDocumentMgr_Release(IEnumTfDocumentMgrs *iface) |
| { |
| EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface); |
| ULONG ret; |
| |
| ret = InterlockedDecrement(&This->refCount); |
| if (ret == 0) |
| EnumTfDocumentMgr_Destructor(This); |
| return ret; |
| } |
| |
| static HRESULT WINAPI EnumTfDocumentMgr_Next(IEnumTfDocumentMgrs *iface, |
| ULONG ulCount, ITfDocumentMgr **rgDocumentMgr, ULONG *pcFetched) |
| { |
| EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface); |
| ULONG fetched = 0; |
| |
| TRACE("(%p)\n",This); |
| |
| if (rgDocumentMgr == NULL) return E_POINTER; |
| |
| while (fetched < ulCount) |
| { |
| DocumentMgrEntry *mgrentry; |
| if (This->index == NULL) |
| break; |
| |
| mgrentry = LIST_ENTRY(This->index,DocumentMgrEntry,entry); |
| if (mgrentry == NULL) |
| break; |
| |
| *rgDocumentMgr = mgrentry->docmgr; |
| ITfDocumentMgr_AddRef(*rgDocumentMgr); |
| |
| This->index = list_next(This->head, This->index); |
| ++fetched; |
| ++rgDocumentMgr; |
| } |
| |
| if (pcFetched) *pcFetched = fetched; |
| return fetched == ulCount ? S_OK : S_FALSE; |
| } |
| |
| static HRESULT WINAPI EnumTfDocumentMgr_Skip( IEnumTfDocumentMgrs* iface, ULONG celt) |
| { |
| EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface); |
| ULONG i; |
| |
| TRACE("(%p)\n",This); |
| for(i = 0; i < celt && This->index != NULL; i++) |
| This->index = list_next(This->head, This->index); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI EnumTfDocumentMgr_Reset( IEnumTfDocumentMgrs* iface) |
| { |
| EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface); |
| TRACE("(%p)\n",This); |
| This->index = list_head(This->head); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI EnumTfDocumentMgr_Clone( IEnumTfDocumentMgrs *iface, |
| IEnumTfDocumentMgrs **ppenum) |
| { |
| EnumTfDocumentMgr *This = impl_from_IEnumTfDocumentMgrs(iface); |
| HRESULT res; |
| |
| TRACE("(%p)\n",This); |
| |
| if (ppenum == NULL) return E_POINTER; |
| |
| res = EnumTfDocumentMgr_Constructor(This->head, ppenum); |
| if (SUCCEEDED(res)) |
| { |
| EnumTfDocumentMgr *new_This = impl_from_IEnumTfDocumentMgrs(*ppenum); |
| new_This->index = This->index; |
| } |
| return res; |
| } |
| |
| static const IEnumTfDocumentMgrsVtbl EnumTfDocumentMgrsVtbl = |
| { |
| EnumTfDocumentMgr_QueryInterface, |
| EnumTfDocumentMgr_AddRef, |
| EnumTfDocumentMgr_Release, |
| EnumTfDocumentMgr_Clone, |
| EnumTfDocumentMgr_Next, |
| EnumTfDocumentMgr_Reset, |
| EnumTfDocumentMgr_Skip |
| }; |
| |
| static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut) |
| { |
| EnumTfDocumentMgr *This; |
| |
| This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfDocumentMgr)); |
| if (This == NULL) |
| return E_OUTOFMEMORY; |
| |
| This->IEnumTfDocumentMgrs_iface.lpVtbl= &EnumTfDocumentMgrsVtbl; |
| This->refCount = 1; |
| This->head = head; |
| This->index = list_head(This->head); |
| |
| TRACE("returning %p\n", &This->IEnumTfDocumentMgrs_iface); |
| *ppOut = &This->IEnumTfDocumentMgrs_iface; |
| return S_OK; |
| } |
| |
| void ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *iface, ITfDocumentMgr *mgr) |
| { |
| ThreadMgr *This = impl_from_ITfThreadMgrEx((ITfThreadMgrEx *)iface); |
| struct list *cursor; |
| LIST_FOR_EACH(cursor, &This->CreatedDocumentMgrs) |
| { |
| DocumentMgrEntry *mgrentry = LIST_ENTRY(cursor,DocumentMgrEntry,entry); |
| if (mgrentry->docmgr == mgr) |
| { |
| list_remove(cursor); |
| HeapFree(GetProcessHeap(),0,mgrentry); |
| return; |
| } |
| } |
| FIXME("ITfDocumentMgr %p not found in this thread\n",mgr); |
| } |