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