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