maintainers: Update the Direct3D section.
[wine.git] / dlls / winex11.drv / xim.c
blob00c15bb3bcfbe61662027a3f8485964ed110dd11
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(DWORD dwOffset,
65 DWORD selLength, LPWSTR lpComp, DWORD dwCompLen)
67 /* Composition strings are edited in chunks */
68 unsigned int byte_length = dwCompLen * sizeof(WCHAR);
69 unsigned int byte_offset = dwOffset * sizeof(WCHAR);
70 unsigned int byte_selection = selLength * sizeof(WCHAR);
71 int byte_expansion = byte_length - byte_selection;
72 LPBYTE ptr_new;
74 TRACE("( %i, %i, %p, %d):\n", dwOffset, selLength, lpComp, dwCompLen );
76 if (byte_expansion + dwCompStringLength >= dwCompStringSize)
78 ptr_new = realloc( CompositionString, dwCompStringSize + byte_expansion );
79 if (ptr_new == NULL)
81 ERR("Couldn't expand composition string buffer\n");
82 return;
85 CompositionString = ptr_new;
86 dwCompStringSize += byte_expansion;
89 ptr_new = CompositionString + byte_offset;
90 memmove(ptr_new + byte_length, ptr_new + byte_selection,
91 dwCompStringLength - byte_offset - byte_selection);
92 if (lpComp) memcpy(ptr_new, lpComp, byte_length);
93 dwCompStringLength += byte_expansion;
95 x11drv_client_func( client_func_ime_set_composition_string,
96 CompositionString, dwCompStringLength );
99 void X11DRV_XIMLookupChars( const char *str, DWORD count )
101 WCHAR *output;
102 DWORD len;
104 TRACE("%p %u\n", str, count);
106 if (!(output = malloc( count * sizeof(WCHAR) ))) return;
107 len = ntdll_umbstowcs( str, count, output, count );
109 x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) );
110 free( output );
113 static BOOL XIMPreEditStateNotifyCallback(XIC xic, XPointer p, XPointer data)
115 const struct x11drv_win_data * const win_data = (struct x11drv_win_data *)p;
116 const XIMPreeditState state = ((XIMPreeditStateNotifyCallbackStruct *)data)->state;
118 TRACE("xic = %p, win = %lx, state = %lu\n", xic, win_data->whole_window, state);
119 switch (state)
121 case XIMPreeditEnable:
122 x11drv_client_call( client_ime_set_open_status, TRUE );
123 break;
124 case XIMPreeditDisable:
125 x11drv_client_call( client_ime_set_open_status, FALSE );
126 break;
127 default:
128 break;
131 return TRUE;
134 static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
136 TRACE("PreEditStartCallback %p\n",ic);
137 x11drv_client_call( client_ime_set_composition_status, TRUE );
138 ximInComposeMode = TRUE;
139 return -1;
142 static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
144 TRACE("PreeditDoneCallback %p\n",ic);
145 ximInComposeMode = FALSE;
146 if (dwCompStringSize)
147 free( CompositionString );
148 dwCompStringSize = 0;
149 dwCompStringLength = 0;
150 CompositionString = NULL;
151 x11drv_client_call( client_ime_set_composition_status, FALSE );
154 static void XIMPreEditDrawCallback(XIM ic, XPointer client_data,
155 XIMPreeditDrawCallbackStruct *P_DR)
157 TRACE("PreEditDrawCallback %p\n",ic);
159 if (P_DR)
161 int sel = P_DR->chg_first;
162 int len = P_DR->chg_length;
163 if (P_DR->text)
165 if (! P_DR->text->encoding_is_wchar)
167 size_t text_len;
168 WCHAR *output;
170 TRACE("multibyte\n");
171 text_len = strlen( P_DR->text->string.multi_byte );
172 if ((output = malloc( text_len * sizeof(WCHAR) )))
174 text_len = ntdll_umbstowcs( P_DR->text->string.multi_byte, text_len,
175 output, text_len );
177 X11DRV_ImmSetInternalString( sel, len, output, text_len );
178 free( output );
181 else
183 FIXME("wchar PROBIBILY WRONG\n");
184 X11DRV_ImmSetInternalString (sel, len,
185 (LPWSTR)P_DR->text->string.wide_char,
186 P_DR->text->length);
189 else
190 X11DRV_ImmSetInternalString (sel, len, NULL, 0);
191 x11drv_client_call( client_ime_set_cursor_pos, P_DR->caret );
193 TRACE("Finished\n");
196 static void XIMPreEditCaretCallback(XIC ic, XPointer client_data,
197 XIMPreeditCaretCallbackStruct *P_C)
199 TRACE("PreeditCaretCallback %p\n",ic);
201 if (P_C)
203 int pos = x11drv_client_call( client_ime_get_cursor_pos, 0 );
204 TRACE("pos: %d\n", pos);
205 switch(P_C->direction)
207 case XIMForwardChar:
208 case XIMForwardWord:
209 pos++;
210 break;
211 case XIMBackwardChar:
212 case XIMBackwardWord:
213 pos--;
214 break;
215 case XIMLineStart:
216 pos = 0;
217 break;
218 case XIMAbsolutePosition:
219 pos = P_C->position;
220 break;
221 case XIMDontChange:
222 P_C->position = pos;
223 return;
224 case XIMCaretUp:
225 case XIMCaretDown:
226 case XIMPreviousLine:
227 case XIMNextLine:
228 case XIMLineEnd:
229 FIXME("Not implemented\n");
230 break;
232 x11drv_client_call( client_ime_set_cursor_pos, pos );
233 P_C->position = pos;
235 TRACE("Finished\n");
238 NTSTATUS x11drv_xim_reset( void *hwnd )
240 XIC ic = X11DRV_get_ic(hwnd);
241 if (ic)
243 char* leftover;
244 TRACE("Forcing Reset %p\n",ic);
245 leftover = XmbResetIC(ic);
246 XFree(leftover);
248 return 0;
251 NTSTATUS x11drv_xim_preedit_state( void *arg )
253 struct xim_preedit_state_params *params = arg;
254 XIC ic;
255 XIMPreeditState state;
256 XVaNestedList attr;
258 ic = X11DRV_get_ic( params->hwnd );
259 if (!ic)
260 return 0;
262 if (params->open)
263 state = XIMPreeditEnable;
264 else
265 state = XIMPreeditDisable;
267 attr = XVaCreateNestedList(0, XNPreeditState, state, NULL);
268 if (attr != NULL)
270 XSetICValues(ic, XNPreeditAttributes, attr, NULL);
271 XFree(attr);
273 return 0;
277 /***********************************************************************
278 * X11DRV_InitXIM
280 * Process-wide XIM initialization.
282 BOOL X11DRV_InitXIM( const WCHAR *input_style )
284 static const WCHAR offthespotW[] = {'o','f','f','t','h','e','s','p','o','t',0};
285 static const WCHAR overthespotW[] = {'o','v','e','r','t','h','e','s','p','o','t',0};
286 static const WCHAR rootW[] = {'r','o','o','t',0};
288 if (!wcsicmp( input_style, offthespotW ))
289 ximStyleRequest = STYLE_OFFTHESPOT;
290 else if (!wcsicmp( input_style, overthespotW ))
291 ximStyleRequest = STYLE_OVERTHESPOT;
292 else if (!wcsicmp( input_style, rootW ))
293 ximStyleRequest = STYLE_ROOT;
295 if (!XSupportsLocale())
297 WARN("X does not support locale.\n");
298 return FALSE;
300 if (XSetLocaleModifiers("") == NULL)
302 WARN("Could not set locale modifiers.\n");
303 return FALSE;
305 return TRUE;
309 static void open_xim_callback( Display *display, XPointer ptr, XPointer data );
311 static void X11DRV_DestroyIM(XIM xim, XPointer p, XPointer data)
313 struct x11drv_thread_data *thread_data = x11drv_thread_data();
315 TRACE("xim = %p, p = %p\n", xim, p);
316 thread_data->xim = NULL;
317 ximStyle = 0;
318 XRegisterIMInstantiateCallback( thread_data->display, NULL, NULL, NULL, open_xim_callback, NULL );
321 /***********************************************************************
322 * X11DRV Ime creation
324 * Should always be called with the x11 lock held
326 static BOOL open_xim( Display *display )
328 struct x11drv_thread_data *thread_data = x11drv_thread_data();
329 XIMStyle ximStyleNone;
330 XIMStyles *ximStyles = NULL;
331 INT i;
332 XIM xim;
333 XIMCallback destroy;
335 xim = XOpenIM(display, NULL, NULL, NULL);
336 if (xim == NULL)
338 WARN("Could not open input method.\n");
339 return FALSE;
342 destroy.client_data = NULL;
343 destroy.callback = X11DRV_DestroyIM;
344 if (XSetIMValues(xim, XNDestroyCallback, &destroy, NULL))
346 WARN("Could not set destroy callback.\n");
349 TRACE("xim = %p\n", xim);
350 TRACE("X display of IM = %p\n", XDisplayOfIM(xim));
351 TRACE("Using %s locale of Input Method\n", XLocaleOfIM(xim));
353 XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL);
354 if (ximStyles == 0)
356 WARN("Could not find supported input style.\n");
357 XCloseIM(xim);
358 return FALSE;
360 else
362 TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles);
364 ximStyleRoot = 0;
365 ximStyleNone = 0;
367 for (i = 0; i < ximStyles->count_styles; ++i)
369 int style = ximStyles->supported_styles[i];
370 TRACE("ximStyles[%d] = %s%s%s%s%s\n", i,
371 (style&XIMPreeditArea)?"XIMPreeditArea ":"",
372 (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"",
373 (style&XIMPreeditPosition)?"XIMPreeditPosition ":"",
374 (style&XIMPreeditNothing)?"XIMPreeditNothing ":"",
375 (style&XIMPreeditNone)?"XIMPreeditNone ":"");
376 if (!ximStyle && (ximStyles->supported_styles[i] ==
377 ximStyleRequest))
379 ximStyle = ximStyleRequest;
380 TRACE("Setting Style: ximStyle = ximStyleRequest\n");
382 else if (!ximStyleRoot &&(ximStyles->supported_styles[i] ==
383 STYLE_ROOT))
385 ximStyleRoot = STYLE_ROOT;
386 TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n");
388 else if (!ximStyleNone && (ximStyles->supported_styles[i] ==
389 STYLE_NONE))
391 TRACE("Setting Style: ximStyleNone = STYLE_NONE\n");
392 ximStyleNone = STYLE_NONE;
395 XFree(ximStyles);
397 if (ximStyle == 0)
398 ximStyle = ximStyleRoot;
400 if (ximStyle == 0)
401 ximStyle = ximStyleNone;
404 thread_data->xim = xim;
406 if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0 ||
407 (ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0)
409 char **list;
410 int count;
411 thread_data->font_set = XCreateFontSet(display, "fixed",
412 &list, &count, NULL);
413 TRACE("ximFontSet = %p\n", thread_data->font_set);
414 TRACE("list = %p, count = %d\n", list, count);
415 if (list != NULL)
417 int i;
418 for (i = 0; i < count; ++i)
419 TRACE("list[%d] = %s\n", i, list[i]);
420 XFreeStringList(list);
423 else
424 thread_data->font_set = NULL;
426 x11drv_client_call( client_ime_update_association, 0 );
427 return TRUE;
430 static void open_xim_callback( Display *display, XPointer ptr, XPointer data )
432 if (open_xim( display ))
433 XUnregisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL);
436 void X11DRV_SetupXIM(void)
438 Display *display = thread_display();
440 if (!open_xim( display ))
441 XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL );
444 static BOOL X11DRV_DestroyIC(XIC xic, XPointer p, XPointer data)
446 struct x11drv_win_data *win_data = (struct x11drv_win_data *)p;
447 TRACE("xic = %p, win = %lx\n", xic, win_data->whole_window);
448 win_data->xic = NULL;
449 return TRUE;
453 XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data)
455 XPoint spot = {0};
456 XVaNestedList preedit = NULL;
457 XVaNestedList status = NULL;
458 XIC xic;
459 XICCallback destroy = {(XPointer)data, X11DRV_DestroyIC};
460 XICCallback P_StateNotifyCB, P_StartCB, P_DoneCB, P_DrawCB, P_CaretCB;
461 LCID lcid;
462 Window win = data->whole_window;
463 XFontSet fontSet = x11drv_thread_data()->font_set;
465 TRACE("xim = %p\n", xim);
467 lcid = NtCurrentTeb()->CurrentLocale;
468 if (!lcid) NtQueryDefaultLocale( TRUE, &lcid );
470 /* use complex and slow XIC initialization method only for CJK */
471 switch (PRIMARYLANGID(LANGIDFROMLCID(lcid)))
473 case LANG_CHINESE:
474 case LANG_JAPANESE:
475 case LANG_KOREAN:
476 break;
478 default:
479 xic = XCreateIC(xim,
480 XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
481 XNClientWindow, win,
482 XNFocusWindow, win,
483 XNDestroyCallback, &destroy,
484 NULL);
485 data->xic = xic;
486 return xic;
489 /* create callbacks */
490 P_StateNotifyCB.client_data = (XPointer)data;
491 P_StartCB.client_data = NULL;
492 P_DoneCB.client_data = NULL;
493 P_DrawCB.client_data = NULL;
494 P_CaretCB.client_data = NULL;
495 P_StateNotifyCB.callback = XIMPreEditStateNotifyCallback;
496 P_StartCB.callback = XIMPreEditStartCallback;
497 P_DoneCB.callback = (XICProc)XIMPreEditDoneCallback;
498 P_DrawCB.callback = (XICProc)XIMPreEditDrawCallback;
499 P_CaretCB.callback = (XICProc)XIMPreEditCaretCallback;
501 if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0)
503 preedit = XVaCreateNestedList(0,
504 XNFontSet, fontSet,
505 XNSpotLocation, &spot,
506 XNPreeditStateNotifyCallback, &P_StateNotifyCB,
507 XNPreeditStartCallback, &P_StartCB,
508 XNPreeditDoneCallback, &P_DoneCB,
509 XNPreeditDrawCallback, &P_DrawCB,
510 XNPreeditCaretCallback, &P_CaretCB,
511 NULL);
512 TRACE("preedit = %p\n", preedit);
514 else
516 preedit = XVaCreateNestedList(0,
517 XNPreeditStateNotifyCallback, &P_StateNotifyCB,
518 XNPreeditStartCallback, &P_StartCB,
519 XNPreeditDoneCallback, &P_DoneCB,
520 XNPreeditDrawCallback, &P_DrawCB,
521 XNPreeditCaretCallback, &P_CaretCB,
522 NULL);
524 TRACE("preedit = %p\n", preedit);
527 if ((ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0)
529 status = XVaCreateNestedList(0,
530 XNFontSet, fontSet,
531 NULL);
532 TRACE("status = %p\n", status);
535 if (preedit != NULL && status != NULL)
537 xic = XCreateIC(xim,
538 XNInputStyle, ximStyle,
539 XNPreeditAttributes, preedit,
540 XNStatusAttributes, status,
541 XNClientWindow, win,
542 XNFocusWindow, win,
543 XNDestroyCallback, &destroy,
544 NULL);
546 else if (preedit != NULL)
548 xic = XCreateIC(xim,
549 XNInputStyle, ximStyle,
550 XNPreeditAttributes, preedit,
551 XNClientWindow, win,
552 XNFocusWindow, win,
553 XNDestroyCallback, &destroy,
554 NULL);
556 else if (status != NULL)
558 xic = XCreateIC(xim,
559 XNInputStyle, ximStyle,
560 XNStatusAttributes, status,
561 XNClientWindow, win,
562 XNFocusWindow, win,
563 XNDestroyCallback, &destroy,
564 NULL);
566 else
568 xic = XCreateIC(xim,
569 XNInputStyle, ximStyle,
570 XNClientWindow, win,
571 XNFocusWindow, win,
572 XNDestroyCallback, &destroy,
573 NULL);
576 TRACE("xic = %p\n", xic);
577 data->xic = xic;
579 if (preedit != NULL)
580 XFree(preedit);
581 if (status != NULL)
582 XFree(status);
584 return xic;