diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index c5b5895bec8..89541612ea2 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -100,14 +100,6 @@ typedef struct _tagTRANSMSG { LPARAM lParam; } TRANSMSG, *LPTRANSMSG; -typedef struct _tagIMMThreadData { - struct list entry; - DWORD threadID; - HWND hwndDefault; - BOOL disableIME; - DWORD windowRefs; -} IMMThreadData; - struct coinit_spy { IInitializeSpy IInitializeSpy_iface; @@ -123,20 +115,9 @@ struct coinit_spy }; static struct list ImmHklList = LIST_INIT(ImmHklList); -static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList); static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx"; -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 }; -static BOOL disable_ime; - static inline BOOL is_himc_ime_unicode(const InputContextData *data) { return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE); @@ -412,38 +393,6 @@ static void imm_coinit_thread(void) spy->apt_flags |= IMM_APT_CREATED; } -static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread) -{ - IMMThreadData *data; - DWORD process; - - if (hwnd) - { - if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL; - if (process != GetCurrentProcessId()) return NULL; - } - else if (thread) - { - HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread); - if (!h) return NULL; - process = GetProcessIdOfThread(h); - CloseHandle(h); - if (process != GetCurrentProcessId()) return NULL; - } - else - thread = GetCurrentThreadId(); - - EnterCriticalSection(&threaddata_cs); - LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry) - if (data->threadID == thread) return data; - - data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); - data->threadID = thread; - list_add_head(&ImmThreadDataList,&data->entry); - TRACE("Thread Data Created (%lx)\n",thread); - return data; -} - static BOOL IMM_IsDefaultContext(HIMC imc) { InputContextData *data = get_imc_data(imc); @@ -490,21 +439,6 @@ static BOOL free_input_context_data(HIMC hIMC) static void IMM_FreeThreadData(void) { struct coinit_spy *spy; - IMMThreadData *data; - - EnterCriticalSection(&threaddata_cs); - LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry) - { - if (data->threadID == GetCurrentThreadId()) - { - list_remove(&data->entry); - LeaveCriticalSection(&threaddata_cs); - HeapFree(GetProcessHeap(),0,data); - TRACE("Thread Data Destroyed\n"); - return; - } - } - LeaveCriticalSection(&threaddata_cs); free_input_context_data(NtUserGetThreadInfo()->default_imc); if ((spy = get_thread_coinit_spy())) @@ -981,62 +915,6 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) return FALSE; } -static HWND imm_detach_default_window(IMMThreadData *thread_data) -{ - HWND to_destroy; - - to_destroy = thread_data->hwndDefault; - thread_data->hwndDefault = NULL; - thread_data->windowRefs = 0; - return to_destroy; -} - -/*********************************************************************** - * ImmDisableIME (IMM32.@) - */ -BOOL WINAPI ImmDisableIME(DWORD idThread) -{ - IMMThreadData *thread_data; - HWND to_destroy; - - if (idThread == (DWORD)-1) - { - disable_ime = TRUE; - - while (1) - { - to_destroy = 0; - EnterCriticalSection(&threaddata_cs); - LIST_FOR_EACH_ENTRY(thread_data, &ImmThreadDataList, IMMThreadData, entry) - { - if (thread_data->hwndDefault) - { - to_destroy = imm_detach_default_window(thread_data); - break; - } - } - LeaveCriticalSection(&threaddata_cs); - - if (!to_destroy) - break; - DestroyWindow(to_destroy); - } - } - else if (!idThread || idThread == GetCurrentThreadId()) - { - thread_data = IMM_GetThreadData(NULL, idThread); - if (!thread_data) return FALSE; - thread_data->disableIME = TRUE; - to_destroy = imm_detach_default_window(thread_data); - LeaveCriticalSection(&threaddata_cs); - - if (to_destroy) - DestroyWindow(to_destroy); - } - else return FALSE; - return TRUE; -} - /*********************************************************************** * ImmEnumRegisterWordA (IMM32.@) */ @@ -1816,107 +1694,12 @@ BOOL WINAPI ImmGetConversionStatus( return TRUE; } -static BOOL needs_ime_window(HWND hwnd) -{ - WCHAR classW[8]; - - if (GetClassNameW(hwnd, classW, ARRAY_SIZE(classW)) && !lstrcmpW(classW, L"IME")) - 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 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=%lu, hwndDefault=%p\n", - thread_data->windowRefs, thread_data->hwndDefault); - - /* Create default IME window */ - if (thread_data->windowRefs == 1) - { - /* Do not create the window inside of a critical section */ - LeaveCriticalSection(&threaddata_cs); - new = CreateWindowExW( 0, L"IME", L"Default IME", - WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS, - 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 */ - if (thread_data->hwndDefault == NULL) - { - thread_data->hwndDefault = new; - new = NULL; - TRACE("Default is %p\n", thread_data->hwndDefault); - } - } - - LeaveCriticalSection(&threaddata_cs); - - /* 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=%lu, hwndDefault=%p\n", - thread_data->windowRefs, thread_data->hwndDefault); - - /* Destroy default IME window */ - if (thread_data->windowRefs == 0) - to_destroy = imm_detach_default_window(thread_data); - 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; + return NtUserGetDefaultImeWindow(hWnd); } /*********************************************************************** diff --git a/dlls/imm32/imm32.spec b/dlls/imm32/imm32.spec index e95731183ea..70b8aef3a95 100644 --- a/dlls/imm32/imm32.spec +++ b/dlls/imm32/imm32.spec @@ -9,8 +9,8 @@ @ stdcall ImmDestroyContext(long) @ stdcall ImmDestroyIMCC(long) @ stdcall ImmDestroySoftKeyboard(long) -@ stdcall ImmDisableIME(long) -@ stdcall ImmDisableIme(long) ImmDisableIME +@ stdcall ImmDisableIME(long) NtUserDisableThreadIme +@ stdcall ImmDisableIme(long) NtUserDisableThreadIme @ stdcall ImmDisableLegacyIME() @ stdcall ImmDisableTextFrameService(long) @ stdcall ImmEnumInputContext(long ptr long) @@ -115,5 +115,3 @@ ################################################################ # Wine internal extensions @ stdcall __wine_ime_wnd_proc(long long long long long) -@ stdcall __wine_register_window(long) -@ stdcall __wine_unregister_window(long) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index c5409ce1708..17369ca9102 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2426,11 +2426,9 @@ static void test_ImmDisableIME(void) ok(IsWindow(def), "not a window\n"); def2 = ImmGetDefaultIMEWnd(hwnd); - todo_wine ok(def2 == def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2); ok(IsWindow(def), "not a window\n"); msg_spy_pump_msg_queue(); - todo_wine ok(!IsWindow(def), "window is still valid\n"); def = ImmGetDefaultIMEWnd(hwnd); ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index 31ec85c36eb..64a300f83ef 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -39,8 +39,6 @@ BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL); #define IMM_INIT_MAGIC 0x19650412 static LRESULT (WINAPI *imm_ime_wnd_proc)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi); -BOOL (WINAPI *imm_register_window)(HWND) = NULL; -void (WINAPI *imm_unregister_window)(HWND) = NULL; /* USER signal proc flags and codes */ /* See UserSignalProc for comments */ @@ -328,8 +326,6 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) /* this part is not compatible with native imm32.dll */ imm_ime_wnd_proc = (void*)GetProcAddress(imm32, "__wine_ime_wnd_proc"); - imm_register_window = (void*)GetProcAddress(imm32, "__wine_register_window"); - imm_unregister_window = (void*)GetProcAddress(imm32, "__wine_unregister_window"); if (!imm_ime_wnd_proc) FIXME("native imm32.dll not supported\n"); return TRUE; diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 26427bd2cf6..ae6a0d4c8e4 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -119,22 +119,6 @@ static void dpiaware_init(void) } } -static void CDECL notify_ime( HWND hwnd, UINT param ) -{ - HWND ime_default = ImmGetDefaultIMEWnd( hwnd ); - if (ime_default) SendMessageW( ime_default, WM_IME_INTERNAL, param, HandleToUlong(hwnd) ); -} - -static BOOL WINAPI register_imm( HWND hwnd ) -{ - return imm_register_window( hwnd ); -} - -static void WINAPI unregister_imm( HWND hwnd ) -{ - imm_unregister_window( hwnd ); -} - static NTSTATUS try_finally( NTSTATUS (CDECL *func)( void *), void *arg, void (CALLBACK *finally_func)( BOOL )) { @@ -152,11 +136,8 @@ static const struct user_callbacks user_funcs = ImmProcessKey, ImmTranslateMessage, NtWaitForMultipleObjects, - notify_ime, post_dde_message, unpack_dde_message, - register_imm, - unregister_imm, try_finally, }; diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 3be5b84b41b..e637bf01f5e 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -47,9 +47,6 @@ struct wm_char_mapping_data MSG get_msg; }; -extern BOOL (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN; -extern void (WINAPI *imm_unregister_window)(HWND) DECLSPEC_HIDDEN; - static inline struct user_thread_info *get_user_thread_info(void) { return (struct user_thread_info *)NtCurrentTeb()->Win32ClientInfo; diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 5af9e586e01..6a3f039bc3b 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -1007,6 +1007,18 @@ WORD get_class_word( HWND hwnd, INT offset ) return retvalue; } +BOOL needs_ime_window( HWND hwnd ) +{ + static const WCHAR imeW[] = {'I','M','E',0}; + CLASS *class; + BOOL ret; + + if (!(class = get_class_ptr( hwnd, FALSE ))) return FALSE; + ret = !(class->style & CS_IME) && wcscmp( imeW, class->name ); + release_class_ptr( class ); + return ret; +} + static void register_builtins(void) { void *ret_ptr; diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 9aab651e551..fddaf898761 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1157,6 +1157,7 @@ static struct unix_funcs unix_funcs = NtUserDestroyCursor, NtUserDestroyMenu, NtUserDestroyWindow, + NtUserDisableThreadIme, NtUserDispatchMessage, NtUserDragDetect, NtUserDrawCaptionTemp, diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index c0fe5887ffd..94621bb2a5c 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -1,6 +1,8 @@ /* * Input Context implementation * + * Copyright 1998 Patrik Stridvall + * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart * Copyright 2022 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or @@ -22,6 +24,7 @@ #pragma makedep unix #endif +#include #include "win32u_private.h" #include "ntuser_private.h" #include "wine/debug.h" @@ -36,6 +39,18 @@ struct imc UINT_PTR client_ptr; }; +struct imm_thread_data +{ + struct list entry; + DWORD thread_id; + HWND default_hwnd; + BOOL disable_ime; + UINT window_cnt; +}; + +static struct list thread_data_list = LIST_INIT( thread_data_list ); +static pthread_mutex_t imm_mutex = PTHREAD_MUTEX_INITIALIZER; +static BOOL disable_ime; static struct imc *get_imc_ptr( HIMC handle ) { @@ -215,3 +230,164 @@ HIMC get_window_input_context( HWND hwnd ) release_win_ptr( win ); return ret; } + +static HWND detach_default_window( struct imm_thread_data *thread_data ) +{ + HWND hwnd = thread_data->default_hwnd; + thread_data->default_hwnd = NULL; + thread_data->window_cnt = 0; + return hwnd; +} + +static struct imm_thread_data *get_imm_thread_data(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + if (!thread_info->imm_thread_data) + { + struct imm_thread_data *data; + if (!(data = calloc( 1, sizeof( *data )))) return NULL; + data->thread_id = GetCurrentThreadId(); + + pthread_mutex_lock( &imm_mutex ); + list_add_tail( &thread_data_list, &data->entry ); + pthread_mutex_unlock( &imm_mutex ); + + thread_info->imm_thread_data = data; + } + return thread_info->imm_thread_data; +} + +BOOL register_imm_window( HWND hwnd ) +{ + struct imm_thread_data *thread_data; + + TRACE( "(%p)\n", hwnd ); + + if (disable_ime || !needs_ime_window( hwnd )) + return FALSE; + + thread_data = get_imm_thread_data(); + if (!thread_data || thread_data->disable_ime) + return FALSE; + + TRACE( "window_cnt=%u, default_hwnd=%p\n", thread_data->window_cnt + 1, thread_data->default_hwnd ); + + /* Create default IME window */ + if (!thread_data->window_cnt++) + { + UNICODE_STRING class_name, name; + static const WCHAR imeW[] = {'I','M','E',0}; + static const WCHAR default_imeW[] = {'D','e','f','a','u','l','t',' ','I','M','E',0}; + + RtlInitUnicodeString( &class_name, imeW ); + RtlInitUnicodeString( &name, default_imeW ); + thread_data->default_hwnd = NtUserCreateWindowEx( 0, &class_name, &class_name, &name, + WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, FALSE ); + } + + return TRUE; +} + +void unregister_imm_window( HWND hwnd ) +{ + struct imm_thread_data *thread_data = get_user_thread_info()->imm_thread_data; + + if (!thread_data) return; + if (thread_data->default_hwnd == hwnd) + { + detach_default_window( thread_data ); + return; + } + + if (!(win_set_flags( hwnd, 0, WIN_HAS_IME_WIN ) & WIN_HAS_IME_WIN)) return; + + /* destroy default IME window */ + TRACE( "unregister IME window for %p\n", hwnd ); + if (!--thread_data->window_cnt) + { + HWND destroy_hwnd = detach_default_window( thread_data ); + if (destroy_hwnd) NtUserDestroyWindow( destroy_hwnd ); + } +} + +/*********************************************************************** + * NtUserDisableThreadIme (win32u.@) + */ +BOOL WINAPI NtUserDisableThreadIme( DWORD thread_id ) +{ + struct imm_thread_data *thread_data; + + if (thread_id == -1) + { + disable_ime = TRUE; + + pthread_mutex_lock( &imm_mutex ); + LIST_FOR_EACH_ENTRY( thread_data, &thread_data_list, struct imm_thread_data, entry ) + { + if (thread_data->thread_id == GetCurrentThreadId()) continue; + if (!thread_data->default_hwnd) continue; + NtUserMessageCall( thread_data->default_hwnd, WM_WINE_DESTROYWINDOW, 0, 0, + 0, NtUserSendNotifyMessage, FALSE ); + } + pthread_mutex_unlock( &imm_mutex ); + } + else if (!thread_id || thread_id == GetCurrentThreadId()) + { + if (!(thread_data = get_imm_thread_data())) return FALSE; + thread_data->disable_ime = TRUE; + } + else return FALSE; + + if ((thread_data = get_user_thread_info()->imm_thread_data)) + { + HWND destroy_hwnd = detach_default_window( thread_data ); + NtUserDestroyWindow( destroy_hwnd ); + } + return TRUE; +} + +HWND get_default_ime_window( HWND hwnd ) +{ + struct imm_thread_data *thread_data; + HWND ret = 0; + + if (hwnd) + { + DWORD thread_id; + + if (!(thread_id = get_window_thread( hwnd, NULL ))) return 0; + + pthread_mutex_lock( &imm_mutex ); + LIST_FOR_EACH_ENTRY( thread_data, &thread_data_list, struct imm_thread_data, entry ) + { + if (thread_data->thread_id != thread_id) continue; + ret = thread_data->default_hwnd; + break; + } + pthread_mutex_unlock( &imm_mutex ); + } + else if ((thread_data = get_user_thread_info()->imm_thread_data)) + { + ret = thread_data->default_hwnd; + } + + TRACE( "default for %p is %p\n", hwnd, ret ); + return ret; +} + +void cleanup_imm_thread(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + + if (thread_info->imm_thread_data) + { + pthread_mutex_lock( &imm_mutex ); + list_remove( &thread_info->imm_thread_data->entry ); + pthread_mutex_unlock( &imm_mutex ); + free( thread_info->imm_thread_data ); + thread_info->imm_thread_data = NULL; + } + + NtUserDestroyInputContext( thread_info->client_info.default_imc ); +} diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 6f0e4f45501..c41a41c605a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1551,7 +1551,7 @@ HWND get_focus(void) */ static HWND set_focus_window( HWND hwnd ) { - HWND previous = 0; + HWND previous = 0, ime_hwnd; BOOL ret; SERVER_START_REQ( set_focus_window ) @@ -1568,7 +1568,10 @@ static HWND set_focus_window( HWND hwnd ) { send_message( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 ); - if (user_callbacks) user_callbacks->notify_ime( previous, IME_INTERNAL_DEACTIVATE ); + ime_hwnd = get_default_ime_window( previous ); + if (ime_hwnd) + send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_DEACTIVATE, + HandleToUlong(previous) ); if (hwnd != get_focus()) return previous; /* changed by the message */ } @@ -1576,7 +1579,10 @@ static HWND set_focus_window( HWND hwnd ) { user_driver->pSetFocus(hwnd); - if (user_callbacks) user_callbacks->notify_ime( hwnd, IME_INTERNAL_ACTIVATE ); + ime_hwnd = get_default_ime_window( hwnd ); + if (ime_hwnd) + send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_ACTIVATE, + HandleToUlong(hwnd) ); if (previous) NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, 0 ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index ba1c0b68d17..780af425673 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -35,13 +35,10 @@ struct user_callbacks BOOL (WINAPI *pImmProcessKey)(HWND, HKL, UINT, LPARAM, DWORD); BOOL (WINAPI *pImmTranslateMessage)(HWND, UINT, WPARAM, LPARAM); NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); - void (CDECL *notify_ime)( HWND hwnd, UINT param ); BOOL (CDECL *post_dde_message)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD dest_tid, DWORD type ); BOOL (CDECL *unpack_dde_message)( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, void **buffer, size_t size ); - BOOL (WINAPI *register_imm)( HWND hwnd ); - void (WINAPI *unregister_imm)( HWND hwnd ); NTSTATUS (CDECL *try_finally)( NTSTATUS (CDECL *func)( void *), void *arg, void (CALLBACK *finally_func)( BOOL )); }; @@ -154,6 +151,7 @@ struct user_thread_info struct received_message_info *receive_info; /* Message being currently received */ struct wm_char_mapping_data *wmchar_data; /* Data for WM_CHAR mappings */ struct user_key_state_info *key_state; /* Cache of global key state */ + struct imm_thread_data *imm_thread_data; /* IMM thread data */ HKL kbd_layout; /* Current keyboard layout */ DWORD kbd_layout_id; /* Current keyboard layout ID */ struct rawinput_thread_data *rawinput; /* RawInput thread local data / buffer */ @@ -273,6 +271,7 @@ WNDPROC get_winproc( WNDPROC proc, BOOL ansi ) DECLSPEC_HIDDEN; void get_winproc_params( struct win_proc_params *params ) DECLSPEC_HIDDEN; struct dce *get_class_dce( struct tagCLASS *class ) DECLSPEC_HIDDEN; struct dce *set_class_dce( struct tagCLASS *class, struct dce *dce ) DECLSPEC_HIDDEN; +BOOL needs_ime_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void register_builtin_classes(void) DECLSPEC_HIDDEN; /* cursoricon.c */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 69e39713102..2c1f8f4241f 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -4818,7 +4818,7 @@ static void thread_detach(void) free( thread_info->rawinput ); destroy_thread_windows(); - NtUserDestroyInputContext( thread_info->client_info.default_imc ); + cleanup_imm_thread(); NtClose( thread_info->server_queue ); exiting_thread_id = 0; diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 313361989ec..d74685ad603 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -837,7 +837,7 @@ @ stdcall NtUserDestroyWindow(long) @ stub NtUserDisableImmersiveOwner @ stub NtUserDisableProcessWindowFiltering -@ stub NtUserDisableThreadIme +@ stdcall NtUserDisableThreadIme(long) @ stub NtUserDiscardPointerFrameMessages @ stdcall NtUserDispatchMessage(ptr) @ stub NtUserDisplayConfigGetDeviceInfo diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 1f7bcb9e2e3..a0b3e8c2e9e 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -214,6 +214,7 @@ struct unix_funcs BOOL (WINAPI *pNtUserDestroyCursor)( HCURSOR cursor, ULONG arg ); BOOL (WINAPI *pNtUserDestroyMenu)( HMENU handle ); BOOL (WINAPI *pNtUserDestroyWindow)( HWND hwnd ); + BOOL (WINAPI *pNtUserDisableThreadIme)( DWORD thread_id ); LRESULT (WINAPI *pNtUserDispatchMessage)( const MSG *msg ); BOOL (WINAPI *pNtUserDragDetect)( HWND hwnd, int x, int y ); BOOL (WINAPI *pNtUserDrawCaptionTemp)( HWND hwnd, HDC hdc, const RECT *rect, HFONT font, @@ -393,8 +394,12 @@ extern LRESULT call_hooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL extern BOOL unhook_windows_hook( INT id, HOOKPROC proc ) DECLSPEC_HIDDEN; /* imm.c */ +extern void cleanup_imm_thread(void) DECLSPEC_HIDDEN; +extern HWND get_default_ime_window( HWND hwnd ) DECLSPEC_HIDDEN; extern HIMC get_default_input_context(void) DECLSPEC_HIDDEN; extern HIMC get_window_input_context( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL register_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; +extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; /* input.c */ extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index a8fca0678d0..fee1617ef10 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -4680,12 +4680,7 @@ LRESULT destroy_window( 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); - if (user_callbacks) user_callbacks->unregister_imm( hwnd ); - } + unregister_imm_window( hwnd ); /* free child windows */ if ((children = list_window_children( 0, hwnd, NULL, 0 ))) @@ -5262,7 +5257,7 @@ HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name, /* create default IME window */ if (!is_desktop_window( hwnd ) && parent != get_hwnd_message_parent() && - user_callbacks && user_callbacks->register_imm( hwnd )) + register_imm_window( hwnd )) { TRACE( "register IME window for %p\n", hwnd ); win_set_flags( hwnd, WIN_HAS_IME_WIN, 0 ); @@ -5377,6 +5372,9 @@ ULONG_PTR WINAPI NtUserCallHwnd( HWND hwnd, DWORD code ) case NtUserCallHwnd_DrawMenuBar: return draw_menu_bar( hwnd ); + case NtUserCallHwnd_GetDefaultImeWindow: + return HandleToUlong( get_default_ime_window( hwnd )); + case NtUserCallHwnd_GetDpiForWindow: return get_dpi_for_window( hwnd ); diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index ba6fa9ea0a0..609e893403b 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -849,6 +849,12 @@ BOOL WINAPI NtUserDestroyWindow( HWND hwnd ) return unix_funcs->pNtUserDestroyWindow( hwnd ); } +BOOL WINAPI NtUserDisableThreadIme( DWORD thread_id ) +{ + if (!unix_funcs) return FALSE; + return unix_funcs->pNtUserDisableThreadIme( thread_id ); +} + LRESULT WINAPI NtUserDispatchMessage( const MSG *msg ) { if (!unix_funcs) return 0; diff --git a/include/ntuser.h b/include/ntuser.h index 0528e0d90bf..281d88dfb1a 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -599,6 +599,7 @@ BOOL WINAPI NtUserDestroyCursor( HCURSOR cursor, ULONG arg ); BOOL WINAPI NtUserDestroyInputContext( HIMC handle ); BOOL WINAPI NtUserDestroyMenu( HMENU menu ); BOOL WINAPI NtUserDestroyWindow( HWND hwnd ); +BOOL WINAPI NtUserDisableThreadIme( DWORD thread_id ); LRESULT WINAPI NtUserDispatchMessage( const MSG *msg ); BOOL WINAPI NtUserDragDetect( HWND hwnd, int x, int y ); BOOL WINAPI NtUserDrawCaptionTemp( HWND hwnd, HDC hdc, const RECT *rect, HFONT font, @@ -1055,6 +1056,7 @@ enum { NtUserCallHwnd_ArrangeIconicWindows, NtUserCallHwnd_DrawMenuBar, + NtUserCallHwnd_GetDefaultImeWindow, NtUserCallHwnd_GetDpiForWindow, NtUserCallHwnd_GetParent, NtUserCallHwnd_GetWindowContextHelpId, @@ -1083,6 +1085,11 @@ static inline DWORD NtUserGetWindowContextHelpId( HWND hwnd ) return NtUserCallHwnd( hwnd, NtUserCallHwnd_GetWindowContextHelpId ); } +static inline HWND NtUserGetDefaultImeWindow( HWND hwnd ) +{ + return UlongToHandle( NtUserCallHwnd( hwnd, NtUserCallHwnd_GetDefaultImeWindow )); +} + static inline UINT NtUserGetDpiForWindow( HWND hwnd ) { return NtUserCallHwnd( hwnd, NtUserCallHwnd_GetDpiForWindow );