xref: /aoo41x/main/vcl/unx/generic/app/i18n_cb.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <stdio.h>
32 #include <string.h>
33 
34 #include <sal/alloca.h>
35 #include <osl/thread.h>
36 
37 #include <tools/prex.h>
38 #include <X11/Xlocale.h>
39 #include <X11/Xlib.h>
40 #include <tools/postx.h>
41 
42 #include "unx/salunx.h"
43 #include "unx/XIM.h"
44 #include "unx/i18n_cb.hxx"
45 #include "unx/i18n_status.hxx"
46 #include "unx/i18n_ic.hxx"
47 #include "unx/i18n_im.hxx"
48 #include "salframe.hxx"
49 
50 // -------------------------------------------------------------------------
51 //
52 // i. preedit start callback
53 //
54 // -------------------------------------------------------------------------
55 
56 int
57 PreeditStartCallback ( XIC, XPointer client_data, XPointer )
58 {
59   	preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
60 	if ( pPreeditData->eState == ePreeditStatusActivationRequired )
61 	{
62 		pPreeditData->eState = ePreeditStatusActive;
63 		pPreeditData->aText.nCursorPos = 0;
64 		pPreeditData->aText.nLength    = 0;
65 	}
66 
67 	return -1;
68 }
69 
70 // -------------------------------------------------------------------------
71 //
72 // ii. preedit done callback
73 //
74 // -------------------------------------------------------------------------
75 
76 void
77 PreeditDoneCallback ( XIC, XPointer client_data, XPointer )
78 {
79   	preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
80  	if (pPreeditData->eState == ePreeditStatusActive )
81 	{
82         if( pPreeditData->pFrame )
83             pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
84 	}
85 	pPreeditData->eState = ePreeditStatusStartPending;
86 }
87 
88 // -------------------------------------------------------------------------
89 //
90 // iii. preedit draw callback
91 //
92 // -------------------------------------------------------------------------
93 
94 //
95 // Handle deletion of text in a preedit_draw_callback
96 // from and howmuch are guaranteed to be nonnegative
97 //
98 
99 void
100 Preedit_DeleteText(preedit_text_t *ptext, int from, int howmuch)
101 {
102     // If we've been asked to delete no text then just set
103     // nLength correctly and return
104     if (ptext->nLength == 0)
105     {
106         ptext->nLength = from;
107         return;
108     }
109 
110 	int to = from + howmuch;
111 
112   	if (to == (int)ptext->nLength)
113 	{
114     	// delete from the end of the text
115     	ptext->nLength = from;
116   	}
117 	else
118         if (to < (int)ptext->nLength)
119 	{
120     	// cut out of the middle of the text
121     	memmove( (void*)(ptext->pUnicodeBuffer + from),
122 				(void*)(ptext->pUnicodeBuffer + to),
123 				(ptext->nLength - to) * sizeof(sal_Unicode));
124     	memmove( (void*)(ptext->pCharStyle + from),
125 				(void*)(ptext->pCharStyle + to),
126 				(ptext->nLength - to) * sizeof(XIMFeedback));
127     	ptext->nLength -= howmuch;
128   	}
129 	else
130     // if ( to > pText->nLength )
131     {
132       	// XXX this indicates an error, are we out of sync ?
133       	fprintf(stderr, "Preedit_DeleteText( from=%i to=%i length=%i )\n",
134 				from, to, ptext->nLength );
135       	fprintf (stderr, "\t XXX internal error, out of sync XXX\n");
136 
137       	ptext->nLength = from;
138     }
139 
140   	// NULL-terminate the string
141   	ptext->pUnicodeBuffer[ptext->nLength] = (sal_Unicode)0;
142 }
143 
144 // reallocate the textbuffer with sufficiently large size 2^x
145 // nnewlimit is presupposed to be larger than ptext->size
146 void
147 enlarge_buffer ( preedit_text_t *ptext, int nnewlimit )
148 {
149   	size_t nnewsize = ptext->nSize;
150 
151   	while ( nnewsize <= (size_t)nnewlimit )
152     	nnewsize *= 2;
153 
154   	ptext->nSize = nnewsize;
155   	ptext->pUnicodeBuffer = (sal_Unicode*)realloc((void*)ptext->pUnicodeBuffer,
156 			nnewsize * sizeof(sal_Unicode));
157   	ptext->pCharStyle = (XIMFeedback*)realloc((void*)ptext->pCharStyle,
158 		    nnewsize * sizeof(XIMFeedback));
159 }
160 
161 //
162 // Handle insertion of text in a preedit_draw_callback
163 // string field of XIMText struct is guaranteed to be != NULL
164 //
165 
166 void
167 Preedit_InsertText(preedit_text_t *pText, XIMText *pInsertText, int where,
168 		   Bool isMultilingual)
169 {
170   	sal_Unicode *pInsertTextString;
171   	int nInsertTextLength = 0;
172   	XIMFeedback *pInsertTextCharStyle = pInsertText->feedback;
173 
174   	nInsertTextLength = pInsertText->length;
175 
176   	if (isMultilingual)
177 	{
178     	XIMUnicodeText *pUniText = (XIMUnicodeText*)pInsertText;
179     	pInsertTextString = pUniText->string.utf16_char;
180   	}
181 	else
182 	{
183     	//  can't handle wchar_t strings, so convert to multibyte chars first
184     	char *pMBString;
185     	size_t nMBLength;
186     	if (pInsertText->encoding_is_wchar)
187 		{
188 			wchar_t *pWCString = pInsertText->string.wide_char;
189   			size_t nBytes = wcstombs ( NULL, pWCString, 1024 /* dont care */);
190   			pMBString = (char*)alloca( nBytes + 1 );
191   			nMBLength = wcstombs ( pMBString, pWCString, nBytes + 1);
192     	}
193 		else
194 		{
195       		pMBString = pInsertText->string.multi_byte;
196       		nMBLength = strlen(pMBString); // xxx
197     	}
198 
199 		// convert multibyte chars to unicode
200     	rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
201 
202     	if (nEncoding != RTL_TEXTENCODING_UNICODE)
203 		{
204       		rtl_TextToUnicodeConverter aConverter =
205 					rtl_createTextToUnicodeConverter( nEncoding );
206       		rtl_TextToUnicodeContext aContext =
207 					rtl_createTextToUnicodeContext(aConverter);
208 
209       		sal_Size nBufferSize = nInsertTextLength * 2;
210 
211       		pInsertTextString = (sal_Unicode*)alloca(nBufferSize);
212 
213       		sal_uInt32  nConversionInfo;
214       		sal_Size    nConvertedChars;
215 
216 			rtl_convertTextToUnicode( aConverter, aContext,
217 					pMBString, nMBLength,
218 	 				pInsertTextString, nBufferSize,
219 					  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE
220 					| RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
221 					&nConversionInfo, &nConvertedChars );
222 
223       		rtl_destroyTextToUnicodeContext(aConverter, aContext);
224       		rtl_destroyTextToUnicodeConverter(aConverter);
225 
226     	}
227 		else
228 		{
229       		pInsertTextString = (sal_Unicode*)pMBString;
230     	}
231   	}
232 
233   	// enlarge target text-buffer if necessary
234   	if (pText->nSize <= (pText->nLength + nInsertTextLength))
235     	enlarge_buffer(pText, pText->nLength + nInsertTextLength);
236 
237   	// insert text: displace old mem and put new bytes in
238   	int from    = where;
239   	int to      = where + nInsertTextLength;
240   	int howmany = pText->nLength - where;
241 
242   	memmove((void*)(pText->pUnicodeBuffer + to),
243 			(void*)(pText->pUnicodeBuffer + from),
244 	  		howmany * sizeof(sal_Unicode));
245   	memmove((void*)(pText->pCharStyle + to),
246 	  		(void*)(pText->pCharStyle + from),
247 	  		howmany * sizeof(XIMFeedback));
248 
249   	to = from;
250   	howmany = nInsertTextLength;
251 
252   	memcpy((void*)(pText->pUnicodeBuffer + to), (void*)pInsertTextString,
253 	 		howmany * sizeof(sal_Unicode));
254   	memcpy((void*)(pText->pCharStyle + to), (void*)pInsertTextCharStyle,
255 	  		howmany * sizeof(XIMFeedback));
256 
257   	pText->nLength += howmany;
258 
259   	// NULL-terminate the string
260   	pText->pUnicodeBuffer[pText->nLength] = (sal_Unicode)0;
261 }
262 
263 //
264 // Handle the change of attributes in a preedit_draw_callback
265 //
266 void
267 Preedit_UpdateAttributes ( preedit_text_t* ptext, XIMFeedback* feedback,
268 		int from, int amount )
269 {
270 	if ( (from + amount) > (int)ptext->nLength )
271 	{
272 		// XXX this indicates an error, are we out of sync ?
273 		fprintf (stderr, "Preedit_UpdateAttributes( %i + %i > %i )\n",
274 			from, amount, ptext->nLength );
275 		fprintf (stderr, "\t XXX internal error, out of sync XXX\n");
276 
277 		return;
278 	}
279 
280 	memcpy ( ptext->pCharStyle + from,
281 		feedback, amount * sizeof(XIMFeedback) );
282 }
283 
284 // Convert the XIM feedback values into appropriate VCL
285 // SAL_EXTTEXTINPUT_ATTR values
286 // returns an allocate list of attributes, which must be freed by caller
287 sal_uInt16*
288 Preedit_FeedbackToSAL ( XIMFeedback* pfeedback, int nlength, std::vector<sal_uInt16>& rSalAttr )
289 {
290   	sal_uInt16 *psalattr;
291   	sal_uInt16  nval;
292   	sal_uInt16  noldval = 0;
293   	XIMFeedback nfeedback;
294 
295   	// only work with reasonable length
296   	if (nlength > 0 && nlength > sal::static_int_cast<int>(rSalAttr.size()) )
297     {
298         rSalAttr.reserve( nlength );
299     	psalattr = &rSalAttr[0];
300     }
301   	else
302     	return (sal_uInt16*)NULL;
303 
304   	for (int npos = 0; npos < nlength; npos++)
305 	{
306     	nval = 0;
307     	nfeedback = pfeedback[npos];
308 
309     	// means to use the feedback of the previous char
310     	if (nfeedback == 0)
311 		{
312       		nval = noldval;
313    		}
314     	// convert feedback to attributes
315     	else
316 		{
317       		if (nfeedback & XIMReverse)
318 			    nval |= SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
319       		if (nfeedback & XIMUnderline)
320 				nval |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
321       		if (nfeedback & XIMHighlight)
322 				nval |= SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
323       		if (nfeedback & XIMPrimary)
324 				nval |= SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
325       		if (nfeedback & XIMSecondary)
326 				nval |= SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
327       		if (nfeedback & XIMTertiary) // same as 2ery
328 				nval |= SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
329 
330 			/*
331 			// visibility feedback not supported now
332       		if (   (nfeedback & XIMVisibleToForward)
333 	  			|| (nfeedback & XIMVisibleToBackward)
334 	  			|| (nfeedback & XIMVisibleCenter) )
335 			{ }
336 			*/
337     	}
338     	// copy in list
339     	psalattr[npos] = nval;
340     	noldval = nval;
341   	}
342   	// return list of sal attributes
343  	return psalattr;
344 }
345 
346 void
347 PreeditDrawCallback(XIC ic, XPointer client_data,
348 		    XIMPreeditDrawCallbackStruct *call_data)
349 {
350   	preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
351 
352 	// if there's nothing to change then change nothing
353 	if ( ( (call_data->text == NULL) && (call_data->chg_length == 0) )
354          || pPreeditData->pFrame == NULL )
355 		return;
356 
357     // #88564# Solaris 7 deletes the preedit buffer after commit
358     // since the next call to preeditstart will have the same effect just skip this.
359     // if (pPreeditData->eState == ePreeditStatusStartPending && call_data->text == NULL)
360     //    return;
361 
362 	if ( pPreeditData->eState == ePreeditStatusStartPending )
363 		pPreeditData->eState = ePreeditStatusActivationRequired;
364 	PreeditStartCallback( ic, client_data, NULL );
365 
366   	// Edit the internal textbuffer as indicated by the call_data,
367   	// chg_first and chg_length are guaranteed to be nonnegative
368 
369   	// handle text deletion
370   	if (call_data->text == NULL)
371 	{
372     	Preedit_DeleteText(&(pPreeditData->aText),
373 		       call_data->chg_first, call_data->chg_length );
374   	}
375 	else
376 	{
377     	// handle text insertion
378     	if (   (call_data->chg_length == 0)
379 			&& (call_data->text->string.wide_char != NULL))
380 		{
381       		Preedit_InsertText(&(pPreeditData->aText), call_data->text,
382 			 		call_data->chg_first, pPreeditData->bIsMultilingual);
383     	}
384 		else
385       	// handle text replacement by deletion and insertion of text,
386       	// not smart, just good enough
387       	if (   (call_data->chg_length != 0)
388 	  		&& (call_data->text->string.wide_char != NULL))
389 		{
390 			Preedit_DeleteText(&(pPreeditData->aText),
391 			   		call_data->chg_first, call_data->chg_length);
392 			Preedit_InsertText(&(pPreeditData->aText), call_data->text,
393 			   		call_data->chg_first, pPreeditData->bIsMultilingual);
394       	}
395 		else
396 		// not really a text update, only attributes are concerned
397 		if (   (call_data->chg_length != 0)
398 	    	&& (call_data->text->string.wide_char == NULL))
399 		{
400 	  		Preedit_UpdateAttributes(&(pPreeditData->aText),
401 				   call_data->text->feedback,
402 				   call_data->chg_first, call_data->chg_length);
403 		}
404   	}
405 
406   	//
407   	// build the SalExtTextInputEvent and send it up
408   	//
409   	pPreeditData->aInputEv.mnTime = 0;
410   	pPreeditData->aInputEv.mpTextAttr = Preedit_FeedbackToSAL(
411 			pPreeditData->aText.pCharStyle, pPreeditData->aText.nLength, pPreeditData->aInputFlags);
412   	pPreeditData->aInputEv.mnCursorPos = call_data->caret;
413   	pPreeditData->aInputEv.maText = String (pPreeditData->aText.pUnicodeBuffer,
414                                 pPreeditData->aText.nLength);
415 	pPreeditData->aInputEv.mnCursorFlags 	= 0; // default: make cursor visible
416   	pPreeditData->aInputEv.mnDeltaStart = 0; // call_data->chg_first;
417   	pPreeditData->aInputEv.mbOnlyCursor = False;
418 
419   	if ( pPreeditData->eState == ePreeditStatusActive && pPreeditData->pFrame )
420     	pPreeditData->pFrame->CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&pPreeditData->aInputEv);
421     if (pPreeditData->aText.nLength == 0 && pPreeditData->pFrame )
422 	    pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
423 
424     if (pPreeditData->aText.nLength == 0)
425         pPreeditData->eState = ePreeditStatusStartPending;
426 
427 	GetPreeditSpotLocation(ic, (XPointer)pPreeditData);
428 }
429 
430 void
431 GetPreeditSpotLocation(XIC ic, XPointer client_data)
432 {
433   	//
434   	// Send SalEventExtTextInputPos event to get spotlocation
435   	//
436   	SalExtTextInputPosEvent mPosEvent;
437   	preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
438 
439     if( pPreeditData->pFrame )
440         pPreeditData->pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&mPosEvent);
441 
442   	XPoint point;
443   	point.x = mPosEvent.mnX + mPosEvent.mnWidth;
444   	point.y = mPosEvent.mnY + mPosEvent.mnHeight;
445 
446   	XVaNestedList preedit_attr;
447   	preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &point, NULL);
448   	XSetICValues(ic, XNPreeditAttributes, preedit_attr, NULL);
449   	XFree(preedit_attr);
450 
451 	return;
452 }
453 
454 // -------------------------------------------------------------------------
455 //
456 // iv. preedit caret callback
457 //
458 // -------------------------------------------------------------------------
459 
460 #if OSL_DEBUG_LEVEL > 1
461 void
462 PreeditCaretCallback ( XIC ic, XPointer client_data,
463 	XIMPreeditCaretCallbackStruct *call_data )
464 #else
465 void
466 PreeditCaretCallback ( XIC, XPointer,XIMPreeditCaretCallbackStruct* )
467 #endif
468 {
469     #if OSL_DEBUG_LEVEL > 1
470 	// XXX PreeditCaretCallback is pure debug code for now
471 	const char *direction = "?";
472 	const char *style = "?";
473 
474 	switch ( call_data->style )
475 	{
476 		case XIMIsInvisible: style = "Invisible"; break;
477 		case XIMIsPrimary:   style = "Primary";   break;
478 		case XIMIsSecondary: style = "Secondary"; break;
479 	}
480 	switch ( call_data->direction )
481 	{
482 		case XIMForwardChar:  direction = "Forward char";  break;
483 		case XIMBackwardChar: direction = "Backward char"; break;
484 		case XIMForwardWord:  direction = "Forward word";  break;
485 		case XIMBackwardWord: direction = "Backward word"; break;
486 		case XIMCaretUp:      direction = "Caret up";      break;
487 		case XIMCaretDown:    direction = "Caret down";    break;
488 		case XIMNextLine:     direction = "Next line";     break;
489 		case XIMPreviousLine: direction = "Previous line"; break;
490 		case XIMLineStart:    direction = "Line start";    break;
491 		case XIMLineEnd:      direction = "Line end";      break;
492 		case XIMAbsolutePosition: direction = "Absolute";  break;
493 		case XIMDontChange:   direction = "Dont change";   break;
494 	}
495 
496 	fprintf (stderr, "PreeditCaretCallback( ic=%p, client=%p,\n",
497 		ic, client_data );
498 	fprintf (stderr, "\t position=%i, direction=\"%s\", style=\"%s\" )\n",
499 		call_data->position, direction, style );
500     #endif
501 }
502 
503 // -----------------------------------------------------------------------
504 //
505 // v. commit string callback: convert an extended text input (iiimp ... )
506 //     into an ordinary key-event
507 //
508 // -----------------------------------------------------------------------
509 
510 Bool
511 IsControlCode(sal_Unicode nChar)
512 {
513     if ( nChar <= 0x1F // C0 controls
514      /* || (0x80 <= nChar && nChar <= 0x9F) C1 controls */ )
515         return True;
516     else
517         return False;
518 }
519 
520 int
521 CommitStringCallback( XIC ic, XPointer client_data, XPointer call_data )
522 {
523 	preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
524 
525   	XIMUnicodeText *cbtext = (XIMUnicodeText *)call_data;
526   	sal_Unicode *p_unicode_data = (sal_Unicode*)cbtext->string.utf16_char;
527 
528     // #86964# filter unexpected pure control events
529     if (cbtext->length == 1 && IsControlCode(p_unicode_data[0]) )
530     {
531         if( pPreeditData->pFrame )
532         {
533             pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
534         }
535     }
536     else
537     {
538         if( pPreeditData->pFrame )
539         {
540             pPreeditData->aInputEv.mnTime 			= 0;
541             pPreeditData->aInputEv.mpTextAttr 		= 0;
542             pPreeditData->aInputEv.mnCursorPos 		= cbtext->length;
543             pPreeditData->aInputEv.maText 			= UniString(p_unicode_data, cbtext->length);
544             pPreeditData->aInputEv.mnCursorFlags 	= 0; // default: make cursor visible
545             pPreeditData->aInputEv.mnDeltaStart 	= 0;
546             pPreeditData->aInputEv.mbOnlyCursor 	= False;
547 
548             pPreeditData->pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pPreeditData->aInputEv);
549             pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
550         }
551     }
552 	pPreeditData->eState = ePreeditStatusStartPending;
553 
554 	GetPreeditSpotLocation(ic, (XPointer)pPreeditData);
555 
556 	return 0;
557 }
558 
559 // ----------------------------------------------------------------------------------
560 //
561 // vi. status callbacks: for now these are empty, they are just needed for turbo linux
562 //
563 // ----------------------------------------------------------------------------------
564 
565 void
566 StatusStartCallback (XIC, XPointer, XPointer)
567 {
568 	return;
569 }
570 
571 void
572 StatusDoneCallback (XIC, XPointer, XPointer)
573 {
574 	return;
575 }
576 
577 void
578 StatusDrawCallback (XIC ic, XPointer client_data, XIMStatusDrawCallbackStruct *call_data)
579 {
580   	preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
581     if( pPreeditData->bIsMultilingual )
582     {
583         // IIIMP
584         XIMUnicodeText *cbtext = (XIMUnicodeText *)call_data->data.text;
585         ::vcl::I18NStatus::get().setStatusText( String( cbtext->string.utf16_char, call_data->data.text->length ) );
586         XIMUnicodeCharacterSubset* pSubset = NULL;
587         if( ! XGetICValues( ic,
588                             XNUnicodeCharacterSubset, & pSubset,
589                             NULL )
590             && pSubset )
591         {
592             ::vcl::I18NStatus::get().changeIM( String( ByteString( pSubset->name ), RTL_TEXTENCODING_UTF8 ) );
593 #if OSL_DEBUG_LEVEL > 1
594             fprintf( stderr, "got XNUnicodeCharacterSubset\n   %d\n   %d\n   %s\n   %d\n", pSubset->index, pSubset->subset_id, pSubset->name, pSubset->is_active );
595 #endif
596         }
597     }
598     else if( call_data->type == XIMTextType )
599     {
600 		String aText;
601 		if( call_data->data.text )
602 		{
603 			// XIM with text
604 			sal_Char* pMBString = NULL;
605 			size_t nLength = 0;
606 			if( call_data->data.text->encoding_is_wchar )
607 			{
608 				if( call_data->data.text->string.wide_char )
609 				{
610 					wchar_t* pWString = call_data->data.text->string.wide_char;
611 					size_t nBytes = wcstombs( NULL, pWString, 1024 );
612 					pMBString = (sal_Char*)alloca( nBytes+1 );
613 					nLength = wcstombs( pMBString, pWString, nBytes+1 );
614 				}
615 			}
616 			else
617 			{
618 				if( call_data->data.text->string.multi_byte )
619 				{
620 					pMBString = call_data->data.text->string.multi_byte;
621 					nLength = strlen( pMBString );
622 				}
623 			}
624 			if( nLength )
625 	        	aText = String( pMBString, nLength, gsl_getSystemTextEncoding() );
626 		}
627         ::vcl::I18NStatus::get().setStatusText( aText );
628     }
629 #if OSL_DEBUG_LEVEL > 1
630     else
631         fprintf( stderr, "XIMStatusDataType %s not supported\n",
632                  call_data->type == XIMBitmapType ? "XIMBitmapType" : ByteString::CreateFromInt32( call_data->type ).GetBuffer() );
633 #endif
634 	return;
635 }
636 
637 void
638 SwitchIMCallback (XIC, XPointer, XPointer call_data)
639 {
640     XIMSwitchIMNotifyCallbackStruct* pCallData = (XIMSwitchIMNotifyCallbackStruct*)call_data;
641     ::vcl::I18NStatus::get().changeIM( String( ByteString( pCallData->to->name ), RTL_TEXTENCODING_UTF8 ) );
642 }
643 
644 // ----------------------------------------------------------------------------------
645 //
646 // vii. destroy callbacks: internally disable all IC/IM calls
647 //
648 // ----------------------------------------------------------------------------------
649 
650 void
651 IC_IMDestroyCallback (XIM, XPointer client_data, XPointer)
652 {
653     SalI18N_InputContext *pContext = (SalI18N_InputContext*)client_data;
654     if (pContext != NULL)
655         pContext->HandleDestroyIM();
656 }
657 
658 void
659 IM_IMDestroyCallback (XIM, XPointer client_data, XPointer)
660 {
661     SalI18N_InputMethod *pMethod = (SalI18N_InputMethod*)client_data;
662     if (pMethod != NULL)
663         pMethod->HandleDestroyIM();
664 }
665