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
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(xim
);
40 #ifndef HAVE_XICCALLBACK_CALLBACK
41 #define XICCallback XIMCallback
42 #define XICProc XIMProc
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
;
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");
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
)
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
) );
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
);
130 case XIMPreeditEnable
:
131 x11drv_client_call( client_ime_set_open_status
, TRUE
);
133 case XIMPreeditDisable
:
134 x11drv_client_call( client_ime_set_open_status
, FALSE
);
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
;
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
);
165 x11drv_client_call( client_ime_set_composition_status
, FALSE
);
169 static int xic_preedit_draw( XIC xic
, XPointer user
, XPointer arg
)
171 XIMPreeditDrawCallbackStruct
*params
= (void *)arg
;
172 HWND hwnd
= (HWND
)user
;
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 );
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
);
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
);
204 if (str
!= text
->string
.multi_byte
) free( str
);
207 x11drv_client_call( client_ime_set_cursor_pos
, params
->caret
);
212 static int xic_preedit_caret( XIC xic
, XPointer user
, XPointer arg
)
214 XIMPreeditCaretCallbackStruct
*params
= (void *)arg
;
215 HWND hwnd
= (HWND
)user
;
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
)
229 case XIMBackwardChar
:
230 case XIMBackwardWord
:
236 case XIMAbsolutePosition
:
237 pos
= params
->position
;
240 params
->position
= pos
;
244 case XIMPreviousLine
:
247 FIXME( "Not implemented\n" );
250 x11drv_client_call( client_ime_set_cursor_pos
, pos
);
251 params
->position
= pos
;
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
);
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
);
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
);
277 NTSTATUS
x11drv_xim_reset( void *hwnd
)
279 XIC ic
= X11DRV_get_ic(hwnd
);
283 TRACE("Forcing Reset %p\n",ic
);
284 leftover
= XmbResetIC(ic
);
290 NTSTATUS
x11drv_xim_preedit_state( void *arg
)
292 struct xim_preedit_state_params
*params
= arg
;
294 XIMPreeditState state
;
297 ic
= X11DRV_get_ic( params
->hwnd
);
302 state
= XIMPreeditEnable
;
304 state
= XIMPreeditDisable
;
306 attr
= XVaCreateNestedList(0, XNPreeditState
, state
, NULL
);
309 XSetICValues(ic
, XNPreeditAttributes
, attr
, NULL
);
315 /***********************************************************************
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");
329 if (XSetLocaleModifiers("") == NULL
)
331 WARN("Could not set locale modifiers.\n");
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
) );
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
;
359 if (!(xim
= XOpenIM( data
->display
, NULL
, NULL
, NULL
)))
361 WARN("Could not open input method.\n");
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
);
374 WARN( "Could not find supported input style.\n" );
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
;
391 if (!input_style
) input_style
= input_style_fallback
;
392 TRACE( "selected style %#lx %s\n", input_style
, debugstr_xim_style( input_style
) );
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;
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
;
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
);
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
};
459 XVaNestedList preedit
, status
;
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
,
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
);
487 XIC
X11DRV_get_ic( HWND hwnd
)
489 struct x11drv_win_data
*data
;
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
);