widl: Generate helper macros for WinRT implementation.
[wine/zf.git] / dlls / winex11.drv / xim.c
blob44fe62e90068f24be4bb57dcb7bbc0edd13f5e05
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 #include "config.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "wingdi.h"
30 #include "winnls.h"
31 #include "winternl.h"
32 #include "x11drv.h"
33 #include "imm.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(xim);
38 #ifndef HAVE_XICCALLBACK_CALLBACK
39 #define XICCallback XIMCallback
40 #define XICProc XIMProc
41 #endif
43 BOOL ximInComposeMode=FALSE;
45 /* moved here from imm32 for dll separation */
46 static DWORD dwCompStringLength = 0;
47 static LPBYTE CompositionString = NULL;
48 static DWORD dwCompStringSize = 0;
50 #define STYLE_OFFTHESPOT (XIMPreeditArea | XIMStatusArea)
51 #define STYLE_OVERTHESPOT (XIMPreeditPosition | XIMStatusNothing)
52 #define STYLE_ROOT (XIMPreeditNothing | XIMStatusNothing)
53 /* this uses all the callbacks to utilize full IME support */
54 #define STYLE_CALLBACK (XIMPreeditCallbacks | XIMStatusNothing)
55 /* in order to enable deadkey support */
56 #define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing)
58 static XIMStyle ximStyle = 0;
59 static XIMStyle ximStyleRoot = 0;
60 static XIMStyle ximStyleRequest = STYLE_CALLBACK;
62 static void X11DRV_ImmSetInternalString(DWORD dwOffset,
63 DWORD selLength, LPWSTR lpComp, DWORD dwCompLen)
65 /* Composition strings are edited in chunks */
66 unsigned int byte_length = dwCompLen * sizeof(WCHAR);
67 unsigned int byte_offset = dwOffset * sizeof(WCHAR);
68 unsigned int byte_selection = selLength * sizeof(WCHAR);
69 int byte_expansion = byte_length - byte_selection;
70 LPBYTE ptr_new;
72 TRACE("( %i, %i, %p, %d):\n", dwOffset, selLength, lpComp, dwCompLen );
74 if (byte_expansion + dwCompStringLength >= dwCompStringSize)
76 if (CompositionString)
77 ptr_new = HeapReAlloc(GetProcessHeap(), 0, CompositionString,
78 dwCompStringSize + byte_expansion);
79 else
80 ptr_new = HeapAlloc(GetProcessHeap(), 0,
81 dwCompStringSize + byte_expansion);
83 if (ptr_new == NULL)
85 ERR("Couldn't expand composition string buffer\n");
86 return;
89 CompositionString = ptr_new;
90 dwCompStringSize += byte_expansion;
93 ptr_new = CompositionString + byte_offset;
94 memmove(ptr_new + byte_length, ptr_new + byte_selection,
95 dwCompStringLength - byte_offset - byte_selection);
96 if (lpComp) memcpy(ptr_new, lpComp, byte_length);
97 dwCompStringLength += byte_expansion;
99 IME_SetCompositionString(SCS_SETSTR, CompositionString,
100 dwCompStringLength, NULL, 0);
103 void X11DRV_XIMLookupChars( const char *str, DWORD count )
105 DWORD dwOutput;
106 WCHAR *wcOutput;
107 HWND focus;
109 TRACE("%p %u\n", str, count);
111 dwOutput = MultiByteToWideChar(CP_UNIXCP, 0, str, count, NULL, 0);
112 wcOutput = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * dwOutput);
113 if (wcOutput == NULL)
114 return;
115 MultiByteToWideChar(CP_UNIXCP, 0, str, count, wcOutput, dwOutput);
117 if ((focus = GetFocus()))
118 IME_UpdateAssociation(focus);
120 IME_SetResultString(wcOutput, dwOutput);
121 HeapFree(GetProcessHeap(), 0, wcOutput);
124 static BOOL XIMPreEditStateNotifyCallback(XIC xic, XPointer p, XPointer data)
126 const struct x11drv_win_data * const win_data = (struct x11drv_win_data *)p;
127 const XIMPreeditState state = ((XIMPreeditStateNotifyCallbackStruct *)data)->state;
129 TRACE("xic = %p, win = %lx, state = %lu\n", xic, win_data->whole_window, state);
130 switch (state)
132 case XIMPreeditEnable:
133 IME_SetOpenStatus(TRUE);
134 break;
135 case XIMPreeditDisable:
136 IME_SetOpenStatus(FALSE);
137 break;
138 default:
139 break;
141 return TRUE;
144 static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
146 TRACE("PreEditStartCallback %p\n",ic);
147 IME_SetCompositionStatus(TRUE);
148 ximInComposeMode = TRUE;
149 return -1;
152 static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
154 TRACE("PreeditDoneCallback %p\n",ic);
155 ximInComposeMode = FALSE;
156 if (dwCompStringSize)
157 HeapFree(GetProcessHeap(), 0, CompositionString);
158 dwCompStringSize = 0;
159 dwCompStringLength = 0;
160 CompositionString = NULL;
161 IME_SetCompositionStatus(FALSE);
164 static void XIMPreEditDrawCallback(XIM ic, XPointer client_data,
165 XIMPreeditDrawCallbackStruct *P_DR)
167 TRACE("PreEditDrawCallback %p\n",ic);
169 if (P_DR)
171 int sel = P_DR->chg_first;
172 int len = P_DR->chg_length;
173 if (P_DR->text)
175 if (! P_DR->text->encoding_is_wchar)
177 DWORD dwOutput;
178 WCHAR *wcOutput;
180 TRACE("multibyte\n");
181 dwOutput = MultiByteToWideChar(CP_UNIXCP, 0,
182 P_DR->text->string.multi_byte, -1,
183 NULL, 0);
184 wcOutput = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * dwOutput);
185 if (wcOutput)
187 dwOutput = MultiByteToWideChar(CP_UNIXCP, 0,
188 P_DR->text->string.multi_byte, -1,
189 wcOutput, dwOutput);
191 /* ignore null */
192 dwOutput --;
193 X11DRV_ImmSetInternalString (sel, len, wcOutput, dwOutput);
194 HeapFree(GetProcessHeap(), 0, wcOutput);
197 else
199 FIXME("wchar PROBIBILY WRONG\n");
200 X11DRV_ImmSetInternalString (sel, len,
201 (LPWSTR)P_DR->text->string.wide_char,
202 P_DR->text->length);
205 else
206 X11DRV_ImmSetInternalString (sel, len, NULL, 0);
207 IME_SetCursorPos(P_DR->caret);
209 TRACE("Finished\n");
212 static void XIMPreEditCaretCallback(XIC ic, XPointer client_data,
213 XIMPreeditCaretCallbackStruct *P_C)
215 TRACE("PreeditCaretCallback %p\n",ic);
217 if (P_C)
219 int pos = IME_GetCursorPos();
220 TRACE("pos: %d\n", pos);
221 switch(P_C->direction)
223 case XIMForwardChar:
224 case XIMForwardWord:
225 pos++;
226 break;
227 case XIMBackwardChar:
228 case XIMBackwardWord:
229 pos--;
230 break;
231 case XIMLineStart:
232 pos = 0;
233 break;
234 case XIMAbsolutePosition:
235 pos = P_C->position;
236 break;
237 case XIMDontChange:
238 P_C->position = pos;
239 return;
240 case XIMCaretUp:
241 case XIMCaretDown:
242 case XIMPreviousLine:
243 case XIMNextLine:
244 case XIMLineEnd:
245 FIXME("Not implemented\n");
246 break;
248 IME_SetCursorPos(pos);
249 P_C->position = pos;
251 TRACE("Finished\n");
254 void X11DRV_ForceXIMReset(HWND hwnd)
256 XIC ic = X11DRV_get_ic(hwnd);
257 if (ic)
259 char* leftover;
260 TRACE("Forcing Reset %p\n",ic);
261 leftover = XmbResetIC(ic);
262 XFree(leftover);
266 void X11DRV_SetPreeditState(HWND hwnd, BOOL fOpen)
268 XIC ic;
269 XIMPreeditState state;
270 XVaNestedList attr;
272 ic = X11DRV_get_ic(hwnd);
273 if (!ic)
274 return;
276 if (fOpen)
277 state = XIMPreeditEnable;
278 else
279 state = XIMPreeditDisable;
281 attr = XVaCreateNestedList(0, XNPreeditState, state, NULL);
282 if (attr != NULL)
284 XSetICValues(ic, XNPreeditAttributes, attr, NULL);
285 XFree(attr);
290 /***********************************************************************
291 * X11DRV_InitXIM
293 * Process-wide XIM initialization.
295 BOOL X11DRV_InitXIM( const char *input_style )
297 if (!_strnicmp(input_style, "offthespot", -1))
298 ximStyleRequest = STYLE_OFFTHESPOT;
299 else if (!_strnicmp(input_style, "overthespot", -1))
300 ximStyleRequest = STYLE_OVERTHESPOT;
301 else if (!_strnicmp(input_style, "root", -1))
302 ximStyleRequest = STYLE_ROOT;
304 if (!XSupportsLocale())
306 WARN("X does not support locale.\n");
307 return FALSE;
309 if (XSetLocaleModifiers("") == NULL)
311 WARN("Could not set locale modifiers.\n");
312 return FALSE;
314 return TRUE;
318 static void open_xim_callback( Display *display, XPointer ptr, XPointer data );
320 static void X11DRV_DestroyIM(XIM xim, XPointer p, XPointer data)
322 struct x11drv_thread_data *thread_data = x11drv_thread_data();
324 TRACE("xim = %p, p = %p\n", xim, p);
325 thread_data->xim = NULL;
326 ximStyle = 0;
327 XRegisterIMInstantiateCallback( thread_data->display, NULL, NULL, NULL, open_xim_callback, NULL );
330 /***********************************************************************
331 * X11DRV Ime creation
333 * Should always be called with the x11 lock held
335 static BOOL open_xim( Display *display )
337 struct x11drv_thread_data *thread_data = x11drv_thread_data();
338 XIMStyle ximStyleNone;
339 XIMStyles *ximStyles = NULL;
340 INT i;
341 XIM xim;
342 XIMCallback destroy;
344 xim = XOpenIM(display, NULL, NULL, NULL);
345 if (xim == NULL)
347 WARN("Could not open input method.\n");
348 return FALSE;
351 destroy.client_data = NULL;
352 destroy.callback = X11DRV_DestroyIM;
353 if (XSetIMValues(xim, XNDestroyCallback, &destroy, NULL))
355 WARN("Could not set destroy callback.\n");
358 TRACE("xim = %p\n", xim);
359 TRACE("X display of IM = %p\n", XDisplayOfIM(xim));
360 TRACE("Using %s locale of Input Method\n", XLocaleOfIM(xim));
362 XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL);
363 if (ximStyles == 0)
365 WARN("Could not find supported input style.\n");
366 XCloseIM(xim);
367 return FALSE;
369 else
371 TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles);
373 ximStyleRoot = 0;
374 ximStyleNone = 0;
376 for (i = 0; i < ximStyles->count_styles; ++i)
378 int style = ximStyles->supported_styles[i];
379 TRACE("ximStyles[%d] = %s%s%s%s%s\n", i,
380 (style&XIMPreeditArea)?"XIMPreeditArea ":"",
381 (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"",
382 (style&XIMPreeditPosition)?"XIMPreeditPosition ":"",
383 (style&XIMPreeditNothing)?"XIMPreeditNothing ":"",
384 (style&XIMPreeditNone)?"XIMPreeditNone ":"");
385 if (!ximStyle && (ximStyles->supported_styles[i] ==
386 ximStyleRequest))
388 ximStyle = ximStyleRequest;
389 TRACE("Setting Style: ximStyle = ximStyleRequest\n");
391 else if (!ximStyleRoot &&(ximStyles->supported_styles[i] ==
392 STYLE_ROOT))
394 ximStyleRoot = STYLE_ROOT;
395 TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n");
397 else if (!ximStyleNone && (ximStyles->supported_styles[i] ==
398 STYLE_NONE))
400 TRACE("Setting Style: ximStyleNone = STYLE_NONE\n");
401 ximStyleNone = STYLE_NONE;
404 XFree(ximStyles);
406 if (ximStyle == 0)
407 ximStyle = ximStyleRoot;
409 if (ximStyle == 0)
410 ximStyle = ximStyleNone;
413 thread_data->xim = xim;
415 if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0 ||
416 (ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0)
418 char **list;
419 int count;
420 thread_data->font_set = XCreateFontSet(display, "fixed",
421 &list, &count, NULL);
422 TRACE("ximFontSet = %p\n", thread_data->font_set);
423 TRACE("list = %p, count = %d\n", list, count);
424 if (list != NULL)
426 int i;
427 for (i = 0; i < count; ++i)
428 TRACE("list[%d] = %s\n", i, list[i]);
429 XFreeStringList(list);
432 else
433 thread_data->font_set = NULL;
435 IME_UpdateAssociation(NULL);
436 return TRUE;
439 static void open_xim_callback( Display *display, XPointer ptr, XPointer data )
441 if (open_xim( display ))
442 XUnregisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL);
445 void X11DRV_SetupXIM(void)
447 Display *display = thread_display();
449 if (!open_xim( display ))
450 XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL );
453 static BOOL X11DRV_DestroyIC(XIC xic, XPointer p, XPointer data)
455 struct x11drv_win_data *win_data = (struct x11drv_win_data *)p;
456 TRACE("xic = %p, win = %lx\n", xic, win_data->whole_window);
457 win_data->xic = NULL;
458 return TRUE;
462 XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data)
464 XPoint spot = {0};
465 XVaNestedList preedit = NULL;
466 XVaNestedList status = NULL;
467 XIC xic;
468 XICCallback destroy = {(XPointer)data, X11DRV_DestroyIC};
469 XICCallback P_StateNotifyCB, P_StartCB, P_DoneCB, P_DrawCB, P_CaretCB;
470 LANGID langid = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale()));
471 Window win = data->whole_window;
472 XFontSet fontSet = x11drv_thread_data()->font_set;
474 TRACE("xim = %p\n", xim);
476 /* use complex and slow XIC initialization method only for CJK */
477 if (langid != LANG_CHINESE &&
478 langid != LANG_JAPANESE &&
479 langid != LANG_KOREAN)
481 xic = XCreateIC(xim,
482 XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
483 XNClientWindow, win,
484 XNFocusWindow, win,
485 XNDestroyCallback, &destroy,
486 NULL);
487 data->xic = xic;
488 return xic;
491 /* create callbacks */
492 P_StateNotifyCB.client_data = (XPointer)data;
493 P_StartCB.client_data = NULL;
494 P_DoneCB.client_data = NULL;
495 P_DrawCB.client_data = NULL;
496 P_CaretCB.client_data = NULL;
497 P_StateNotifyCB.callback = XIMPreEditStateNotifyCallback;
498 P_StartCB.callback = XIMPreEditStartCallback;
499 P_DoneCB.callback = (XICProc)XIMPreEditDoneCallback;
500 P_DrawCB.callback = (XICProc)XIMPreEditDrawCallback;
501 P_CaretCB.callback = (XICProc)XIMPreEditCaretCallback;
503 if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0)
505 preedit = XVaCreateNestedList(0,
506 XNFontSet, fontSet,
507 XNSpotLocation, &spot,
508 XNPreeditStateNotifyCallback, &P_StateNotifyCB,
509 XNPreeditStartCallback, &P_StartCB,
510 XNPreeditDoneCallback, &P_DoneCB,
511 XNPreeditDrawCallback, &P_DrawCB,
512 XNPreeditCaretCallback, &P_CaretCB,
513 NULL);
514 TRACE("preedit = %p\n", preedit);
516 else
518 preedit = XVaCreateNestedList(0,
519 XNPreeditStateNotifyCallback, &P_StateNotifyCB,
520 XNPreeditStartCallback, &P_StartCB,
521 XNPreeditDoneCallback, &P_DoneCB,
522 XNPreeditDrawCallback, &P_DrawCB,
523 XNPreeditCaretCallback, &P_CaretCB,
524 NULL);
526 TRACE("preedit = %p\n", preedit);
529 if ((ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0)
531 status = XVaCreateNestedList(0,
532 XNFontSet, fontSet,
533 NULL);
534 TRACE("status = %p\n", status);
537 if (preedit != NULL && status != NULL)
539 xic = XCreateIC(xim,
540 XNInputStyle, ximStyle,
541 XNPreeditAttributes, preedit,
542 XNStatusAttributes, status,
543 XNClientWindow, win,
544 XNFocusWindow, win,
545 XNDestroyCallback, &destroy,
546 NULL);
548 else if (preedit != NULL)
550 xic = XCreateIC(xim,
551 XNInputStyle, ximStyle,
552 XNPreeditAttributes, preedit,
553 XNClientWindow, win,
554 XNFocusWindow, win,
555 XNDestroyCallback, &destroy,
556 NULL);
558 else if (status != NULL)
560 xic = XCreateIC(xim,
561 XNInputStyle, ximStyle,
562 XNStatusAttributes, status,
563 XNClientWindow, win,
564 XNFocusWindow, win,
565 XNDestroyCallback, &destroy,
566 NULL);
568 else
570 xic = XCreateIC(xim,
571 XNInputStyle, ximStyle,
572 XNClientWindow, win,
573 XNFocusWindow, win,
574 XNDestroyCallback, &destroy,
575 NULL);
578 TRACE("xic = %p\n", xic);
579 data->xic = xic;
581 if (preedit != NULL)
582 XFree(preedit);
583 if (status != NULL)
584 XFree(status);
586 return xic;