Aric Stewart : msctf: Implement ITfThreadMgr::AssociateFocus.

Alexandre Julliard julliard at winehq.org
Wed Sep 2 09:30:25 CDT 2009


Module: wine
Branch: master
Commit: 81118f7f06a40f71ccb263808a1ed47ad63883b9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=81118f7f06a40f71ccb263808a1ed47ad63883b9

Author: Aric Stewart <aric at codeweavers.com>
Date:   Tue Sep  1 07:07:57 2009 -0500

msctf: Implement ITfThreadMgr::AssociateFocus.

---

 dlls/msctf/threadmgr.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/dlls/msctf/threadmgr.c b/dlls/msctf/threadmgr.c
index 4b21b56..0661fec 100644
--- a/dlls/msctf/threadmgr.c
+++ b/dlls/msctf/threadmgr.c
@@ -71,6 +71,13 @@ typedef struct tagDocumentMgrs
     ITfDocumentMgr  *docmgr;
 } DocumentMgrEntry;
 
+typedef struct tagAssociatedWindow
+{
+    struct list     entry;
+    HWND            hwnd;
+    ITfDocumentMgr  *docmgr;
+} AssociatedWindow;
+
 typedef struct tagACLMulti {
     const ITfThreadMgrVtbl *ThreadMgrVtbl;
     const ITfSourceVtbl *SourceVtbl;
@@ -98,6 +105,9 @@ typedef struct tagACLMulti {
     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;
@@ -116,6 +126,7 @@ typedef struct tagEnumTfDocumentMgr {
 } EnumTfDocumentMgr;
 
 static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut);
+LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam);
 
 static inline ThreadMgr *impl_from_ITfSourceVtbl(ITfSource *iface)
 {
@@ -142,6 +153,22 @@ static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *
     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ThreadMgrEventSinkVtbl));
 }
 
+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 void free_sink(ThreadMgrSink *sink)
 {
         IUnknown_Release(sink->interfaces.pIUnknown);
@@ -152,6 +179,10 @@ 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)
@@ -211,6 +242,13 @@ static void ThreadMgr_Destructor(ThreadMgr *This)
         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);
@@ -406,9 +444,43 @@ static HRESULT WINAPI ThreadMgr_SetFocus( ITfThreadMgr* iface, ITfDocumentMgr *p
 static HRESULT WINAPI ThreadMgr_AssociateFocus( ITfThreadMgr* iface, HWND hwnd,
 ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev)
 {
+    struct list *cursor, *cursor2;
     ThreadMgr *This = (ThreadMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    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( ITfThreadMgr* iface, BOOL *pfThreadFocus)
@@ -1132,6 +1204,7 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
 
     list_init(&This->CurrentPreservedKeys);
     list_init(&This->CreatedDocumentMgrs);
+    list_init(&This->AssociatedFocusWindows);
 
     list_init(&This->ActiveLanguageProfileNotifySink);
     list_init(&This->DisplayAttributeNotifySink);
@@ -1305,3 +1378,39 @@ void ThreadMgr_OnDocumentMgrDestruction(ITfThreadMgr *tm, ITfDocumentMgr *mgr)
     }
     FIXME("ITfDocumenMgr %p not found in this thread\n",mgr);
 }
+
+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((ITfThreadMgr*)This, wnd->docmgr);
+                break;
+            }
+        }
+    }
+
+    return CallNextHookEx(This->focusHook, nCode, wParam, lParam);
+}




More information about the wine-cvs mailing list