dxgi: Create d3d11 swapchain textures directly from d3d11_swapchain_init().
[wine.git] / dlls / win32u / imm.c
blob7dee4912e27610cfe6409641c22539de7b46957c
1 /*
2 * Input Context implementation
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
6 * Copyright 2022 Jacek Caban for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include <pthread.h>
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "win32u_private.h"
31 #include "ntuser_private.h"
32 #include "immdev.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(imm);
38 struct imc
40 struct user_object obj;
41 DWORD thread_id;
42 UINT_PTR client_ptr;
45 struct imm_thread_data
47 struct list entry;
48 DWORD thread_id;
49 HWND default_hwnd;
50 BOOL disable_ime;
51 UINT window_cnt;
54 static struct list thread_data_list = LIST_INIT( thread_data_list );
55 static pthread_mutex_t imm_mutex = PTHREAD_MUTEX_INITIALIZER;
56 static BOOL disable_ime;
58 static struct imc *get_imc_ptr( HIMC handle )
60 struct imc *imc = get_user_handle_ptr( handle, NTUSER_OBJ_IMC );
61 if (imc && imc != OBJ_OTHER_PROCESS) return imc;
62 WARN( "invalid handle %p\n", handle );
63 RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
64 return NULL;
67 static void release_imc_ptr( struct imc *imc )
69 release_user_handle_ptr( imc );
72 /******************************************************************************
73 * NtUserCreateInputContext (win32u.@)
75 HIMC WINAPI NtUserCreateInputContext( UINT_PTR client_ptr )
77 struct imc *imc;
78 HIMC handle;
80 if (!(imc = malloc( sizeof(*imc) ))) return 0;
81 imc->client_ptr = client_ptr;
82 imc->thread_id = GetCurrentThreadId();
83 if (!(handle = alloc_user_handle( &imc->obj, NTUSER_OBJ_IMC )))
85 free( imc );
86 return 0;
89 TRACE( "%lx returning %p\n", (long)client_ptr, handle );
90 return handle;
93 /******************************************************************************
94 * NtUserDestroyInputContext (win32u.@)
96 BOOL WINAPI NtUserDestroyInputContext( HIMC handle )
98 struct imc *imc;
100 TRACE( "%p\n", handle );
102 if (!(imc = free_user_handle( handle, NTUSER_OBJ_IMC ))) return FALSE;
103 if (imc == OBJ_OTHER_PROCESS)
105 FIXME( "other process handle %p\n", handle );
106 return FALSE;
108 free( imc );
109 return TRUE;
112 /******************************************************************************
113 * NtUserUpdateInputContext (win32u.@)
115 BOOL WINAPI NtUserUpdateInputContext( HIMC handle, UINT attr, UINT_PTR value )
117 struct imc *imc;
118 BOOL ret = TRUE;
120 TRACE( "%p %u %lx\n", handle, attr, (long)value );
122 if (!(imc = get_imc_ptr( handle ))) return FALSE;
124 switch (attr)
126 case NtUserInputContextClientPtr:
127 imc->client_ptr = value;
128 break;
130 default:
131 FIXME( "unknown attr %u\n", attr );
132 ret = FALSE;
135 release_imc_ptr( imc );
136 return ret;
139 /******************************************************************************
140 * NtUserQueryInputContext (win32u.@)
142 UINT_PTR WINAPI NtUserQueryInputContext( HIMC handle, UINT attr )
144 struct imc *imc;
145 UINT_PTR ret;
147 if (!(imc = get_imc_ptr( handle ))) return FALSE;
149 switch (attr)
151 case NtUserInputContextClientPtr:
152 ret = imc->client_ptr;
153 break;
155 case NtUserInputContextThreadId:
156 ret = imc->thread_id;
157 break;
159 default:
160 FIXME( "unknown attr %u\n", attr );
161 ret = 0;
164 release_imc_ptr( imc );
165 return ret;
168 /******************************************************************************
169 * NtUserAssociateInputContext (win32u.@)
171 UINT WINAPI NtUserAssociateInputContext( HWND hwnd, HIMC ctx, ULONG flags )
173 WND *win;
174 UINT ret = AICR_OK;
176 TRACE( "%p %p %x\n", hwnd, ctx, (int)flags );
178 switch (flags)
180 case 0:
181 case IACE_IGNORENOCONTEXT:
182 case IACE_DEFAULT:
183 break;
185 default:
186 FIXME( "unknown flags 0x%x\n", (int)flags );
187 return AICR_FAILED;
190 if (flags == IACE_DEFAULT)
192 if (!(ctx = get_default_input_context())) return AICR_FAILED;
194 else if (ctx)
196 if (NtUserQueryInputContext( ctx, NtUserInputContextThreadId ) != GetCurrentThreadId())
197 return AICR_FAILED;
200 if (!(win = get_win_ptr( hwnd )) || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
201 return AICR_FAILED;
203 if (ctx && win->tid != GetCurrentThreadId()) ret = AICR_FAILED;
204 else if (flags != IACE_IGNORENOCONTEXT || win->imc)
206 if (win->imc != ctx && get_focus() == hwnd) ret = AICR_FOCUS_CHANGED;
207 win->imc = ctx;
210 release_win_ptr( win );
211 return ret;
214 HIMC get_default_input_context(void)
216 struct ntuser_thread_info *thread_info = NtUserGetThreadInfo();
217 if (!thread_info->default_imc)
218 thread_info->default_imc = HandleToUlong( NtUserCreateInputContext( 0 ));
219 return UlongToHandle( thread_info->default_imc );
222 HIMC get_window_input_context( HWND hwnd )
224 WND *win;
225 HIMC ret;
227 if (!(win = get_win_ptr( hwnd )) || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
229 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE );
230 return 0;
233 ret = win->imc;
234 release_win_ptr( win );
235 return ret;
238 static HWND detach_default_window( struct imm_thread_data *thread_data )
240 HWND hwnd = thread_data->default_hwnd;
241 thread_data->default_hwnd = NULL;
242 thread_data->window_cnt = 0;
243 return hwnd;
246 static struct imm_thread_data *get_imm_thread_data(void)
248 struct user_thread_info *thread_info = get_user_thread_info();
249 if (!thread_info->imm_thread_data)
251 struct imm_thread_data *data;
252 if (!(data = calloc( 1, sizeof( *data )))) return NULL;
253 data->thread_id = GetCurrentThreadId();
255 pthread_mutex_lock( &imm_mutex );
256 list_add_tail( &thread_data_list, &data->entry );
257 pthread_mutex_unlock( &imm_mutex );
259 thread_info->imm_thread_data = data;
261 return thread_info->imm_thread_data;
264 BOOL register_imm_window( HWND hwnd )
266 struct imm_thread_data *thread_data;
268 TRACE( "(%p)\n", hwnd );
270 if (disable_ime || !needs_ime_window( hwnd ))
271 return FALSE;
273 thread_data = get_imm_thread_data();
274 if (!thread_data || thread_data->disable_ime)
275 return FALSE;
277 TRACE( "window_cnt=%u, default_hwnd=%p\n", thread_data->window_cnt + 1, thread_data->default_hwnd );
279 /* Create default IME window */
280 if (!thread_data->window_cnt++)
282 static const WCHAR imeW[] = {'I','M','E',0};
283 static const WCHAR default_imeW[] = {'D','e','f','a','u','l','t',' ','I','M','E',0};
284 UNICODE_STRING class_name = RTL_CONSTANT_STRING( imeW );
285 UNICODE_STRING name = RTL_CONSTANT_STRING( default_imeW );
287 thread_data->default_hwnd = NtUserCreateWindowEx( 0, &class_name, &class_name, &name,
288 WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
289 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, FALSE );
292 return TRUE;
295 void unregister_imm_window( HWND hwnd )
297 struct imm_thread_data *thread_data = get_user_thread_info()->imm_thread_data;
299 if (!thread_data) return;
300 if (thread_data->default_hwnd == hwnd)
302 detach_default_window( thread_data );
303 return;
306 if (!(win_set_flags( hwnd, 0, WIN_HAS_IME_WIN ) & WIN_HAS_IME_WIN)) return;
308 /* destroy default IME window */
309 TRACE( "unregister IME window for %p\n", hwnd );
310 if (!--thread_data->window_cnt)
312 HWND destroy_hwnd = detach_default_window( thread_data );
313 if (destroy_hwnd) NtUserDestroyWindow( destroy_hwnd );
317 /***********************************************************************
318 * NtUserDisableThreadIme (win32u.@)
320 BOOL WINAPI NtUserDisableThreadIme( DWORD thread_id )
322 struct imm_thread_data *thread_data;
324 if (thread_id == -1)
326 disable_ime = TRUE;
328 pthread_mutex_lock( &imm_mutex );
329 LIST_FOR_EACH_ENTRY( thread_data, &thread_data_list, struct imm_thread_data, entry )
331 if (thread_data->thread_id == GetCurrentThreadId()) continue;
332 if (!thread_data->default_hwnd) continue;
333 NtUserMessageCall( thread_data->default_hwnd, WM_WINE_DESTROYWINDOW, 0, 0,
334 0, NtUserSendNotifyMessage, FALSE );
336 pthread_mutex_unlock( &imm_mutex );
338 else if (!thread_id || thread_id == GetCurrentThreadId())
340 if (!(thread_data = get_imm_thread_data())) return FALSE;
341 thread_data->disable_ime = TRUE;
343 else return FALSE;
345 if ((thread_data = get_user_thread_info()->imm_thread_data))
347 HWND destroy_hwnd = detach_default_window( thread_data );
348 NtUserDestroyWindow( destroy_hwnd );
350 return TRUE;
353 HWND get_default_ime_window( HWND hwnd )
355 struct imm_thread_data *thread_data;
356 HWND ret = 0;
358 if (hwnd)
360 DWORD thread_id;
362 if (!(thread_id = get_window_thread( hwnd, NULL ))) return 0;
364 pthread_mutex_lock( &imm_mutex );
365 LIST_FOR_EACH_ENTRY( thread_data, &thread_data_list, struct imm_thread_data, entry )
367 if (thread_data->thread_id != thread_id) continue;
368 ret = thread_data->default_hwnd;
369 break;
371 pthread_mutex_unlock( &imm_mutex );
373 else if ((thread_data = get_user_thread_info()->imm_thread_data))
375 ret = thread_data->default_hwnd;
378 TRACE( "default for %p is %p\n", hwnd, ret );
379 return ret;
382 void cleanup_imm_thread(void)
384 struct user_thread_info *thread_info = get_user_thread_info();
386 if (thread_info->imm_thread_data)
388 pthread_mutex_lock( &imm_mutex );
389 list_remove( &thread_info->imm_thread_data->entry );
390 pthread_mutex_unlock( &imm_mutex );
391 free( thread_info->imm_thread_data );
392 thread_info->imm_thread_data = NULL;
395 NtUserDestroyInputContext( UlongToHandle( thread_info->client_info.default_imc ));
398 /*****************************************************************************
399 * NtUserBuildHimcList (win32u.@)
401 NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, UINT *size )
403 HANDLE handle = 0;
404 struct imc *imc;
406 TRACE( "thread_id %#x, count %u, buffer %p, size %p\n", thread_id, count, buffer, size );
408 if (!buffer) return STATUS_UNSUCCESSFUL;
409 if (!thread_id) thread_id = GetCurrentThreadId();
411 *size = 0;
412 user_lock();
413 while (count && (imc = next_process_user_handle_ptr( &handle, NTUSER_OBJ_IMC )))
415 if (thread_id != -1 && imc->thread_id != thread_id) continue;
416 buffer[(*size)++] = handle;
417 count--;
419 user_unlock();
421 return STATUS_SUCCESS;
424 BOOL WINAPI DECLSPEC_HIDDEN ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM key_data, DWORD unknown )
426 struct imm_process_key_params params =
427 { .hwnd = hwnd, .hkl = hkl, .vkey = vkey, .key_data = key_data };
428 void *ret_ptr;
429 ULONG ret_len;
430 return KeUserModeCallback( NtUserImmProcessKey, &params, sizeof(params), &ret_ptr, &ret_len );
433 BOOL WINAPI DECLSPEC_HIDDEN ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM key_data )
435 struct imm_translate_message_params params =
436 { .hwnd = hwnd, .msg = msg, .wparam = wparam, .key_data = key_data };
437 void *ret_ptr;
438 ULONG ret_len;
439 return KeUserModeCallback( NtUserImmTranslateMessage, &params, sizeof(params),
440 &ret_ptr, &ret_len );