winex11: Remove non-CJK specific XIC creation logic.
[wine.git] / dlls / winex11.drv / xim.c
blobe04bf91206c6a6a2bd2d6ae3667629fbbb250df7
1 /*
2 * Functions for further XIM control
4 * Copyright 2003 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winnls.h"
33 #include "winternl.h"
34 #include "x11drv.h"
35 #include "imm.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(xim);
40 #ifndef HAVE_XICCALLBACK_CALLBACK
41 #define XICCallback XIMCallback
42 #define XICProc XIMProc
43 #endif
45 BOOL ximInComposeMode=FALSE;
47 /* moved here from imm32 for dll separation */
48 static DWORD dwCompStringLength = 0;
49 static LPBYTE CompositionString = NULL;
50 static DWORD dwCompStringSize = 0;
52 #define STYLE_OFFTHESPOT (XIMPreeditArea | XIMStatusArea)
53 #define STYLE_OVERTHESPOT (XIMPreeditPosition | XIMStatusNothing)
54 #define STYLE_ROOT (XIMPreeditNothing | XIMStatusNothing)
55 /* this uses all the callbacks to utilize full IME support */
56 #define STYLE_CALLBACK (XIMPreeditCallbacks | XIMStatusNothing)
57 /* in order to enable deadkey support */
58 #define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing)
60 static XIMStyle ximStyle = 0;
61 static XIMStyle ximStyleRoot = 0;
62 static XIMStyle ximStyleRequest = STYLE_CALLBACK;
64 static void X11DRV_ImmSetInternalString(UINT offset, UINT selLength, LPWSTR lpComp, UINT len)
66 /* Composition strings are edited in chunks */
67 unsigned int byte_length = len * sizeof(WCHAR);
68 unsigned int byte_offset = offset * sizeof(WCHAR);
69 unsigned int byte_selection = selLength * sizeof(WCHAR);
70 int byte_expansion = byte_length - byte_selection;
71 LPBYTE ptr_new;
73 TRACE("( %i, %i, %p, %d):\n", offset, selLength, lpComp, len );
75 if (byte_expansion + dwCompStringLength >= dwCompStringSize)
77 ptr_new = realloc( CompositionString, dwCompStringSize + byte_expansion );
78 if (ptr_new == NULL)
80 ERR("Couldn't expand composition string buffer\n");
81 return;
84 CompositionString = ptr_new;
85 dwCompStringSize += byte_expansion;
88 ptr_new = CompositionString + byte_offset;
89 memmove(ptr_new + byte_length, ptr_new + byte_selection,
90 dwCompStringLength - byte_offset - byte_selection);
91 if (lpComp) memcpy(ptr_new, lpComp, byte_length);
92 dwCompStringLength += byte_expansion;
94 x11drv_client_func( client_func_ime_set_composition_string,
95 CompositionString, dwCompStringLength );
98 void X11DRV_XIMLookupChars( const char *str, UINT count )
100 WCHAR *output;
101 DWORD len;
103 TRACE("%p %u\n", str, count);
105 if (!(output = malloc( count * sizeof(WCHAR) ))) return;
106 len = ntdll_umbstowcs( str, count, output, count );
108 x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) );
109 free( output );
112 static BOOL XIMPreEditStateNotifyCallback(XIC xic, XPointer p, XPointer data)
114 const struct x11drv_win_data * const win_data = (struct x11drv_win_data *)p;
115 const XIMPreeditState state = ((XIMPreeditStateNotifyCallbackStruct *)data)->state;
117 TRACE("xic = %p, win = %lx, state = %lu\n", xic, win_data->whole_window, state);
118 switch (state)
120 case XIMPreeditEnable:
121 x11drv_client_call( client_ime_set_open_status, TRUE );
122 break;
123 case XIMPreeditDisable:
124 x11drv_client_call( client_ime_set_open_status, FALSE );
125 break;
126 default:
127 break;
130 return TRUE;
133 static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
135 TRACE("PreEditStartCallback %p\n",ic);
136 x11drv_client_call( client_ime_set_composition_status, TRUE );
137 ximInComposeMode = TRUE;
138 return -1;
141 static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
143 TRACE("PreeditDoneCallback %p\n",ic);
144 ximInComposeMode = FALSE;
145 if (dwCompStringSize)
146 free( CompositionString );
147 dwCompStringSize = 0;
148 dwCompStringLength = 0;
149 CompositionString = NULL;
150 x11drv_client_call( client_ime_set_composition_status, FALSE );
153 static void XIMPreEditDrawCallback(XIM ic, XPointer client_data,
154 XIMPreeditDrawCallbackStruct *P_DR)
156 TRACE("PreEditDrawCallback %p\n",ic);
158 if (P_DR)
160 int sel = P_DR->chg_first;
161 int len = P_DR->chg_length;
162 if (P_DR->text)
164 if (! P_DR->text->encoding_is_wchar)
166 size_t text_len;
167 WCHAR *output;
169 TRACE("multibyte\n");
170 text_len = strlen( P_DR->text->string.multi_byte );
171 if ((output = malloc( text_len * sizeof(WCHAR) )))
173 text_len = ntdll_umbstowcs( P_DR->text->string.multi_byte, text_len,
174 output, text_len );
176 X11DRV_ImmSetInternalString( sel, len, output, text_len );
177 free( output );
180 else
182 FIXME("wchar PROBIBILY WRONG\n");
183 X11DRV_ImmSetInternalString (sel, len,
184 (LPWSTR)P_DR->text->string.wide_char,
185 P_DR->text->length);
188 else
189 X11DRV_ImmSetInternalString (sel, len, NULL, 0);
190 x11drv_client_call( client_ime_set_cursor_pos, P_DR->caret );
192 TRACE("Finished\n");
195 static void XIMPreEditCaretCallback(XIC ic, XPointer client_data,
196 XIMPreeditCaretCallbackStruct *P_C)
198 TRACE("PreeditCaretCallback %p\n",ic);
200 if (P_C)
202 int pos = x11drv_client_call( client_ime_get_cursor_pos, 0 );
203 TRACE("pos: %d\n", pos);
204 switch(P_C->direction)
206 case XIMForwardChar:
207 case XIMForwardWord:
208 pos++;
209 break;
210 case XIMBackwardChar:
211 case XIMBackwardWord:
212 pos--;
213 break;
214 case XIMLineStart:
215 pos = 0;
216 break;
217 case XIMAbsolutePosition:
218 pos = P_C->position;
219 break;
220 case XIMDontChange:
221 P_C->position = pos;
222 return;
223 case XIMCaretUp:
224 case XIMCaretDown:
225 case XIMPreviousLine:
226 case XIMNextLine:
227 case XIMLineEnd:
228 FIXME("Not implemented\n");
229 break;
231 x11drv_client_call( client_ime_set_cursor_pos, pos );
232 P_C->position = pos;
234 TRACE("Finished\n");
237 NTSTATUS x11drv_xim_reset( void *hwnd )
239 XIC ic = X11DRV_get_ic(hwnd);
240 if (ic)
242 char* leftover;
243 TRACE("Forcing Reset %p\n",ic);
244 leftover = XmbResetIC(ic);
245 XFree(leftover);
247 return 0;
250 NTSTATUS x11drv_xim_preedit_state( void *arg )
252 struct xim_preedit_state_params *params = arg;
253 XIC ic;
254 XIMPreeditState state;
255 XVaNestedList attr;
257 ic = X11DRV_get_ic( params->hwnd );
258 if (!ic)
259 return 0;
261 if (params->open)
262 state = XIMPreeditEnable;
263 else
264 state = XIMPreeditDisable;
266 attr = XVaCreateNestedList(0, XNPreeditState, state, NULL);
267 if (attr != NULL)
269 XSetICValues(ic, XNPreeditAttributes, attr, NULL);
270 XFree(attr);
272 return 0;
276 /***********************************************************************
277 * X11DRV_InitXIM
279 * Process-wide XIM initialization.
281 BOOL X11DRV_InitXIM( const WCHAR *input_style )
283 static const WCHAR offthespotW[] = {'o','f','f','t','h','e','s','p','o','t',0};
284 static const WCHAR overthespotW[] = {'o','v','e','r','t','h','e','s','p','o','t',0};
285 static const WCHAR rootW[] = {'r','o','o','t',0};
287 if (!wcsicmp( input_style, offthespotW ))
288 ximStyleRequest = STYLE_OFFTHESPOT;
289 else if (!wcsicmp( input_style, overthespotW ))
290 ximStyleRequest = STYLE_OVERTHESPOT;
291 else if (!wcsicmp( input_style, rootW ))
292 ximStyleRequest = STYLE_ROOT;
294 if (!XSupportsLocale())
296 WARN("X does not support locale.\n");
297 return FALSE;
299 if (XSetLocaleModifiers("") == NULL)
301 WARN("Could not set locale modifiers.\n");
302 return FALSE;
304 return TRUE;
308 static void open_xim_callback( Display *display, XPointer ptr, XPointer data );
310 static void X11DRV_DestroyIM(XIM xim, XPointer p, XPointer data)
312 struct x11drv_thread_data *thread_data = x11drv_thread_data();
314 TRACE("xim = %p, p = %p\n", xim, p);
315 thread_data->xim = NULL;
316 ximStyle = 0;
317 XRegisterIMInstantiateCallback( thread_data->display, NULL, NULL, NULL, open_xim_callback, NULL );
320 /***********************************************************************
321 * X11DRV Ime creation
323 * Should always be called with the x11 lock held
325 static BOOL open_xim( Display *display )
327 struct x11drv_thread_data *thread_data = x11drv_thread_data();
328 XIMStyle ximStyleNone;
329 XIMStyles *ximStyles = NULL;
330 INT i;
331 XIM xim;
332 XIMCallback destroy;
334 xim = XOpenIM(display, NULL, NULL, NULL);
335 if (xim == NULL)
337 WARN("Could not open input method.\n");
338 return FALSE;
341 destroy.client_data = NULL;
342 destroy.callback = X11DRV_DestroyIM;
343 if (XSetIMValues(xim, XNDestroyCallback, &destroy, NULL))
345 WARN("Could not set destroy callback.\n");
348 TRACE("xim = %p\n", xim);
349 TRACE("X display of IM = %p\n", XDisplayOfIM(xim));
350 TRACE("Using %s locale of Input Method\n", XLocaleOfIM(xim));
352 XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL);
353 if (ximStyles == 0)
355 WARN("Could not find supported input style.\n");
356 XCloseIM(xim);
357 return FALSE;
359 else
361 TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles);
363 ximStyleRoot = 0;
364 ximStyleNone = 0;
366 for (i = 0; i < ximStyles->count_styles; ++i)
368 int style = ximStyles->supported_styles[i];
369 TRACE("ximStyles[%d] = %s%s%s%s%s\n", i,
370 (style&XIMPreeditArea)?"XIMPreeditArea ":"",
371 (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"",
372 (style&XIMPreeditPosition)?"XIMPreeditPosition ":"",
373 (style&XIMPreeditNothing)?"XIMPreeditNothing ":"",
374 (style&XIMPreeditNone)?"XIMPreeditNone ":"");
375 if (!ximStyle && (ximStyles->supported_styles[i] ==
376 ximStyleRequest))
378 ximStyle = ximStyleRequest;
379 TRACE("Setting Style: ximStyle = ximStyleRequest\n");
381 else if (!ximStyleRoot &&(ximStyles->supported_styles[i] ==
382 STYLE_ROOT))
384 ximStyleRoot = STYLE_ROOT;
385 TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n");
387 else if (!ximStyleNone && (ximStyles->supported_styles[i] ==
388 STYLE_NONE))
390 TRACE("Setting Style: ximStyleNone = STYLE_NONE\n");
391 ximStyleNone = STYLE_NONE;
394 XFree(ximStyles);
396 if (ximStyle == 0)
397 ximStyle = ximStyleRoot;
399 if (ximStyle == 0)
400 ximStyle = ximStyleNone;
403 thread_data->xim = xim;
405 if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0 ||
406 (ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0)
408 char **list;
409 int count;
410 thread_data->font_set = XCreateFontSet(display, "fixed",
411 &list, &count, NULL);
412 TRACE("ximFontSet = %p\n", thread_data->font_set);
413 TRACE("list = %p, count = %d\n", list, count);
414 if (list != NULL)
416 int i;
417 for (i = 0; i < count; ++i)
418 TRACE("list[%d] = %s\n", i, list[i]);
419 XFreeStringList(list);
422 else
423 thread_data->font_set = NULL;
425 x11drv_client_call( client_ime_update_association, 0 );
426 return TRUE;
429 static void open_xim_callback( Display *display, XPointer ptr, XPointer data )
431 if (open_xim( display ))
432 XUnregisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL);
435 void X11DRV_SetupXIM(void)
437 Display *display = thread_display();
439 if (!open_xim( display ))
440 XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL );
443 static BOOL X11DRV_DestroyIC(XIC xic, XPointer p, XPointer data)
445 struct x11drv_win_data *win_data = (struct x11drv_win_data *)p;
446 TRACE("xic = %p, win = %lx\n", xic, win_data->whole_window);
447 win_data->xic = NULL;
448 return TRUE;
452 XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data)
454 XPoint spot = {0};
455 XVaNestedList preedit = NULL;
456 XVaNestedList status = NULL;
457 XIC xic;
458 XICCallback destroy = {(XPointer)data, X11DRV_DestroyIC};
459 XICCallback P_StateNotifyCB, P_StartCB, P_DoneCB, P_DrawCB, P_CaretCB;
460 Window win = data->whole_window;
461 XFontSet fontSet = x11drv_thread_data()->font_set;
463 TRACE( "xim %p, data %p\n", xim, data );
465 /* create callbacks */
466 P_StateNotifyCB.client_data = (XPointer)data;
467 P_StartCB.client_data = NULL;
468 P_DoneCB.client_data = NULL;
469 P_DrawCB.client_data = NULL;
470 P_CaretCB.client_data = NULL;
471 P_StateNotifyCB.callback = XIMPreEditStateNotifyCallback;
472 P_StartCB.callback = XIMPreEditStartCallback;
473 P_DoneCB.callback = (XICProc)XIMPreEditDoneCallback;
474 P_DrawCB.callback = (XICProc)XIMPreEditDrawCallback;
475 P_CaretCB.callback = (XICProc)XIMPreEditCaretCallback;
477 if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0)
479 preedit = XVaCreateNestedList(0,
480 XNFontSet, fontSet,
481 XNSpotLocation, &spot,
482 XNPreeditStateNotifyCallback, &P_StateNotifyCB,
483 XNPreeditStartCallback, &P_StartCB,
484 XNPreeditDoneCallback, &P_DoneCB,
485 XNPreeditDrawCallback, &P_DrawCB,
486 XNPreeditCaretCallback, &P_CaretCB,
487 NULL);
488 TRACE("preedit = %p\n", preedit);
490 else
492 preedit = XVaCreateNestedList(0,
493 XNPreeditStateNotifyCallback, &P_StateNotifyCB,
494 XNPreeditStartCallback, &P_StartCB,
495 XNPreeditDoneCallback, &P_DoneCB,
496 XNPreeditDrawCallback, &P_DrawCB,
497 XNPreeditCaretCallback, &P_CaretCB,
498 NULL);
500 TRACE("preedit = %p\n", preedit);
503 if ((ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0)
505 status = XVaCreateNestedList(0,
506 XNFontSet, fontSet,
507 NULL);
508 TRACE("status = %p\n", status);
511 if (preedit != NULL && status != NULL)
513 xic = XCreateIC(xim,
514 XNInputStyle, ximStyle,
515 XNPreeditAttributes, preedit,
516 XNStatusAttributes, status,
517 XNClientWindow, win,
518 XNFocusWindow, win,
519 XNDestroyCallback, &destroy,
520 NULL);
522 else if (preedit != NULL)
524 xic = XCreateIC(xim,
525 XNInputStyle, ximStyle,
526 XNPreeditAttributes, preedit,
527 XNClientWindow, win,
528 XNFocusWindow, win,
529 XNDestroyCallback, &destroy,
530 NULL);
532 else if (status != NULL)
534 xic = XCreateIC(xim,
535 XNInputStyle, ximStyle,
536 XNStatusAttributes, status,
537 XNClientWindow, win,
538 XNFocusWindow, win,
539 XNDestroyCallback, &destroy,
540 NULL);
542 else
544 xic = XCreateIC(xim,
545 XNInputStyle, ximStyle,
546 XNClientWindow, win,
547 XNFocusWindow, win,
548 XNDestroyCallback, &destroy,
549 NULL);
552 TRACE("xic = %p\n", xic);
553 data->xic = xic;
555 if (preedit != NULL)
556 XFree(preedit);
557 if (status != NULL)
558 XFree(status);
560 return xic;