1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include <stdio.h> 28 29 #include <sal/alloca.h> 30 #include <osl/thread.h> 31 32 #include <tools/prex.h> 33 #include <X11/Xlocale.h> 34 #include <X11/Xlib.h> 35 #include <tools/postx.h> 36 37 #include <unx/salunx.h> 38 #include <unx/XIM.h> 39 #include <unx/i18n_ic.hxx> 40 #include <unx/i18n_im.hxx> 41 #include <unx/i18n_status.hxx> 42 43 #include <unx/salframe.h> 44 #include <unx/saldata.hxx> 45 #include <unx/saldisp.hxx> 46 47 using namespace vcl; 48 49 static void sendEmptyCommit( SalFrame* pFrame ) 50 { 51 vcl::DeletionListener aDel( pFrame ); 52 53 SalExtTextInputEvent aEmptyEv; 54 aEmptyEv.mnTime = 0; 55 aEmptyEv.mpTextAttr = 0; 56 aEmptyEv.maText = String(); 57 aEmptyEv.mnCursorPos = 0; 58 aEmptyEv.mnCursorFlags = 0; 59 aEmptyEv.mnDeltaStart = 0; 60 aEmptyEv.mbOnlyCursor = False; 61 pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv ); 62 if( ! aDel.isDeleted() ) 63 pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL ); 64 } 65 66 // --------------------------------------------------------------------------- 67 // 68 // Constructor / Destructor, the InputContext is bound to the SalFrame, as it 69 // needs the shell window as a focus window 70 // 71 // ---------------------------------------------------------------------------- 72 73 SalI18N_InputContext::~SalI18N_InputContext() 74 { 75 if ( maContext != NULL ) 76 XDestroyIC( maContext ); 77 if ( mpAttributes != NULL ) 78 XFree( mpAttributes ); 79 if ( mpStatusAttributes != NULL ) 80 XFree( mpStatusAttributes ); 81 if ( mpPreeditAttributes != NULL ) 82 XFree( mpPreeditAttributes ); 83 84 if (maClientData.aText.pUnicodeBuffer != NULL) 85 free(maClientData.aText.pUnicodeBuffer); 86 if (maClientData.aText.pCharStyle != NULL) 87 free(maClientData.aText.pCharStyle); 88 } 89 90 // ---------------------------------------------------------------------------- 91 // convenience routine to add items to a XVaNestedList 92 // ---------------------------------------------------------------------------- 93 94 static XVaNestedList 95 XVaAddToNestedList( XVaNestedList a_srclist, char* name, XPointer value ) 96 { 97 XVaNestedList a_dstlist; 98 99 // if ( value == NULL ) 100 // return a_srclist; 101 102 if ( a_srclist == NULL ) 103 { 104 a_dstlist = XVaCreateNestedList( 105 0, 106 name, value, 107 NULL ); 108 } 109 else 110 { 111 a_dstlist = XVaCreateNestedList( 112 0, 113 XNVaNestedList, a_srclist, 114 name, value, 115 NULL ); 116 } 117 118 return a_dstlist != NULL ? a_dstlist : a_srclist ; 119 } 120 121 // ---------------------------------------------------------------------------- 122 // convenience routine to create a fontset 123 // ---------------------------------------------------------------------------- 124 125 static XFontSet 126 get_font_set( Display *p_display ) 127 { 128 static XFontSet p_font_set = NULL; 129 130 if (p_font_set == NULL) 131 { 132 char **pp_missing_list; 133 int n_missing_count; 134 char *p_default_string; 135 136 p_font_set = XCreateFontSet(p_display, "-*", 137 &pp_missing_list, &n_missing_count, &p_default_string); 138 } 139 140 return p_font_set; 141 } 142 143 // --------------------------------------------------------------------------- 144 // 145 // Constructor for a InputContext (IC) 146 // 147 // ---------------------------------------------------------------------------- 148 149 SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) : 150 mbUseable( True ), 151 maContext( (XIC)NULL ), 152 mnSupportedStatusStyle( 153 XIMStatusCallbacks | 154 XIMStatusNothing | 155 XIMStatusNone 156 ), 157 mnSupportedPreeditStyle( 158 XIMPreeditCallbacks | 159 XIMPreeditNothing | 160 XIMPreeditNone 161 ), 162 mnStatusStyle( 0 ), 163 mnPreeditStyle( 0 ), 164 mpAttributes( NULL ), 165 mpStatusAttributes( NULL ), 166 mpPreeditAttributes( NULL ) 167 { 168 #ifdef SOLARIS 169 static const char* pIIIMPEnable = getenv( "SAL_DISABLE_OWN_IM_STATUS" ); 170 if( pIIIMPEnable && *pIIIMPEnable ) 171 mnSupportedStatusStyle &= ~XIMStatusCallbacks; 172 #endif 173 174 maClientData.aText.pUnicodeBuffer = NULL; 175 maClientData.aText.pCharStyle = NULL; 176 maClientData.aInputEv.mnTime = 0; 177 maClientData.aInputEv.mpTextAttr = NULL; 178 maClientData.aInputEv.mnCursorPos = 0; 179 maClientData.aInputEv.mnDeltaStart = 0; 180 maClientData.aInputEv.mnCursorFlags = 0; 181 maClientData.aInputEv.mbOnlyCursor = sal_False; 182 183 SalI18N_InputMethod *pInputMethod; 184 pInputMethod = GetX11SalData()->GetDisplay()->GetInputMethod(); 185 mbMultiLingual = pInputMethod->IsMultiLingual(); 186 187 mnSupportedPreeditStyle = XIMPreeditCallbacks | XIMPreeditPosition 188 | XIMPreeditNothing | XIMPreeditNone; 189 if (pInputMethod->UseMethod() 190 && SupportInputMethodStyle( pInputMethod->GetSupportedStyles() ) ) 191 { 192 const SystemEnvData* pEnv = pFrame->GetSystemData(); 193 XLIB_Window aClientWindow = pEnv->aShellWindow; 194 XLIB_Window aFocusWindow = pEnv->aWindow; 195 196 // for status callbacks and commit string callbacks 197 #define PREEDIT_BUFSZ 16 198 maClientData.bIsMultilingual = mbMultiLingual; 199 maClientData.eState = ePreeditStatusStartPending; 200 maClientData.pFrame = pFrame; 201 maClientData.aText.pUnicodeBuffer = 202 (sal_Unicode*)malloc(PREEDIT_BUFSZ * sizeof(sal_Unicode)); 203 maClientData.aText.pCharStyle = 204 (XIMFeedback*)malloc(PREEDIT_BUFSZ * sizeof(XIMFeedback));; 205 maClientData.aText.nSize = PREEDIT_BUFSZ; 206 maClientData.aText.nCursorPos = 0; 207 maClientData.aText.nLength = 0; 208 209 // 210 // Status attributes 211 // 212 213 switch ( mnStatusStyle ) 214 { 215 case XIMStatusCallbacks: 216 { 217 static XIMCallback aStatusStartCallback; 218 static XIMCallback aStatusDoneCallback; 219 static XIMCallback aStatusDrawCallback; 220 221 aStatusStartCallback.callback = (XIMProc)StatusStartCallback; 222 aStatusStartCallback.client_data = (XPointer)&maClientData; 223 aStatusDoneCallback.callback = (XIMProc)StatusDoneCallback; 224 aStatusDoneCallback.client_data = (XPointer)&maClientData; 225 aStatusDrawCallback.callback = (XIMProc)StatusDrawCallback; 226 aStatusDrawCallback.client_data = (XPointer)&maClientData; 227 228 mpStatusAttributes = XVaCreateNestedList ( 229 0, 230 XNStatusStartCallback, &aStatusStartCallback, 231 XNStatusDoneCallback, &aStatusDoneCallback, 232 XNStatusDrawCallback, &aStatusDrawCallback, 233 NULL ); 234 235 break; 236 } 237 238 case XIMStatusArea: 239 /* not supported */ 240 break; 241 242 case XIMStatusNone: 243 case XIMStatusNothing: 244 default: 245 /* no arguments needed */ 246 break; 247 } 248 249 // 250 // set preedit attributes 251 // 252 253 switch ( mnPreeditStyle ) 254 { 255 case XIMPreeditCallbacks: 256 257 maPreeditCaretCallback.callback = (XIMProc)PreeditCaretCallback; 258 maPreeditStartCallback.callback = (XIMProc)PreeditStartCallback; 259 maPreeditDoneCallback.callback = (XIMProc)PreeditDoneCallback; 260 maPreeditDrawCallback.callback = (XIMProc)PreeditDrawCallback; 261 maPreeditCaretCallback.client_data = (XPointer)&maClientData; 262 maPreeditStartCallback.client_data = (XPointer)&maClientData; 263 maPreeditDoneCallback.client_data = (XPointer)&maClientData; 264 maPreeditDrawCallback.client_data = (XPointer)&maClientData; 265 266 mpPreeditAttributes = XVaCreateNestedList ( 267 0, 268 XNPreeditStartCallback, &maPreeditStartCallback, 269 XNPreeditDoneCallback, &maPreeditDoneCallback, 270 XNPreeditDrawCallback, &maPreeditDrawCallback, 271 XNPreeditCaretCallback, &maPreeditCaretCallback, 272 NULL ); 273 274 break; 275 276 case XIMPreeditArea: 277 /* not supported */ 278 break; 279 280 case XIMPreeditPosition: 281 { 282 // spot location 283 SalExtTextInputPosEvent aPosEvent; 284 pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent); 285 286 static XPoint aSpot; 287 aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth; 288 aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight; 289 290 // create attributes for preedit position style 291 mpPreeditAttributes = XVaCreateNestedList ( 292 0, 293 XNSpotLocation, &aSpot, 294 NULL ); 295 296 // XCreateIC() fails on Redflag Linux 2.0 if there is no 297 // fontset though the data itself is not evaluated nor is 298 // it required according to the X specs. 299 Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay(); 300 XFontSet pFontSet = get_font_set(pDisplay); 301 302 if (pFontSet != NULL) 303 { 304 mpPreeditAttributes = XVaAddToNestedList( mpPreeditAttributes, 305 const_cast<char*>(XNFontSet), (XPointer)pFontSet); 306 } 307 308 break; 309 } 310 311 case XIMPreeditNone: 312 case XIMPreeditNothing: 313 default: 314 /* no arguments needed */ 315 break; 316 } 317 318 // Create the InputContext by giving it exactly the information it 319 // deserves, because inappropriate attributes 320 // let XCreateIC fail on Solaris (eg. for C locale) 321 322 mpAttributes = XVaCreateNestedList( 323 0, 324 XNFocusWindow, aFocusWindow, 325 XNClientWindow, aClientWindow, 326 XNInputStyle, mnPreeditStyle | mnStatusStyle, 327 NULL ); 328 329 if ( mnPreeditStyle != XIMPreeditNone ) 330 { 331 #if defined LINUX || defined FREEBSD || defined NETBSD 332 if ( mpPreeditAttributes != NULL ) 333 #endif 334 mpAttributes = XVaAddToNestedList( mpAttributes, 335 const_cast<char*>(XNPreeditAttributes), (XPointer)mpPreeditAttributes ); 336 } 337 if ( mnStatusStyle != XIMStatusNone ) 338 { 339 #if defined LINUX || defined FREEBSD || defined NETBSD 340 if ( mpStatusAttributes != NULL ) 341 #endif 342 mpAttributes = XVaAddToNestedList( mpAttributes, 343 const_cast<char*>(XNStatusAttributes), (XPointer)mpStatusAttributes ); 344 } 345 maContext = XCreateIC( pInputMethod->GetMethod(), 346 XNVaNestedList, mpAttributes, 347 NULL ); 348 } 349 350 if ( maContext == NULL ) 351 { 352 #if OSL_DEBUG_LEVEL > 1 353 fprintf(stderr, "input context creation failed\n"); 354 #endif 355 356 mbUseable = False; 357 mbMultiLingual = False; 358 359 if ( mpAttributes != NULL ) 360 XFree( mpAttributes ); 361 if ( mpStatusAttributes != NULL ) 362 XFree( mpStatusAttributes ); 363 if ( mpPreeditAttributes != NULL ) 364 XFree( mpPreeditAttributes ); 365 if ( maClientData.aText.pUnicodeBuffer != NULL ) 366 free ( maClientData.aText.pUnicodeBuffer ); 367 if ( maClientData.aText.pCharStyle != NULL ) 368 free ( maClientData.aText.pCharStyle ); 369 370 mpAttributes = NULL; 371 mpStatusAttributes = NULL; 372 mpPreeditAttributes = NULL; 373 maClientData.aText.pUnicodeBuffer = NULL; 374 maClientData.aText.pCharStyle = NULL; 375 } 376 377 if ( maContext != NULL && mbMultiLingual ) 378 { 379 maCommitStringCallback.callback = (XIMProc)::CommitStringCallback; 380 maCommitStringCallback.client_data = (XPointer)&maClientData; 381 maSwitchIMCallback.callback = (XIMProc)::SwitchIMCallback; 382 maSwitchIMCallback.client_data = (XPointer)&maClientData; 383 XSetICValues( maContext, 384 XNCommitStringCallback, &maCommitStringCallback, 385 XNSwitchIMNotifyCallback, &maSwitchIMCallback, 386 NULL ); 387 } 388 if ( maContext != NULL) 389 { 390 maDestroyCallback.callback = (XIMProc)IC_IMDestroyCallback; 391 maDestroyCallback.client_data = (XPointer)this; 392 XSetICValues( maContext, 393 XNDestroyCallback, &maDestroyCallback, 394 NULL ); 395 } 396 397 if( mbMultiLingual ) 398 { 399 // set initial IM status 400 XIMUnicodeCharacterSubset* pSubset = NULL; 401 if( ! XGetICValues( maContext, 402 XNUnicodeCharacterSubset, & pSubset, 403 NULL ) 404 && pSubset ) 405 { 406 String aCurrent( ByteString( pSubset->name ), RTL_TEXTENCODING_UTF8 ); 407 ::vcl::I18NStatus::get().changeIM( aCurrent ); 408 ::vcl::I18NStatus::get().setStatusText( aCurrent ); 409 } 410 } 411 } 412 413 // --------------------------------------------------------------------------- 414 // 415 // In Solaris 8 the status window does not unmap if the frame unmapps, so 416 // unmap it the hard way 417 // 418 // --------------------------------------------------------------------------- 419 420 void 421 SalI18N_InputContext::Unmap( SalFrame* pFrame ) 422 { 423 if ( maContext != NULL ) 424 { 425 I18NStatus& rStatus( I18NStatus::get() ); 426 if( rStatus.getParent() == pFrame ) 427 rStatus.show( false, I18NStatus::contextmap ); 428 429 } 430 UnsetICFocus( pFrame ); 431 maClientData.pFrame = NULL; 432 } 433 434 void 435 SalI18N_InputContext::Map( SalFrame *pFrame ) 436 { 437 if( mbUseable ) 438 { 439 I18NStatus& rStatus(I18NStatus::get() ); 440 rStatus.setParent( pFrame ); 441 if( pFrame ) 442 { 443 rStatus.show( true, I18NStatus::contextmap ); 444 if ( maContext == NULL ) 445 { 446 SalI18N_InputMethod *pInputMethod; 447 pInputMethod = GetX11SalData()->GetDisplay()->GetInputMethod(); 448 449 maContext = XCreateIC( pInputMethod->GetMethod(), 450 XNVaNestedList, mpAttributes, 451 NULL ); 452 if ( maContext != NULL && mbMultiLingual ) 453 XSetICValues( maContext, 454 XNCommitStringCallback, &maCommitStringCallback, 455 XNSwitchIMNotifyCallback, &maSwitchIMCallback, 456 NULL ); 457 } 458 if( maClientData.pFrame != pFrame ) 459 SetICFocus( pFrame ); 460 } 461 } 462 } 463 464 // -------------------------------------------------------------------------- 465 // 466 // Handle DestroyCallbacks 467 // in fact this is a callback called from the XNDestroyCallback 468 // 469 // -------------------------------------------------------------------------- 470 471 void 472 SalI18N_InputContext::HandleDestroyIM() 473 { 474 maContext = 0; // noli me tangere 475 mbUseable = False; 476 } 477 478 // --------------------------------------------------------------------------- 479 // 480 // make sure, the input method gets all the X-Events it needs, this is only 481 // called once on each frame, it relys on a valid maContext 482 // 483 // --------------------------------------------------------------------------- 484 485 void 486 SalI18N_InputContext::ExtendEventMask( XLIB_Window aFocusWindow ) 487 { 488 unsigned long nIMEventMask; 489 XWindowAttributes aWindowAttributes; 490 491 if ( mbUseable ) 492 { 493 Display *pDisplay = XDisplayOfIM( XIMOfIC(maContext) ); 494 495 XGetWindowAttributes( pDisplay, aFocusWindow, 496 &aWindowAttributes ); 497 XGetICValues ( maContext, 498 XNFilterEvents, &nIMEventMask, 499 NULL); 500 nIMEventMask |= aWindowAttributes.your_event_mask; 501 XSelectInput ( pDisplay, aFocusWindow, nIMEventMask ); 502 } 503 } 504 505 // --------------------------------------------------------------------------- 506 // 507 // tune the styles provided by the input method with the supported one 508 // 509 // --------------------------------------------------------------------------- 510 511 unsigned int 512 SalI18N_InputContext::GetWeightingOfIMStyle( XIMStyle nStyle ) const 513 { 514 struct StyleWeightingT { 515 const XIMStyle nStyle; 516 const unsigned int nWeight; 517 }; 518 519 StyleWeightingT const *pWeightPtr; 520 const StyleWeightingT pWeight[] = { 521 { XIMPreeditCallbacks, 0x10000000 }, 522 { XIMPreeditPosition, 0x02000000 }, 523 { XIMPreeditArea, 0x01000000 }, 524 { XIMPreeditNothing, 0x00100000 }, 525 { XIMPreeditNone, 0x00010000 }, 526 { XIMStatusCallbacks, 0x1000 }, 527 { XIMStatusArea, 0x0100 }, 528 { XIMStatusNothing, 0x0010 }, 529 { XIMStatusNone, 0x0001 }, 530 { 0, 0x0 } 531 }; 532 533 int nWeight = 0; 534 for ( pWeightPtr = pWeight; pWeightPtr->nStyle != 0; pWeightPtr++ ) 535 { 536 if ( (pWeightPtr->nStyle & nStyle) != 0 ) 537 nWeight += pWeightPtr->nWeight; 538 } 539 return nWeight; 540 } 541 542 Bool 543 SalI18N_InputContext::IsSupportedIMStyle( XIMStyle nStyle ) const 544 { 545 if ( (nStyle & mnSupportedPreeditStyle) 546 && (nStyle & mnSupportedStatusStyle) ) 547 { 548 return True; 549 } 550 return False; 551 } 552 553 Bool 554 SalI18N_InputContext::SupportInputMethodStyle( XIMStyles *pIMStyles ) 555 { 556 int nBestScore = 0; 557 int nActualScore = 0; 558 559 mnPreeditStyle = 0; 560 mnStatusStyle = 0; 561 562 if ( pIMStyles != NULL ) 563 { 564 // check whether the XIM supports one of the desired styles 565 // only a single preedit and a single status style must occure 566 // in a inpuut method style. Hideki said so, so i trust him 567 for ( int nStyle = 0; nStyle < pIMStyles->count_styles; nStyle++ ) 568 { 569 XIMStyle nProvidedStyle = pIMStyles->supported_styles[ nStyle ]; 570 if ( IsSupportedIMStyle(nProvidedStyle) ) 571 { 572 nActualScore = GetWeightingOfIMStyle( nProvidedStyle ); 573 if ( nActualScore >= nBestScore ) 574 { 575 nBestScore = nActualScore; 576 mnPreeditStyle = nProvidedStyle & mnSupportedPreeditStyle; 577 mnStatusStyle = nProvidedStyle & mnSupportedStatusStyle; 578 } 579 } 580 } 581 } 582 583 #if OSL_DEBUG_LEVEL > 1 584 char pBuf[ 128 ]; 585 fprintf( stderr, "selected inputmethod style = %s\n", 586 GetMethodName(mnPreeditStyle | mnStatusStyle, pBuf, sizeof(pBuf)) ); 587 #endif 588 589 return (mnPreeditStyle != 0) && (mnStatusStyle != 0) ; 590 } 591 592 // --------------------------------------------------------------------------- 593 // 594 // handle extended and normal key input 595 // 596 // --------------------------------------------------------------------------- 597 598 int 599 SalI18N_InputContext::CommitStringCallback (sal_Unicode* pText, sal_Size nLength) 600 { 601 XIMUnicodeText call_data; 602 603 call_data.string.utf16_char = pText; 604 call_data.length = nLength; 605 call_data.annotations = NULL; 606 call_data.count_annotations = 0; 607 call_data.feedback = NULL; 608 609 return ::CommitStringCallback( maContext, 610 (XPointer)&maClientData, (XPointer)&call_data ); 611 } 612 613 int 614 SalI18N_InputContext::CommitKeyEvent(sal_Unicode* pText, sal_Size nLength) 615 { 616 if (nLength == 1 && IsControlCode(pText[0])) 617 return 0; 618 619 if( maClientData.pFrame ) 620 { 621 SalExtTextInputEvent aTextEvent; 622 623 aTextEvent.mnTime = 0; 624 aTextEvent.mpTextAttr = 0; 625 aTextEvent.mnCursorPos = nLength; 626 aTextEvent.maText = UniString(pText, nLength); 627 aTextEvent.mnCursorFlags = 0; 628 aTextEvent.mnDeltaStart = 0; 629 aTextEvent.mbOnlyCursor = False; 630 631 maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aTextEvent); 632 maClientData.pFrame->CallCallback(SALEVENT_ENDEXTTEXTINPUT, (void*)NULL); 633 } 634 #if OSL_DEBUG_LEVEL > 1 635 else 636 fprintf(stderr, "CommitKeyEvent without frame\n" ); 637 #endif 638 639 return 0; 640 } 641 642 int 643 SalI18N_InputContext::UpdateSpotLocation() 644 { 645 if (maContext == 0 || maClientData.pFrame == NULL) 646 return -1; 647 648 SalExtTextInputPosEvent aPosEvent; 649 maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent); 650 651 XPoint aSpot; 652 aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth; 653 aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight; 654 655 XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &aSpot, NULL); 656 XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL); 657 XFree(preedit_attr); 658 659 I18NStatus::get().show( true, I18NStatus::contextmap ); 660 661 return 0; 662 } 663 664 // --------------------------------------------------------------------------- 665 // 666 // set and unset the focus for the Input Context 667 // the context may be NULL despite it is useable if the framewindow is 668 // in unmapped state 669 // 670 // --------------------------------------------------------------------------- 671 672 void 673 SalI18N_InputContext::SetICFocus( SalFrame* pFocusFrame ) 674 { 675 I18NStatus::get().setParent( pFocusFrame ); 676 if ( mbUseable && (maContext != NULL) ) 677 { 678 maClientData.pFrame = pFocusFrame; 679 680 const SystemEnvData* pEnv = pFocusFrame->GetSystemData(); 681 XLIB_Window aClientWindow = pEnv->aShellWindow; 682 XLIB_Window aFocusWindow = pEnv->aWindow; 683 684 XSetICValues( maContext, 685 XNFocusWindow, aFocusWindow, 686 XNClientWindow, aClientWindow, 687 NULL ); 688 689 if( maClientData.aInputEv.mpTextAttr ) 690 { 691 sendEmptyCommit(pFocusFrame); 692 // begin preedit again 693 GetX11SalData()->GetDisplay()->SendInternalEvent( pFocusFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT ); 694 } 695 696 XSetICFocus( maContext ); 697 } 698 } 699 700 void 701 SalI18N_InputContext::UnsetICFocus( SalFrame* pFrame ) 702 { 703 I18NStatus& rStatus( I18NStatus::get() ); 704 if( rStatus.getParent() == pFrame ) 705 rStatus.setParent( NULL ); 706 707 if ( mbUseable && (maContext != NULL) ) 708 { 709 // cancel an eventual event posted to begin preedit again 710 GetX11SalData()->GetDisplay()->CancelInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT ); 711 maClientData.pFrame = NULL; 712 XUnsetICFocus( maContext ); 713 } 714 } 715 716 // --------------------------------------------------------------------------- 717 // 718 // multi byte input method only 719 // 720 // --------------------------------------------------------------------------- 721 722 void 723 SalI18N_InputContext::SetPreeditState(Bool aPreeditState) 724 { 725 XIMPreeditState preedit_state = XIMPreeditUnKnown; 726 XVaNestedList preedit_attr; 727 728 preedit_attr = XVaCreateNestedList( 729 0, 730 XNPreeditState, &preedit_state, 731 NULL); 732 if (!XGetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL)) 733 { 734 XFree(preedit_attr); 735 736 preedit_state = aPreeditState? XIMPreeditEnable : XIMPreeditDisable; 737 preedit_attr = XVaCreateNestedList( 738 0, 739 XNPreeditState, preedit_state, 740 NULL); 741 XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL); 742 } 743 744 XFree(preedit_attr); 745 746 return; 747 } 748 749 void 750 SalI18N_InputContext::SetLanguage(LanguageType) 751 { 752 // not yet implemented 753 return; 754 } 755 756 void 757 SalI18N_InputContext::EndExtTextInput( sal_uInt16 /*nFlags*/ ) 758 { 759 if ( mbUseable && (maContext != NULL) && maClientData.pFrame ) 760 { 761 vcl::DeletionListener aDel( maClientData.pFrame ); 762 // delete preedit in sal (commit an empty string) 763 sendEmptyCommit( maClientData.pFrame ); 764 if( ! aDel.isDeleted() ) 765 { 766 // mark previous preedit state again (will e.g. be sent at focus gain) 767 maClientData.aInputEv.mpTextAttr = &maClientData.aInputFlags[0]; 768 if( static_cast<X11SalFrame*>(maClientData.pFrame)->hasFocus() ) 769 { 770 // begin preedit again 771 GetX11SalData()->GetDisplay()->SendInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT ); 772 } 773 } 774 } 775 } 776 777 778