xref: /trunk/main/vcl/unx/generic/app/i18n_ic.cxx (revision 86e1cf34)
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 
sendEmptyCommit(SalFrame * pFrame)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 
~SalI18N_InputContext()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
XVaAddToNestedList(XVaNestedList a_srclist,char * name,XPointer value)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
get_font_set(Display * p_display)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 
SalI18N_InputContext(SalFrame * pFrame)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
Unmap(SalFrame * pFrame)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
Map(SalFrame * pFrame)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
HandleDestroyIM()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
ExtendEventMask(XLIB_Window aFocusWindow)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
GetWeightingOfIMStyle(XIMStyle nStyle) const512 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
IsSupportedIMStyle(XIMStyle nStyle) const543 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
SupportInputMethodStyle(XIMStyles * pIMStyles)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 occur
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
CommitStringCallback(sal_Unicode * pText,sal_Size nLength)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
CommitKeyEvent(sal_Unicode * pText,sal_Size nLength)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
UpdateSpotLocation()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
SetICFocus(SalFrame * pFocusFrame)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
UnsetICFocus(SalFrame * pFrame)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
SetPreeditState(Bool aPreeditState)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
SetLanguage(LanguageType)750 SalI18N_InputContext::SetLanguage(LanguageType)
751 {
752     // not yet implemented
753     return;
754 }
755 
756 void
EndExtTextInput(sal_uInt16)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