imm32: Move thread data from TLSEntry to an internal list.

This commit is contained in:
Aric Stewart 2015-02-25 11:45:11 -06:00 committed by Alexandre Julliard
parent 9491044e44
commit e28fc1177a

View File

@ -89,12 +89,14 @@ typedef struct _tagTRANSMSG {
} TRANSMSG, *LPTRANSMSG; } TRANSMSG, *LPTRANSMSG;
typedef struct _tagIMMThreadData { typedef struct _tagIMMThreadData {
struct list entry;
DWORD threadID;
HIMC defaultContext; HIMC defaultContext;
HWND hwndDefault; HWND hwndDefault;
} IMMThreadData; } IMMThreadData;
static DWORD tlsIndex = 0;
static struct list ImmHklList = LIST_INIT(ImmHklList); static struct list ImmHklList = LIST_INIT(ImmHklList);
static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0}; static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
@ -104,6 +106,15 @@ static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r'
static const WCHAR szwIME[] = {'I','M','E',0}; static const WCHAR szwIME[] = {'I','M','E',0};
static CRITICAL_SECTION threaddata_cs;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &threaddata_cs,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
};
static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
#define is_himc_ime_unicode(p) (p->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE) #define is_himc_ime_unicode(p) (p->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE)
#define is_kbd_ime_unicode(p) (p->imeInfo.fdwProperty & IME_PROP_UNICODE) #define is_kbd_ime_unicode(p) (p->imeInfo.fdwProperty & IME_PROP_UNICODE)
@ -211,29 +222,47 @@ static DWORD convert_candidatelist_AtoW(
return ret; return ret;
} }
static IMMThreadData* IMM_GetThreadData(void) static IMMThreadData* IMM_GetThreadData(DWORD id)
{ {
IMMThreadData* data = TlsGetValue(tlsIndex); IMMThreadData *data;
if (!data)
if (!id) id = GetCurrentThreadId();
EnterCriticalSection(&threaddata_cs);
LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
{ {
if (data->threadID == id)
return data;
}
data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(IMMThreadData)); sizeof(IMMThreadData));
TlsSetValue(tlsIndex,data); data->threadID = id;
TRACE("Thread Data Created\n"); list_add_head(&ImmThreadDataList,&data->entry);
} TRACE("Thread Data Created (%x)\n",id);
return data; return data;
} }
static void IMM_FreeThreadData(void) static void IMM_FreeThreadData(void)
{ {
IMMThreadData* data = TlsGetValue(tlsIndex); IMMThreadData *data;
if (data)
EnterCriticalSection(&threaddata_cs);
LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
{ {
if (data->threadID == GetCurrentThreadId())
{
list_remove(&data->entry);
LeaveCriticalSection(&threaddata_cs);
IMM_DestroyContext(data->defaultContext); IMM_DestroyContext(data->defaultContext);
DestroyWindow(data->hwndDefault); DestroyWindow(data->hwndDefault);
HeapFree(GetProcessHeap(),0,data); HeapFree(GetProcessHeap(),0,data);
TRACE("Thread Data Destroyed\n"); TRACE("Thread Data Destroyed\n");
return;
} }
}
LeaveCriticalSection(&threaddata_cs);
} }
static HMODULE load_graphics_driver(void) static HMODULE load_graphics_driver(void)
@ -368,12 +397,8 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
switch (fdwReason) switch (fdwReason)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
tlsIndex = TlsAlloc();
if (tlsIndex == TLS_OUT_OF_INDEXES)
return FALSE;
if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC)) if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
{ {
TlsFree(tlsIndex);
return FALSE; return FALSE;
} }
break; break;
@ -386,7 +411,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
if (lpReserved) break; if (lpReserved) break;
IMM_FreeThreadData(); IMM_FreeThreadData();
IMM_FreeAllImmHkl(); IMM_FreeAllImmHkl();
TlsFree(tlsIndex);
break; break;
} }
return TRUE; return TRUE;
@ -442,6 +466,34 @@ static InputContextData* get_imc_data(HIMC hIMC)
return data; return data;
} }
static IMMThreadData* IMM_GetInitializedThreadData(void)
{
IMMThreadData* thread_data = IMM_GetThreadData(0);
if (!thread_data)
return NULL;
if (!thread_data->defaultContext)
{
HIMC defaultContext;
LeaveCriticalSection(&threaddata_cs);
defaultContext = ImmCreateContext();
thread_data = IMM_GetThreadData(0);
if (!thread_data)
{
IMM_DestroyContext(defaultContext);
return NULL;
}
if (thread_data->defaultContext) /* someone beat us */
IMM_DestroyContext(defaultContext);
else
thread_data->defaultContext = defaultContext;
}
return thread_data;
}
/*********************************************************************** /***********************************************************************
* ImmAssociateContext (IMM32.@) * ImmAssociateContext (IMM32.@)
*/ */
@ -449,31 +501,33 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
{ {
HIMC old = NULL; HIMC old = NULL;
InputContextData *data = get_imc_data(hIMC); InputContextData *data = get_imc_data(hIMC);
IMMThreadData* thread_data = NULL;
TRACE("(%p, %p):\n", hWnd, hIMC); TRACE("(%p, %p):\n", hWnd, hIMC);
if(hIMC && !data) if(hIMC && !data)
return NULL; return NULL;
if (!IMM_GetThreadData()->defaultContext)
IMM_GetThreadData()->defaultContext = ImmCreateContext();
/* /*
* If already associated just return * If already associated just return
*/ */
if (hIMC && data->IMC.hWnd == hWnd) if (hIMC && data->IMC.hWnd == hWnd)
return hIMC; return hIMC;
thread_data = IMM_GetInitializedThreadData();
if (!thread_data)
return NULL;
if (hWnd) if (hWnd)
{ {
old = RemovePropW(hWnd,szwWineIMCProperty); old = RemovePropW(hWnd,szwWineIMCProperty);
if (old == NULL) if (old == NULL)
old = IMM_GetThreadData()->defaultContext; old = thread_data->defaultContext;
else if (old == (HIMC)-1) else if (old == (HIMC)-1)
old = NULL; old = NULL;
if (hIMC != IMM_GetThreadData()->defaultContext) if (hIMC != thread_data->defaultContext)
{ {
if (hIMC == NULL) /* Meaning disable imm for that window*/ if (hIMC == NULL) /* Meaning disable imm for that window*/
SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1); SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
@ -488,6 +542,7 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
old_data->IMC.hWnd = NULL; old_data->IMC.hWnd = NULL;
} }
} }
LeaveCriticalSection(&threaddata_cs);
if (!hIMC) if (!hIMC)
return old; return old;
@ -529,12 +584,20 @@ static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
*/ */
BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
{ {
IMMThreadData* thread_data = NULL;
HIMC defaultContext = NULL;
TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags); TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
if (!IMM_GetThreadData()->defaultContext) thread_data = IMM_GetInitializedThreadData();
IMM_GetThreadData()->defaultContext = ImmCreateContext(); if (!thread_data)
return FALSE;
if (!hWnd) return FALSE; defaultContext = thread_data->defaultContext;
LeaveCriticalSection(&threaddata_cs);
if (!hWnd)
return FALSE;
switch (dwFlags) switch (dwFlags)
{ {
@ -542,7 +605,7 @@ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
ImmAssociateContext(hWnd,hIMC); ImmAssociateContext(hWnd,hIMC);
return TRUE; return TRUE;
case IACE_DEFAULT: case IACE_DEFAULT:
ImmAssociateContext(hWnd,IMM_GetThreadData()->defaultContext); ImmAssociateContext(hWnd,defaultContext);
return TRUE; return TRUE;
case IACE_IGNORENOCONTEXT: case IACE_IGNORENOCONTEXT:
if (GetPropW(hWnd,szwWineIMCProperty)) if (GetPropW(hWnd,szwWineIMCProperty))
@ -717,7 +780,11 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
*/ */
BOOL WINAPI ImmDestroyContext(HIMC hIMC) BOOL WINAPI ImmDestroyContext(HIMC hIMC)
{ {
if (hIMC != IMM_GetThreadData()->defaultContext) IMMThreadData* thread_data = IMM_GetThreadData(0);
HIMC defaultContext = thread_data->defaultContext;
LeaveCriticalSection(&threaddata_cs);
if (hIMC != defaultContext)
return IMM_DestroyContext(hIMC); return IMM_DestroyContext(hIMC);
else else
return FALSE; return FALSE;
@ -1383,6 +1450,7 @@ BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
HIMC WINAPI ImmGetContext(HWND hWnd) HIMC WINAPI ImmGetContext(HWND hWnd)
{ {
HIMC rc; HIMC rc;
IMMThreadData* thread_data;
TRACE("%p\n", hWnd); TRACE("%p\n", hWnd);
@ -1391,20 +1459,24 @@ HIMC WINAPI ImmGetContext(HWND hWnd)
SetLastError(ERROR_INVALID_WINDOW_HANDLE); SetLastError(ERROR_INVALID_WINDOW_HANDLE);
return NULL; return NULL;
} }
if (!IMM_GetThreadData()->defaultContext)
IMM_GetThreadData()->defaultContext = ImmCreateContext(); thread_data = IMM_GetInitializedThreadData();
if (!thread_data)
return NULL;
rc = GetPropW(hWnd,szwWineIMCProperty); rc = GetPropW(hWnd,szwWineIMCProperty);
if (rc == (HIMC)-1) if (rc == (HIMC)-1)
rc = NULL; rc = NULL;
else if (rc == NULL) else if (rc == NULL)
rc = IMM_GetThreadData()->defaultContext; rc = thread_data->defaultContext;
if (rc) if (rc)
{ {
InputContextData *data = rc; InputContextData *data = rc;
data->IMC.hWnd = hWnd; data->IMC.hWnd = hWnd;
} }
LeaveCriticalSection(&threaddata_cs);
TRACE("returning %p\n", rc); TRACE("returning %p\n", rc);
return rc; return rc;
@ -1512,11 +1584,35 @@ BOOL WINAPI ImmGetConversionStatus(
*/ */
HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
{ {
if (IMM_GetThreadData()->hwndDefault == NULL) HWND ret, new = NULL;
IMM_GetThreadData()->hwndDefault = CreateWindowExW( WS_EX_TOOLWINDOW, IMMThreadData* thread_data = IMM_GetThreadData(0);
if (!thread_data)
return NULL;
if (thread_data->hwndDefault == NULL)
{
/* Do not create the window inside of a critical section */
LeaveCriticalSection(&threaddata_cs);
new = CreateWindowExW( WS_EX_TOOLWINDOW,
szwIME, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0); szwIME, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0);
TRACE("Default is %p\n",IMM_GetThreadData()->hwndDefault); thread_data = IMM_GetThreadData(0);
return IMM_GetThreadData()->hwndDefault; if (!thread_data)
return NULL;
/* See if anyone beat us */
if (thread_data->hwndDefault == NULL)
{
thread_data->hwndDefault = new;
new = NULL;
}
}
ret = thread_data->hwndDefault;
LeaveCriticalSection(&threaddata_cs);
TRACE("Default is %p\n",ret);
/* Clean up an unused new window outside of the critical section */
if (new != NULL)
{
DestroyWindow(new);
}
return ret;
} }
/*********************************************************************** /***********************************************************************