xref: /aoo41x/main/vcl/unx/generic/app/i18n_ic.cxx (revision cdf0e10c)
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