user32: Create and destroy the default IME window implicitly.

Signed-off-by: Akihiro Sagawa <sagawa.aki@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Akihiro Sagawa 2016-08-23 22:13:27 +09:00 committed by Alexandre Julliard
parent 876d5de0b4
commit 911d269be8
7 changed files with 112 additions and 25 deletions

View File

@ -96,6 +96,7 @@ typedef struct _tagIMMThreadData {
HIMC defaultContext;
HWND hwndDefault;
BOOL disableIME;
DWORD windowRefs;
} IMMThreadData;
static struct list ImmHklList = LIST_INIT(ImmHklList);
@ -1618,27 +1619,51 @@ BOOL WINAPI ImmGetConversionStatus(
return TRUE;
}
/***********************************************************************
* ImmGetDefaultIMEWnd (IMM32.@)
*/
HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
static BOOL needs_ime_window(HWND hwnd)
{
HWND ret, new = NULL;
IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
WCHAR classW[8];
if (GetClassNameW(hwnd, classW, sizeof(classW)/sizeof(classW[0])) &&
!strcmpW(classW, szwIME))
return FALSE;
if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE;
return TRUE;
}
/***********************************************************************
* __wine_register_window (IMM32.@)
*/
BOOL WINAPI __wine_register_window(HWND hwnd)
{
HWND new = NULL;
IMMThreadData *thread_data;
TRACE("(%p)\n", hwnd);
if (!needs_ime_window(hwnd))
return FALSE;
thread_data = IMM_GetThreadData(hwnd, 0);
if (!thread_data)
return NULL;
if (thread_data->hwndDefault == NULL && thread_data->threadID == GetCurrentThreadId())
return FALSE;
if (thread_data->disableIME || disable_ime)
{
TRACE("IME for this thread is disabled\n");
LeaveCriticalSection(&threaddata_cs);
return FALSE;
}
thread_data->windowRefs++;
TRACE("windowRefs=%u, hwndDefault=%p\n",
thread_data->windowRefs, thread_data->hwndDefault);
/* Create default IME window */
if (thread_data->windowRefs == 1)
{
if (thread_data->disableIME || disable_ime)
{
TRACE("IME for this thread is disabled\n");
LeaveCriticalSection(&threaddata_cs);
return 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);
/* thread_data is in the current thread so we can assume it's still valid */
EnterCriticalSection(&threaddata_cs);
/* See if anyone beat us */
@ -1646,16 +1671,56 @@ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
{
thread_data->hwndDefault = new;
new = NULL;
TRACE("Default is %p\n", thread_data->hwndDefault);
}
}
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 TRUE;
}
/***********************************************************************
* __wine_unregister_window (IMM32.@)
*/
void WINAPI __wine_unregister_window(HWND hwnd)
{
HWND to_destroy = 0;
IMMThreadData *thread_data;
TRACE("(%p)\n", hwnd);
thread_data = IMM_GetThreadData(hwnd, 0);
if (!thread_data) return;
thread_data->windowRefs--;
TRACE("windowRefs=%u, hwndDefault=%p\n",
thread_data->windowRefs, thread_data->hwndDefault);
/* Destroy default IME window */
if (thread_data->windowRefs == 0 && thread_data->hwndDefault)
{
to_destroy = thread_data->hwndDefault;
thread_data->hwndDefault = NULL;
}
LeaveCriticalSection(&threaddata_cs);
if (to_destroy) DestroyWindow( to_destroy );
}
/***********************************************************************
* ImmGetDefaultIMEWnd (IMM32.@)
*/
HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
{
HWND ret;
IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
if (!thread_data)
return NULL;
ret = thread_data->hwndDefault;
LeaveCriticalSection(&threaddata_cs);
TRACE("Default is %p\n",ret);
return ret;
}

View File

@ -114,3 +114,5 @@
################################################################
# Wine internal extensions
@ stdcall __wine_get_ui_window(ptr)
@ stdcall __wine_register_window(long)
@ stdcall __wine_unregister_window(long)

View File

