winex11: Rename preedit buffer and related variables.
[wine.git] / dlls / winex11.drv / xim.c
blob4372faed3d6b9ef511465051b210ed272b734e44
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 static BYTE *ime_comp_buf;
48 static DWORD ime_comp_len;
49 static DWORD ime_comp_max;
51 static XIMStyle input_style = 0;
52 static XIMStyle input_style_req = XIMPreeditCallbacks | XIMStatusCallbacks;
54 static const char *debugstr_xim_style( XIMStyle style )
56 char buffer[1024], *buf = buffer;
58 buf += sprintf( buf, "preedit" );
59 if (style & XIMPreeditArea) buf += sprintf( buf, " area" );
60 if (style & XIMPreeditCallbacks) buf += sprintf( buf, " callbacks" );
61 if (style & XIMPreeditPosition) buf += sprintf( buf, " position" );
62 if (style & XIMPreeditNothing) buf += sprintf( buf, " nothing" );
63 if (style & XIMPreeditNone) buf += sprintf( buf, " none" );
65 buf += sprintf( buf, ", status" );
66 if (style & XIMStatusArea) buf += sprintf( buf, " area" );
67 if (style & XIMStatusCallbacks) buf += sprintf( buf, " callbacks" );
68 if (style & XIMStatusNothing) buf += sprintf( buf, " nothing" );
69 if (style & XIMStatusNone) buf += sprintf( buf, " none" );
71 return wine_dbg_sprintf( "%s", buffer );
74 static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text, UINT new_len )
76 /* Composition strings are edited in chunks */
77 unsigned int byte_length = new_len * sizeof(WCHAR);
78 unsigned int byte_offset = offset * sizeof(WCHAR);
79 unsigned int byte_selection = old_len * sizeof(WCHAR);
80 int byte_expansion = byte_length - byte_selection;
81 BYTE *ptr_new;
83 TRACE( "(%i, %i, %p, %d):\n", offset, old_len, text, new_len );
85 if (byte_expansion + ime_comp_len >= ime_comp_max)
87 if (!(ptr_new = realloc( ime_comp_buf, ime_comp_max + byte_expansion )))
89 ERR("Couldn't expand composition string buffer\n");
90 return;
93 ime_comp_buf = ptr_new;
94 ime_comp_max += byte_expansion;
97 ptr_new = ime_comp_buf + byte_offset;
98 memmove( ptr_new + byte_length, ptr_new + byte_selection,
99 ime_comp_len - byte_offset - byte_selection );
100 if (text) memcpy( ptr_new, text, byte_length );
101 ime_comp_len += byte_expansion;
103 x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, ime_comp_len );
106 void X11DRV_XIMLookupChars( const char *str, UINT count )
108 WCHAR *output;
109 DWORD len;
111 TRACE("%p %u\n", str, count);
113 if (!(output = malloc( count * sizeof(WCHAR) ))) return;
114 len = ntdll_umbstowcs( str, count, output, count );
116 x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) );
117 free( output );
120 static BOOL xic_preedit_state_notify( XIC xic, XPointer user, XPointer arg )
122 XIMPreeditStateNotifyCallbackStruct *params = (void *)arg;
123 const XIMPreeditState state = params->state;
124 HWND hwnd = (HWND)user;
126 TRACE( "xic %p, hwnd %p, state %lu\n", xic, hwnd, state );
128 switch (state)
130 case XIMPreeditEnable:
131 x11drv_client_call( client_ime_set_open_status, TRUE );
132 break;
133 case XIMPreeditDisable:
134 x11drv_client_call( client_ime_set_open_status, FALSE );
135 break;
136 default:
137 break;
140 return TRUE;
143 static int xic_preedit_start( XIC xic, XPointer user, XPointer arg )
145 HWND hwnd = (HWND)user;
147 TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
149 x11drv_client_call( client_ime_set_composition_status, TRUE );
150 ximInComposeMode = TRUE;
151 return -1;
154 static int xic_preedit_done( XIC xic, XPointer user, XPointer arg )
156 HWND hwnd = (HWND)user;
158 TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
160 ximInComposeMode = FALSE;
161 free( ime_comp_buf );
162 ime_comp_buf = NULL;
163 ime_comp_max = 0;
164 ime_comp_len = 0;
165 x11drv_client_call( client_ime_set_composition_status, FALSE );
166 return 0;
169 static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg )
171 XIMPreeditDrawCallbackStruct *params = (void *)arg;
172 HWND hwnd = (HWND)user;
173 XIMText *text;
175 TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
177 if (!params) return 0;
179 if (!(text = params->text))
180 xim_update_comp_string( params->chg_first, params->chg_length, NULL, 0 );
181 else
183 size_t text_len;
184 WCHAR *output;
185 char *str;
186 int len;
188 if (!text->encoding_is_wchar) str = text->string.multi_byte;
189 else if ((len = wcstombs( NULL, text->string.wide_char, text->length )) < 0) str = NULL;
190 else if ((str = malloc( len + 1 )))
192 wcstombs( str, text->string.wide_char, len );
193 str[len] = 0;
196 text_len = str ? strlen( str ) : 0;
197 if ((output = malloc( text_len * sizeof(WCHAR) )))
199 text_len = ntdll_umbstowcs( str, text_len, output, text_len );
200 xim_update_comp_string( params->chg_first, params->chg_length, output, text_len );
201 free( output );
204 if (str != text->string.multi_byte) free( str );
207 x11drv_client_call( client_ime_set_cursor_pos, params->caret );
209 return 0;
212 static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg )
214 XIMPreeditCaretCallbackStruct *params = (void *)arg;
215 HWND hwnd = (HWND)user;
216 int pos;
218 TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
220 if (!params) return 0;
222 pos = x11drv_client_call( client_ime_get_cursor_pos, 0 );
223 switch (params->direction)
225 case XIMForwardChar:
226 case XIMForwardWord:
227 pos++;
228 break;
229 case XIMBackwardChar:
230 case XIMBackwardWord:
231 pos--;
232 break;
233 case XIMLineStart:
234 pos = 0;
235 break;
236 case XIMAbsolutePosition:
237 pos = params->position;
238 break;
239 case XIMDontChange:
240 params->position = pos;
241 return 0;
242 case XIMCaretUp:
243 case XIMCaretDown:
244 case XIMPreviousLine:
245 case XIMNextLine:
246 case XIMLineEnd:
247 FIXME( "Not implemented\n" );
248 break;
250 x11drv_client_call( client_ime_set_cursor_pos, pos );
251 params->position = pos;
253 return 0;
256 static int xic_status_start( XIC xic, XPointer user, XPointer arg )
258 HWND hwnd = (HWND)user;
259 TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
260 return 0;
263 static int xic_status_done( XIC xic, XPointer user, XPointer arg )
265 HWND hwnd = (HWND)user;
266 TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
267 return 0;
270 static int xic_status_draw( XIC xic, XPointer user, XPointer arg )
272 HWND hwnd = (HWND)user;
273 TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
274 return 0;
277 NTSTATUS x11drv_xim_reset( void *hwnd )
279 XIC ic = X11DRV_get_ic(hwnd);
280 if (ic)
282 char* leftover;
283 TRACE("Forcing Reset %p\n",ic);
284 leftover = XmbResetIC(ic);
285 XFree(leftover);
287 return 0;
290 NTSTATUS x11drv_xim_preedit_state( void *arg )
292 struct xim_preedit_state_params *params = arg;
293 XIC ic;
294 XIMPreeditState state;
295 XVaNestedList attr;
297 ic = X11DRV_get_ic( params->hwnd );
298 if (!ic)
299 return 0;
301 if (params->open)
302 state = XIMPreeditEnable;
303 else
304 state = XIMPreeditDisable;
306 attr = XVaCreateNestedList(0, XNPreeditState, state, NULL);
307 if (attr != NULL)
309 XSetICValues(ic, XNPreeditAttributes, attr, NULL);
310 XFree(attr);
312 return 0;
315 /***********************************************************************
316 * xim_init
318 BOOL xim_init( const WCHAR *input_style )
320 static const WCHAR offthespotW[] = {'o','f','f','t','h','e','s','p','o','t',0};
321 static const WCHAR overthespotW[] = {'o','v','e','r','t','h','e','s','p','o','t',0};
322 static const WCHAR rootW[] = {'r','o','o','t',0};
324 if (!XSupportsLocale())
326 WARN("X does not support locale.\n");
327 return FALSE;
329 if (XSetLocaleModifiers("") == NULL)
331 WARN("Could not set locale modifiers.\n");
332 return FALSE;
335 if (!wcsicmp( input_style, offthespotW ))
336 input_style_req = XIMPreeditArea | XIMStatusArea;
337 else if (!wcsicmp( input_style, overthespotW ))
338 input_style_req = XIMPreeditPosition | XIMStatusNothing;
339 else if (!wcsicmp( input_style, rootW ))
340 input_style_req = XIMPreeditNothing | XIMStatusNothing;
342 TRACE( "requesting %s style %#lx %s\n", debugstr_w(input_style), input_style_req,
343 debugstr_xim_style( input_style_req ) );
345 return TRUE;
348 static void xim_open( Display *display, XPointer user, XPointer arg );
349 static void xim_destroy( XIM xim, XPointer user, XPointer arg );
351 static XIM xim_create( struct x11drv_thread_data *data )
353 XIMCallback destroy = {.callback = xim_destroy, .client_data = (XPointer)data};
354 XIMStyle input_style_fallback = XIMPreeditNone | XIMStatusNone;
355 XIMStyles *styles = NULL;
356 INT i;
357 XIM xim;
359 if (!(xim = XOpenIM( data->display, NULL, NULL, NULL )))
361 WARN("Could not open input method.\n");
362 return NULL;
365 if (XSetIMValues( xim, XNDestroyCallback, &destroy, NULL ))
366 WARN( "Could not set destroy callback.\n" );
368 TRACE( "xim %p, XDisplayOfIM %p, XLocaleOfIM %s\n", xim, XDisplayOfIM( xim ),
369 debugstr_a(XLocaleOfIM( xim )) );
371 XGetIMValues( xim, XNQueryInputStyle, &styles, NULL );
372 if (!styles)
374 WARN( "Could not find supported input style.\n" );
375 XCloseIM( xim );
376 return NULL;
379 TRACE( "input styles count %u\n", styles->count_styles );
380 for (i = 0, input_style = 0; i < styles->count_styles; ++i)
382 XIMStyle style = styles->supported_styles[i];
383 TRACE( " %u: %#lx %s\n", i, style, debugstr_xim_style( style ) );
385 if (style == input_style_req) input_style = style;
386 if (!input_style && (style & input_style_req)) input_style = style;
387 if (input_style_fallback > style) input_style_fallback = style;
389 XFree(styles);
391 if (!input_style) input_style = input_style_fallback;
392 TRACE( "selected style %#lx %s\n", input_style, debugstr_xim_style( input_style ) );
394 return xim;
397 static void xim_open( Display *display, XPointer user, XPointer arg )
399 struct x11drv_thread_data *data = (void *)user;
400 TRACE( "display %p, data %p, arg %p\n", display, user, arg );
401 if (!(data->xim = xim_create( data ))) return;
402 XUnregisterIMInstantiateCallback( display, NULL, NULL, NULL, xim_open, user );
404 x11drv_client_call( client_ime_update_association, 0 );
407 static void xim_destroy( XIM xim, XPointer user, XPointer arg )
409 struct x11drv_thread_data *data = x11drv_thread_data();
410 TRACE( "xim %p, user %p, arg %p\n", xim, user, arg );
411 if (data->xim != xim) return;
412 data->xim = NULL;
413 XRegisterIMInstantiateCallback( data->display, NULL, NULL, NULL, xim_open, user );
416 void xim_thread_attach( struct x11drv_thread_data *data )
418 Display *display = data->display;
419 int i, count;
420 char **list;
422 data->font_set = XCreateFontSet( display, "fixed", &list, &count, NULL );
423 TRACE( "created XFontSet %p, list %p, count %d\n", data->font_set, list, count );
424 for (i = 0; list && i < count; ++i) TRACE( " %d: %s\n", i, list[i] );
425 if (list) XFreeStringList( list );
427 if ((data->xim = xim_create( data ))) x11drv_client_call( client_ime_update_association, 0 );
428 else XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, xim_open, (XPointer)data );
431 static BOOL xic_destroy( XIC xic, XPointer user, XPointer arg )
433 struct x11drv_win_data *data;
434 HWND hwnd = (HWND)user;
436 TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg );
438 if ((data = get_win_data( hwnd )))
440 if (data->xic == xic) data->xic = NULL;
441 release_win_data( data );
444 return TRUE;
447 static XIC xic_create( XIM xim, HWND hwnd, Window win )
449 XICCallback destroy = {.callback = xic_destroy, .client_data = (XPointer)hwnd};
450 XICCallback preedit_caret = {.callback = xic_preedit_caret, .client_data = (XPointer)hwnd};
451 XICCallback preedit_done = {.callback = xic_preedit_done, .client_data = (XPointer)hwnd};
452 XICCallback preedit_draw = {.callback = xic_preedit_draw, .client_data = (XPointer)hwnd};
453 XICCallback preedit_start = {.callback = xic_preedit_start, .client_data = (XPointer)hwnd};
454 XICCallback preedit_state_notify = {.callback = xic_preedit_state_notify, .client_data = (XPointer)hwnd};
455 XICCallback status_done = {.callback = xic_status_done, .client_data = (XPointer)hwnd};
456 XICCallback status_draw = {.callback = xic_status_draw, .client_data = (XPointer)hwnd};
457 XICCallback status_start = {.callback = xic_status_start, .client_data = (XPointer)hwnd};
458 XPoint spot = {0};
459 XVaNestedList preedit, status;
460 XIC xic;
461 XFontSet fontSet = x11drv_thread_data()->font_set;
463 TRACE( "xim %p, hwnd %p/%lx\n", xim, hwnd, win );
465 preedit = XVaCreateNestedList( 0, XNFontSet, fontSet,
466 XNPreeditCaretCallback, &preedit_caret,
467 XNPreeditDoneCallback, &preedit_done,
468 XNPreeditDrawCallback, &preedit_draw,
469 XNPreeditStartCallback, &preedit_start,
470 XNPreeditStateNotifyCallback, &preedit_state_notify,
471 XNSpotLocation, &spot, NULL );
472 status = XVaCreateNestedList( 0, XNFontSet, fontSet,
473 XNStatusStartCallback, &status_start,
474 XNStatusDoneCallback, &status_done,
475 XNStatusDrawCallback, &status_draw,
476 NULL );
477 xic = XCreateIC( xim, XNInputStyle, input_style, XNPreeditAttributes, preedit, XNStatusAttributes, status,
478 XNClientWindow, win, XNFocusWindow, win, XNDestroyCallback, &destroy, NULL );
479 TRACE( "created XIC %p\n", xic );
481 XFree( preedit );
482 XFree( status );
484 return xic;
487 XIC X11DRV_get_ic( HWND hwnd )
489 struct x11drv_win_data *data;
490 XIM xim;
491 XIC ret;
493 if (!(data = get_win_data( hwnd ))) return 0;
494 x11drv_thread_data()->last_xic_hwnd = hwnd;
495 if (!(ret = data->xic) && (xim = x11drv_thread_data()->xim))
496 ret = data->xic = xic_create( xim, hwnd, data->whole_window );
497 release_win_data( data );
499 return ret;