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