| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include <stdio.h> |
| |
| #include <sal/alloca.h> |
| #include <osl/thread.h> |
| |
| #include <tools/prex.h> |
| #include <X11/Xlocale.h> |
| #include <X11/Xlib.h> |
| #include <tools/postx.h> |
| |
| #include <unx/salunx.h> |
| #include <unx/XIM.h> |
| #include <unx/i18n_ic.hxx> |
| #include <unx/i18n_im.hxx> |
| #include <unx/i18n_status.hxx> |
| |
| #include <unx/salframe.h> |
| #include <unx/saldata.hxx> |
| #include <unx/saldisp.hxx> |
| |
| using namespace vcl; |
| |
| static void sendEmptyCommit( SalFrame* pFrame ) |
| { |
| vcl::DeletionListener aDel( pFrame ); |
| |
| SalExtTextInputEvent aEmptyEv; |
| aEmptyEv.mnTime = 0; |
| aEmptyEv.mpTextAttr = 0; |
| aEmptyEv.maText = String(); |
| aEmptyEv.mnCursorPos = 0; |
| aEmptyEv.mnCursorFlags = 0; |
| aEmptyEv.mnDeltaStart = 0; |
| aEmptyEv.mbOnlyCursor = False; |
| pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv ); |
| if( ! aDel.isDeleted() ) |
| pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL ); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // |
| // Constructor / Destructor, the InputContext is bound to the SalFrame, as it |
| // needs the shell window as a focus window |
| // |
| // ---------------------------------------------------------------------------- |
| |
| SalI18N_InputContext::~SalI18N_InputContext() |
| { |
| if ( maContext != NULL ) |
| XDestroyIC( maContext ); |
| if ( mpAttributes != NULL ) |
| XFree( mpAttributes ); |
| if ( mpStatusAttributes != NULL ) |
| XFree( mpStatusAttributes ); |
| if ( mpPreeditAttributes != NULL ) |
| XFree( mpPreeditAttributes ); |
| |
| if (maClientData.aText.pUnicodeBuffer != NULL) |
| free(maClientData.aText.pUnicodeBuffer); |
| if (maClientData.aText.pCharStyle != NULL) |
| free(maClientData.aText.pCharStyle); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // convenience routine to add items to a XVaNestedList |
| // ---------------------------------------------------------------------------- |
| |
| static XVaNestedList |
| XVaAddToNestedList( XVaNestedList a_srclist, char* name, XPointer value ) |
| { |
| XVaNestedList a_dstlist; |
| |
| // if ( value == NULL ) |
| // return a_srclist; |
| |
| if ( a_srclist == NULL ) |
| { |
| a_dstlist = XVaCreateNestedList( |
| 0, |
| name, value, |
| NULL ); |
| } |
| else |
| { |
| a_dstlist = XVaCreateNestedList( |
| 0, |
| XNVaNestedList, a_srclist, |
| name, value, |
| NULL ); |
| } |
| |
| return a_dstlist != NULL ? a_dstlist : a_srclist ; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // convenience routine to create a fontset |
| // ---------------------------------------------------------------------------- |
| |
| static XFontSet |
| get_font_set( Display *p_display ) |
| { |
| static XFontSet p_font_set = NULL; |
| |
| if (p_font_set == NULL) |
| { |
| char **pp_missing_list; |
| int n_missing_count; |
| char *p_default_string; |
| |
| p_font_set = XCreateFontSet(p_display, "-*", |
| &pp_missing_list, &n_missing_count, &p_default_string); |
| } |
| |
| return p_font_set; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // |
| // Constructor for a InputContext (IC) |
| // |
| // ---------------------------------------------------------------------------- |
| |
| SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) : |
| mbUseable( True ), |
| maContext( (XIC)NULL ), |
| mnSupportedStatusStyle( |
| XIMStatusCallbacks | |
| XIMStatusNothing | |
| XIMStatusNone |
| ), |
| mnSupportedPreeditStyle( |
| XIMPreeditCallbacks | |
| XIMPreeditNothing | |
| XIMPreeditNone |
| ), |
| mnStatusStyle( 0 ), |
| mnPreeditStyle( 0 ), |
| mpAttributes( NULL ), |
| mpStatusAttributes( NULL ), |
| mpPreeditAttributes( NULL ) |
| { |
| #ifdef SOLARIS |
| static const char* pIIIMPEnable = getenv( "SAL_DISABLE_OWN_IM_STATUS" ); |
| if( pIIIMPEnable && *pIIIMPEnable ) |
| mnSupportedStatusStyle &= ~XIMStatusCallbacks; |
| #endif |
| |
| maClientData.aText.pUnicodeBuffer = NULL; |
| maClientData.aText.pCharStyle = NULL; |
| maClientData.aInputEv.mnTime = 0; |
| maClientData.aInputEv.mpTextAttr = NULL; |
| maClientData.aInputEv.mnCursorPos = 0; |
| maClientData.aInputEv.mnDeltaStart = 0; |
| maClientData.aInputEv.mnCursorFlags = 0; |
| maClientData.aInputEv.mbOnlyCursor = sal_False; |
| |
| SalI18N_InputMethod *pInputMethod; |
| pInputMethod = GetX11SalData()->GetDisplay()->GetInputMethod(); |
| mbMultiLingual = pInputMethod->IsMultiLingual(); |
| |
| mnSupportedPreeditStyle = XIMPreeditCallbacks | XIMPreeditPosition |
| | XIMPreeditNothing | XIMPreeditNone; |
| if (pInputMethod->UseMethod() |
| && SupportInputMethodStyle( pInputMethod->GetSupportedStyles() ) ) |
| { |
| const SystemEnvData* pEnv = pFrame->GetSystemData(); |
| XLIB_Window aClientWindow = pEnv->aShellWindow; |
| XLIB_Window aFocusWindow = pEnv->aWindow; |
| |
| // for status callbacks and commit string callbacks |
| #define PREEDIT_BUFSZ 16 |
| maClientData.bIsMultilingual = mbMultiLingual; |
| maClientData.eState = ePreeditStatusStartPending; |
| maClientData.pFrame = pFrame; |
| maClientData.aText.pUnicodeBuffer = |
| (sal_Unicode*)malloc(PREEDIT_BUFSZ * sizeof(sal_Unicode)); |
| maClientData.aText.pCharStyle = |
| (XIMFeedback*)malloc(PREEDIT_BUFSZ * sizeof(XIMFeedback));; |
| maClientData.aText.nSize = PREEDIT_BUFSZ; |
| maClientData.aText.nCursorPos = 0; |
| maClientData.aText.nLength = 0; |
| |
| // |
| // Status attributes |
| // |
| |
| switch ( mnStatusStyle ) |
| { |
| case XIMStatusCallbacks: |
| { |
| static XIMCallback aStatusStartCallback; |
| static XIMCallback aStatusDoneCallback; |
| static XIMCallback aStatusDrawCallback; |
| |
| aStatusStartCallback.callback = (XIMProc)StatusStartCallback; |
| aStatusStartCallback.client_data = (XPointer)&maClientData; |
| aStatusDoneCallback.callback = (XIMProc)StatusDoneCallback; |
| aStatusDoneCallback.client_data = (XPointer)&maClientData; |
| aStatusDrawCallback.callback = (XIMProc)StatusDrawCallback; |
| aStatusDrawCallback.client_data = (XPointer)&maClientData; |
| |
| mpStatusAttributes = XVaCreateNestedList ( |
| 0, |
| XNStatusStartCallback, &aStatusStartCallback, |
| XNStatusDoneCallback, &aStatusDoneCallback, |
| XNStatusDrawCallback, &aStatusDrawCallback, |
| NULL ); |
| |
| break; |
| } |
| |
| case XIMStatusArea: |
| /* not supported */ |
| break; |
| |
| case XIMStatusNone: |
| case XIMStatusNothing: |
| default: |
| /* no arguments needed */ |
| break; |
| } |
| |
| // |
| // set preedit attributes |
| // |
| |
| switch ( mnPreeditStyle ) |
| { |
| case XIMPreeditCallbacks: |
| |
| maPreeditCaretCallback.callback = (XIMProc)PreeditCaretCallback; |
| maPreeditStartCallback.callback = (XIMProc)PreeditStartCallback; |
| maPreeditDoneCallback.callback = (XIMProc)PreeditDoneCallback; |
| maPreeditDrawCallback.callback = (XIMProc)PreeditDrawCallback; |
| maPreeditCaretCallback.client_data = (XPointer)&maClientData; |
| maPreeditStartCallback.client_data = (XPointer)&maClientData; |
| maPreeditDoneCallback.client_data = (XPointer)&maClientData; |
| maPreeditDrawCallback.client_data = (XPointer)&maClientData; |
| |
| mpPreeditAttributes = XVaCreateNestedList ( |
| 0, |
| XNPreeditStartCallback, &maPreeditStartCallback, |
| XNPreeditDoneCallback, &maPreeditDoneCallback, |
| XNPreeditDrawCallback, &maPreeditDrawCallback, |
| XNPreeditCaretCallback, &maPreeditCaretCallback, |
| NULL ); |
| |
| break; |
| |
| case XIMPreeditArea: |
| /* not supported */ |
| break; |
| |
| case XIMPreeditPosition: |
| { |
| // spot location |
| SalExtTextInputPosEvent aPosEvent; |
| pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent); |
| |
| static XPoint aSpot; |
| aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth; |
| aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight; |
| |
| // create attributes for preedit position style |
| mpPreeditAttributes = XVaCreateNestedList ( |
| 0, |
| XNSpotLocation, &aSpot, |
| NULL ); |
| |
| // XCreateIC() fails on Redflag Linux 2.0 if there is no |
| // fontset though the data itself is not evaluated nor is |
| // it required according to the X specs. |
| Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay(); |
| XFontSet pFontSet = get_font_set(pDisplay); |
| |
| if (pFontSet != NULL) |
| { |
| mpPreeditAttributes = XVaAddToNestedList( mpPreeditAttributes, |
| const_cast<char*>(XNFontSet), (XPointer)pFontSet); |
| } |
| |
| break; |
| } |
| |
| case XIMPreeditNone: |
| case XIMPreeditNothing: |
| default: |
| /* no arguments needed */ |
| break; |
| } |
| |
| // Create the InputContext by giving it exactly the information it |
| // deserves, because inappropriate attributes |
| // let XCreateIC fail on Solaris (eg. for C locale) |
| |
| mpAttributes = XVaCreateNestedList( |
| 0, |
| XNFocusWindow, aFocusWindow, |
| XNClientWindow, aClientWindow, |
| XNInputStyle, mnPreeditStyle | mnStatusStyle, |
| NULL ); |
| |
| if ( mnPreeditStyle != XIMPreeditNone ) |
| { |
| #if defined LINUX || defined FREEBSD || defined NETBSD |
| if ( mpPreeditAttributes != NULL ) |
| #endif |
| mpAttributes = XVaAddToNestedList( mpAttributes, |
| const_cast<char*>(XNPreeditAttributes), (XPointer)mpPreeditAttributes ); |
| } |
| if ( mnStatusStyle != XIMStatusNone ) |
| { |
| #if defined LINUX || defined FREEBSD || defined NETBSD |
| if ( mpStatusAttributes != NULL ) |
| #endif |
| mpAttributes = XVaAddToNestedList( mpAttributes, |
| const_cast<char*>(XNStatusAttributes), (XPointer)mpStatusAttributes ); |
| } |
| maContext = XCreateIC( pInputMethod->GetMethod(), |
| XNVaNestedList, mpAttributes, |
| NULL ); |
| } |
| |
| if ( maContext == NULL ) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| fprintf(stderr, "input context creation failed\n"); |
| #endif |
| |
| mbUseable = False; |
| mbMultiLingual = False; |
| |
| if ( mpAttributes != NULL ) |
| XFree( mpAttributes ); |
| if ( mpStatusAttributes != NULL ) |
| XFree( mpStatusAttributes ); |
| if ( mpPreeditAttributes != NULL ) |
| XFree( mpPreeditAttributes ); |
| if ( maClientData.aText.pUnicodeBuffer != NULL ) |
| free ( maClientData.aText.pUnicodeBuffer ); |
| if ( maClientData.aText.pCharStyle != NULL ) |
| free ( maClientData.aText.pCharStyle ); |
| |
| mpAttributes = NULL; |
| mpStatusAttributes = NULL; |
| mpPreeditAttributes = NULL; |
| maClientData.aText.pUnicodeBuffer = NULL; |
| maClientData.aText.pCharStyle = NULL; |
| } |
| |
| if ( maContext != NULL && mbMultiLingual ) |
| { |
| maCommitStringCallback.callback = (XIMProc)::CommitStringCallback; |
| maCommitStringCallback.client_data = (XPointer)&maClientData; |
| maSwitchIMCallback.callback = (XIMProc)::SwitchIMCallback; |
| maSwitchIMCallback.client_data = (XPointer)&maClientData; |
| XSetICValues( maContext, |
| XNCommitStringCallback, &maCommitStringCallback, |
| XNSwitchIMNotifyCallback, &maSwitchIMCallback, |
| NULL ); |
| } |
| if ( maContext != NULL) |
| { |
| maDestroyCallback.callback = (XIMProc)IC_IMDestroyCallback; |
| maDestroyCallback.client_data = (XPointer)this; |
| XSetICValues( maContext, |
| XNDestroyCallback, &maDestroyCallback, |
| NULL ); |
| } |
| |
| if( mbMultiLingual ) |
| { |
| // set initial IM status |
| XIMUnicodeCharacterSubset* pSubset = NULL; |
| if( ! XGetICValues( maContext, |
| XNUnicodeCharacterSubset, & pSubset, |
| NULL ) |
| && pSubset ) |
| { |
| String aCurrent( ByteString( pSubset->name ), RTL_TEXTENCODING_UTF8 ); |
| ::vcl::I18NStatus::get().changeIM( aCurrent ); |
| ::vcl::I18NStatus::get().setStatusText( aCurrent ); |
| } |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| // |
| // In Solaris 8 the status window does not unmap if the frame unmapps, so |
| // unmap it the hard way |
| // |
| // --------------------------------------------------------------------------- |
| |
| void |
| SalI18N_InputContext::Unmap( SalFrame* pFrame ) |
| { |
| if ( maContext != NULL ) |
| { |
| I18NStatus& rStatus( I18NStatus::get() ); |
| if( rStatus.getParent() == pFrame ) |
| rStatus.show( false, I18NStatus::contextmap ); |
| |
| } |
| UnsetICFocus( pFrame ); |
| maClientData.pFrame = NULL; |
| } |
| |
| void |
| SalI18N_InputContext::Map( SalFrame *pFrame ) |
| { |
| if( mbUseable ) |
| { |
| I18NStatus& rStatus(I18NStatus::get() ); |
| rStatus.setParent( pFrame ); |
| if( pFrame ) |
| { |
| rStatus.show( true, I18NStatus::contextmap ); |
| if ( maContext == NULL ) |
| { |
| SalI18N_InputMethod *pInputMethod; |
| pInputMethod = GetX11SalData()->GetDisplay()->GetInputMethod(); |
| |
| maContext = XCreateIC( pInputMethod->GetMethod(), |
| XNVaNestedList, mpAttributes, |
| NULL ); |
| if ( maContext != NULL && mbMultiLingual ) |
| XSetICValues( maContext, |
| XNCommitStringCallback, &maCommitStringCallback, |
| XNSwitchIMNotifyCallback, &maSwitchIMCallback, |
| NULL ); |
| } |
| if( maClientData.pFrame != pFrame ) |
| SetICFocus( pFrame ); |
| } |
| } |
| } |
| |
| // -------------------------------------------------------------------------- |
| // |
| // Handle DestroyCallbacks |
| // in fact this is a callback called from the XNDestroyCallback |
| // |
| // -------------------------------------------------------------------------- |
| |
| void |
| SalI18N_InputContext::HandleDestroyIM() |
| { |
| maContext = 0; // noli me tangere |
| mbUseable = False; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // |
| // make sure, the input method gets all the X-Events it needs, this is only |
| // called once on each frame, it relys on a valid maContext |
| // |
| // --------------------------------------------------------------------------- |
| |
| void |
| SalI18N_InputContext::ExtendEventMask( XLIB_Window aFocusWindow ) |
| { |
| unsigned long nIMEventMask; |
| XWindowAttributes aWindowAttributes; |
| |
| if ( mbUseable ) |
| { |
| Display *pDisplay = XDisplayOfIM( XIMOfIC(maContext) ); |
| |
| XGetWindowAttributes( pDisplay, aFocusWindow, |
| &aWindowAttributes ); |
| XGetICValues ( maContext, |
| XNFilterEvents, &nIMEventMask, |
| NULL); |
| nIMEventMask |= aWindowAttributes.your_event_mask; |
| XSelectInput ( pDisplay, aFocusWindow, nIMEventMask ); |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| // |
| // tune the styles provided by the input method with the supported one |
| // |
| // --------------------------------------------------------------------------- |
| |
| unsigned int |
| SalI18N_InputContext::GetWeightingOfIMStyle( XIMStyle nStyle ) const |
| { |
| struct StyleWeightingT { |
| const XIMStyle nStyle; |
| const unsigned int nWeight; |
| }; |
| |
| StyleWeightingT const *pWeightPtr; |
| const StyleWeightingT pWeight[] = { |
| { XIMPreeditCallbacks, 0x10000000 }, |
| { XIMPreeditPosition, 0x02000000 }, |
| { XIMPreeditArea, 0x01000000 }, |
| { XIMPreeditNothing, 0x00100000 }, |
| { XIMPreeditNone, 0x00010000 }, |
| { XIMStatusCallbacks, 0x1000 }, |
| { XIMStatusArea, 0x0100 }, |
| { XIMStatusNothing, 0x0010 }, |
| { XIMStatusNone, 0x0001 }, |
| { 0, 0x0 } |
| }; |
| |
| int nWeight = 0; |
| for ( pWeightPtr = pWeight; pWeightPtr->nStyle != 0; pWeightPtr++ ) |
| { |
| if ( (pWeightPtr->nStyle & nStyle) != 0 ) |
| nWeight += pWeightPtr->nWeight; |
| } |
| return nWeight; |
| } |
| |
| Bool |
| SalI18N_InputContext::IsSupportedIMStyle( XIMStyle nStyle ) const |
| { |
| if ( (nStyle & mnSupportedPreeditStyle) |
| && (nStyle & mnSupportedStatusStyle) ) |
| { |
| return True; |
| } |
| return False; |
| } |
| |
| Bool |
| SalI18N_InputContext::SupportInputMethodStyle( XIMStyles *pIMStyles ) |
| { |
| int nBestScore = 0; |
| int nActualScore = 0; |
| |
| mnPreeditStyle = 0; |
| mnStatusStyle = 0; |
| |
| if ( pIMStyles != NULL ) |
| { |
| // check whether the XIM supports one of the desired styles |
| // only a single preedit and a single status style must occure |
| // in a inpuut method style. Hideki said so, so i trust him |
| for ( int nStyle = 0; nStyle < pIMStyles->count_styles; nStyle++ ) |
| { |
| XIMStyle nProvidedStyle = pIMStyles->supported_styles[ nStyle ]; |
| if ( IsSupportedIMStyle(nProvidedStyle) ) |
| { |
| nActualScore = GetWeightingOfIMStyle( nProvidedStyle ); |
| if ( nActualScore >= nBestScore ) |
| { |
| nBestScore = nActualScore; |
| mnPreeditStyle = nProvidedStyle & mnSupportedPreeditStyle; |
| mnStatusStyle = nProvidedStyle & mnSupportedStatusStyle; |
| } |
| } |
| } |
| } |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| char pBuf[ 128 ]; |
| fprintf( stderr, "selected inputmethod style = %s\n", |
| GetMethodName(mnPreeditStyle | mnStatusStyle, pBuf, sizeof(pBuf)) ); |
| #endif |
| |
| return (mnPreeditStyle != 0) && (mnStatusStyle != 0) ; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // |
| // handle extended and normal key input |
| // |
| // --------------------------------------------------------------------------- |
| |
| int |
| SalI18N_InputContext::CommitStringCallback (sal_Unicode* pText, sal_Size nLength) |
| { |
| XIMUnicodeText call_data; |
| |
| call_data.string.utf16_char = pText; |
| call_data.length = nLength; |
| call_data.annotations = NULL; |
| call_data.count_annotations = 0; |
| call_data.feedback = NULL; |
| |
| return ::CommitStringCallback( maContext, |
| (XPointer)&maClientData, (XPointer)&call_data ); |
| } |
| |
| int |
| SalI18N_InputContext::CommitKeyEvent(sal_Unicode* pText, sal_Size nLength) |
| { |
| if (nLength == 1 && IsControlCode(pText[0])) |
| return 0; |
| |
| if( maClientData.pFrame ) |
| { |
| SalExtTextInputEvent aTextEvent; |
| |
| aTextEvent.mnTime = 0; |
| aTextEvent.mpTextAttr = 0; |
| aTextEvent.mnCursorPos = nLength; |
| aTextEvent.maText = UniString(pText, nLength); |
| aTextEvent.mnCursorFlags = 0; |
| aTextEvent.mnDeltaStart = 0; |
| aTextEvent.mbOnlyCursor = False; |
| |
| maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aTextEvent); |
| maClientData.pFrame->CallCallback(SALEVENT_ENDEXTTEXTINPUT, (void*)NULL); |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| else |
| fprintf(stderr, "CommitKeyEvent without frame\n" ); |
| #endif |
| |
| return 0; |
| } |
| |
| int |
| SalI18N_InputContext::UpdateSpotLocation() |
| { |
| if (maContext == 0 || maClientData.pFrame == NULL) |
| return -1; |
| |
| SalExtTextInputPosEvent aPosEvent; |
| maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent); |
| |
| XPoint aSpot; |
| aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth; |
| aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight; |
| |
| XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &aSpot, NULL); |
| XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL); |
| XFree(preedit_attr); |
| |
| I18NStatus::get().show( true, I18NStatus::contextmap ); |
| |
| return 0; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // |
| // set and unset the focus for the Input Context |
| // the context may be NULL despite it is useable if the framewindow is |
| // in unmapped state |
| // |
| // --------------------------------------------------------------------------- |
| |
| void |
| SalI18N_InputContext::SetICFocus( SalFrame* pFocusFrame ) |
| { |
| I18NStatus::get().setParent( pFocusFrame ); |
| if ( mbUseable && (maContext != NULL) ) |
| { |
| maClientData.pFrame = pFocusFrame; |
| |
| const SystemEnvData* pEnv = pFocusFrame->GetSystemData(); |
| XLIB_Window aClientWindow = pEnv->aShellWindow; |
| XLIB_Window aFocusWindow = pEnv->aWindow; |
| |
| XSetICValues( maContext, |
| XNFocusWindow, aFocusWindow, |
| XNClientWindow, aClientWindow, |
| NULL ); |
| |
| if( maClientData.aInputEv.mpTextAttr ) |
| { |
| sendEmptyCommit(pFocusFrame); |
| // begin preedit again |
| GetX11SalData()->GetDisplay()->SendInternalEvent( pFocusFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT ); |
| } |
| |
| XSetICFocus( maContext ); |
| } |
| } |
| |
| void |
| SalI18N_InputContext::UnsetICFocus( SalFrame* pFrame ) |
| { |
| I18NStatus& rStatus( I18NStatus::get() ); |
| if( rStatus.getParent() == pFrame ) |
| rStatus.setParent( NULL ); |
| |
| if ( mbUseable && (maContext != NULL) ) |
| { |
| // cancel an eventual event posted to begin preedit again |
| GetX11SalData()->GetDisplay()->CancelInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT ); |
| maClientData.pFrame = NULL; |
| XUnsetICFocus( maContext ); |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| // |
| // multi byte input method only |
| // |
| // --------------------------------------------------------------------------- |
| |
| void |
| SalI18N_InputContext::SetPreeditState(Bool aPreeditState) |
| { |
| XIMPreeditState preedit_state = XIMPreeditUnKnown; |
| XVaNestedList preedit_attr; |
| |
| preedit_attr = XVaCreateNestedList( |
| 0, |
| XNPreeditState, &preedit_state, |
| NULL); |
| if (!XGetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL)) |
| { |
| XFree(preedit_attr); |
| |
| preedit_state = aPreeditState? XIMPreeditEnable : XIMPreeditDisable; |
| preedit_attr = XVaCreateNestedList( |
| 0, |
| XNPreeditState, preedit_state, |
| NULL); |
| XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL); |
| } |
| |
| XFree(preedit_attr); |
| |
| return; |
| } |
| |
| void |
| SalI18N_InputContext::SetLanguage(LanguageType) |
| { |
| // not yet implemented |
| return; |
| } |
| |
| void |
| SalI18N_InputContext::EndExtTextInput( sal_uInt16 /*nFlags*/ ) |
| { |
| if ( mbUseable && (maContext != NULL) && maClientData.pFrame ) |
| { |
| vcl::DeletionListener aDel( maClientData.pFrame ); |
| // delete preedit in sal (commit an empty string) |
| sendEmptyCommit( maClientData.pFrame ); |
| if( ! aDel.isDeleted() ) |
| { |
| // mark previous preedit state again (will e.g. be sent at focus gain) |
| maClientData.aInputEv.mpTextAttr = &maClientData.aInputFlags[0]; |
| if( static_cast<X11SalFrame*>(maClientData.pFrame)->hasFocus() ) |
| { |
| // begin preedit again |
| GetX11SalData()->GetDisplay()->SendInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT ); |
| } |
| } |
| } |
| } |
| |
| |