@ -207,7 +207,6 @@ static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case FIRST_WINDOW:
case SECOND_WINDOW:
case CREATE_CANCEL:
todo_wine_if(test_phase == FIRST_WINDOW || test_phase == CREATE_CANCEL)
ok(default_ime_wnd != NULL, "expected IME window existence\n");
break;
case IME_DISABLED:
@ -223,7 +222,6 @@ static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case FIRST_WINDOW:
case SECOND_WINDOW:
case CREATE_CANCEL:
todo_wine_if(test_phase == FIRST_WINDOW || test_phase == CREATE_CANCEL)
ok(default_ime_wnd != NULL, "expected IME window existence\n");
break;
case IME_DISABLED:
@ -952,9 +950,9 @@ static DWORD WINAPI test_default_ime_window_cb(void *arg)
240, 24, hwnd, NULL, GetModuleHandleW(NULL), NULL);
}
ime_wnd = get_ime_window();
todo_wine ok(ime_wnd != NULL, "Expected IME window existence\n");
ok(ime_wnd != NULL, "Expected IME window existence\n");
default_ime_wnd = ImmGetDefaultIMEWnd(hwnd1);
todo_wine ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd);
ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd);
test_phase = SECOND_WINDOW;
hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test",
@ -962,7 +960,7 @@ static DWORD WINAPI test_default_ime_window_cb(void *arg)
CW_USEDEFAULT, CW_USEDEFAULT,
240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
DestroyWindow(hwnd2);
todo_wine ok(IsWindow(ime_wnd) ||
ok(IsWindow(ime_wnd) ||
broken(!testcase->visible /* Vista */) ||
broken(!testcase->top_level_window /* Vista */) ,
"Expected IME window existence\n");
@ -1000,9 +998,9 @@ static DWORD WINAPI test_default_ime_window_cancel_cb(void *arg)
CW_USEDEFAULT, CW_USEDEFAULT,
240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL);
ime_wnd = get_ime_window();
todo_wine ok(ime_wnd != NULL, "Expected IME window existence\n");
ok(ime_wnd != NULL, "Expected IME window existence\n");
default_ime_wnd = ImmGetDefaultIMEWnd(hwnd2);
todo_wine ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd);
ok(ime_wnd == default_ime_wnd, "Expected %p, got %p\n", ime_wnd, default_ime_wnd);
DestroyWindow(hwnd2);
ok(!IsWindow(ime_wnd), "Expected no IME windows\n");

View File

@ -41,6 +41,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(win);
#define IMM_INIT_MAGIC 0x19650412
static HWND (WINAPI *imm_get_ui_window)(HKL);
BOOL (WINAPI *imm_register_window)(HWND) = NULL;
void (WINAPI *imm_unregister_window)(HWND) = NULL;
/* MSIME messages */
static UINT WM_MSIME_SERVICE;
@ -684,6 +686,8 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic)
/* this part is not compatible with native imm32.dll */
imm_get_ui_window = (void*)GetProcAddress(imm32, "__wine_get_ui_window");
imm_register_window = (void*)GetProcAddress(imm32, "__wine_register_window");
imm_unregister_window = (void*)GetProcAddress(imm32, "__wine_unregister_window");
if (!imm_get_ui_window)
FIXME("native imm32.dll not supported\n");
return TRUE;

View File

@ -196,6 +196,8 @@ struct user_thread_info
C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) );
extern INT global_key_state_counter DECLSPEC_HIDDEN;
extern BOOL (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN;
extern void (WINAPI *imm_unregister_window)(HWND) DECLSPEC_HIDDEN;
struct user_key_state_info
{

View File

@ -958,6 +958,13 @@ LRESULT WIN_DestroyWindow( HWND hwnd )
TRACE("%p\n", hwnd );
/* destroy default IME window */
if (win_set_flags( hwnd, 0, WIN_HAS_IME_WIN ) & WIN_HAS_IME_WIN)
{
TRACE("unregister IME window for %p\n", hwnd);
imm_unregister_window( hwnd );
}
/* free child windows */
if ((list = WIN_ListChildren( hwnd )))
{
@ -1604,6 +1611,14 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module,
goto failed;
}
/* create default IME window */
if (imm_register_window && !is_desktop_window( hwnd ) && imm_register_window( hwnd ))
{
TRACE("register IME window for %p\n", hwnd);
win_set_flags( hwnd, WIN_HAS_IME_WIN, 0 );
}
/* send WM_NCCALCSIZE */
if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))

View File

@ -77,6 +77,7 @@ typedef struct tagWND
#define WIN_ISUNICODE 0x0010 /* Window is Unicode */
#define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */
#define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */
#define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */
/* Window functions */
extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN;