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