Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <stdio.h>
22 :
23 : #include <sal/alloca.h>
24 : #include <osl/thread.h>
25 :
26 : #include <tools/prex.h>
27 : #include <X11/Xlocale.h>
28 : #include <X11/Xlib.h>
29 : #include <tools/postx.h>
30 :
31 : #include <unx/salunx.h>
32 : #include <unx/XIM.h>
33 : #include <unx/i18n_ic.hxx>
34 : #include <unx/i18n_im.hxx>
35 : #include <unx/i18n_status.hxx>
36 :
37 : #include <unx/salframe.h>
38 : #include <unx/saldata.hxx>
39 : #include <unx/saldisp.hxx>
40 :
41 : using namespace vcl;
42 :
43 0 : static void sendEmptyCommit( SalFrame* pFrame )
44 : {
45 0 : vcl::DeletionListener aDel( pFrame );
46 :
47 0 : SalExtTextInputEvent aEmptyEv;
48 0 : aEmptyEv.mnTime = 0;
49 0 : aEmptyEv.mpTextAttr = 0;
50 0 : aEmptyEv.maText = String();
51 0 : aEmptyEv.mnCursorPos = 0;
52 0 : aEmptyEv.mnCursorFlags = 0;
53 0 : aEmptyEv.mnDeltaStart = 0;
54 0 : aEmptyEv.mbOnlyCursor = False;
55 0 : pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
56 0 : if( ! aDel.isDeleted() )
57 0 : pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
58 0 : }
59 :
60 : // ---------------------------------------------------------------------------
61 : //
62 : // Constructor / Destructor, the InputContext is bound to the SalFrame, as it
63 : // needs the shell window as a focus window
64 : //
65 : // ----------------------------------------------------------------------------
66 :
67 0 : SalI18N_InputContext::~SalI18N_InputContext()
68 : {
69 0 : if ( maContext != NULL )
70 0 : XDestroyIC( maContext );
71 0 : if ( mpAttributes != NULL )
72 0 : XFree( mpAttributes );
73 0 : if ( mpStatusAttributes != NULL )
74 0 : XFree( mpStatusAttributes );
75 0 : if ( mpPreeditAttributes != NULL )
76 0 : XFree( mpPreeditAttributes );
77 :
78 0 : if (maClientData.aText.pUnicodeBuffer != NULL)
79 0 : free(maClientData.aText.pUnicodeBuffer);
80 0 : if (maClientData.aText.pCharStyle != NULL)
81 0 : free(maClientData.aText.pCharStyle);
82 0 : }
83 :
84 : // ----------------------------------------------------------------------------
85 : // convenience routine to add items to a XVaNestedList
86 : // ----------------------------------------------------------------------------
87 :
88 : static XVaNestedList
89 0 : XVaAddToNestedList( XVaNestedList a_srclist, char* name, XPointer value )
90 : {
91 : XVaNestedList a_dstlist;
92 :
93 : // if ( value == NULL )
94 : // return a_srclist;
95 :
96 0 : if ( a_srclist == NULL )
97 : {
98 : a_dstlist = XVaCreateNestedList(
99 : 0,
100 : name, value,
101 0 : NULL );
102 : }
103 : else
104 : {
105 : a_dstlist = XVaCreateNestedList(
106 : 0,
107 : XNVaNestedList, a_srclist,
108 : name, value,
109 0 : NULL );
110 : }
111 :
112 0 : return a_dstlist != NULL ? a_dstlist : a_srclist ;
113 : }
114 :
115 : // ----------------------------------------------------------------------------
116 : // convenience routine to create a fontset
117 : // ----------------------------------------------------------------------------
118 :
119 : static XFontSet
120 0 : get_font_set( Display *p_display )
121 : {
122 : static XFontSet p_font_set = NULL;
123 :
124 0 : if (p_font_set == NULL)
125 : {
126 : char **pp_missing_list;
127 : int n_missing_count;
128 : char *p_default_string;
129 :
130 : p_font_set = XCreateFontSet(p_display, "-*",
131 0 : &pp_missing_list, &n_missing_count, &p_default_string);
132 : }
133 :
134 0 : return p_font_set;
135 : }
136 :
137 : // ---------------------------------------------------------------------------
138 : //
139 : // Constructor for a InputContext (IC)
140 : //
141 : // ----------------------------------------------------------------------------
142 :
143 0 : SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) :
144 : mbUseable( True ),
145 : maContext( (XIC)NULL ),
146 : mnSupportedStatusStyle(
147 : XIMStatusCallbacks |
148 : XIMStatusNothing |
149 : XIMStatusNone
150 : ),
151 : mnSupportedPreeditStyle(
152 : XIMPreeditCallbacks |
153 : XIMPreeditNothing |
154 : XIMPreeditNone
155 : ),
156 : mnStatusStyle( 0 ),
157 : mnPreeditStyle( 0 ),
158 : mpAttributes( NULL ),
159 : mpStatusAttributes( NULL ),
160 0 : mpPreeditAttributes( NULL )
161 : {
162 : #ifdef SOLARIS
163 : static const char* pIIIMPEnable = getenv( "SAL_DISABLE_OWN_IM_STATUS" );
164 : if( pIIIMPEnable && *pIIIMPEnable )
165 : mnSupportedStatusStyle &= ~XIMStatusCallbacks;
166 : #endif
167 :
168 0 : maClientData.aText.pUnicodeBuffer = NULL;
169 0 : maClientData.aText.pCharStyle = NULL;
170 0 : maClientData.aInputEv.mnTime = 0;
171 0 : maClientData.aInputEv.mpTextAttr = NULL;
172 0 : maClientData.aInputEv.mnCursorPos = 0;
173 0 : maClientData.aInputEv.mnDeltaStart = 0;
174 0 : maClientData.aInputEv.mnCursorFlags = 0;
175 0 : maClientData.aInputEv.mbOnlyCursor = sal_False;
176 :
177 : SalI18N_InputMethod *pInputMethod;
178 0 : pInputMethod = GetGenericData()->GetSalDisplay()->GetInputMethod();
179 :
180 : mnSupportedPreeditStyle = XIMPreeditCallbacks | XIMPreeditPosition
181 0 : | XIMPreeditNothing | XIMPreeditNone;
182 0 : if (pInputMethod->UseMethod()
183 0 : && SupportInputMethodStyle( pInputMethod->GetSupportedStyles() ) )
184 : {
185 0 : const SystemEnvData* pEnv = pFrame->GetSystemData();
186 0 : XLIB_Window aClientWindow = pEnv->aShellWindow;
187 0 : XLIB_Window aFocusWindow = pEnv->aWindow;
188 :
189 : // for status callbacks and commit string callbacks
190 : #define PREEDIT_BUFSZ 16
191 0 : maClientData.eState = ePreeditStatusStartPending;
192 0 : maClientData.pFrame = pFrame;
193 : maClientData.aText.pUnicodeBuffer =
194 0 : (sal_Unicode*)malloc(PREEDIT_BUFSZ * sizeof(sal_Unicode));
195 : maClientData.aText.pCharStyle =
196 0 : (XIMFeedback*)malloc(PREEDIT_BUFSZ * sizeof(XIMFeedback));
197 0 : maClientData.aText.nSize = PREEDIT_BUFSZ;
198 0 : maClientData.aText.nCursorPos = 0;
199 0 : maClientData.aText.nLength = 0;
200 :
201 : //
202 : // Status attributes
203 : //
204 :
205 0 : switch ( mnStatusStyle )
206 : {
207 : case XIMStatusCallbacks:
208 : {
209 : static XIMCallback aStatusStartCallback;
210 : static XIMCallback aStatusDoneCallback;
211 : static XIMCallback aStatusDrawCallback;
212 :
213 0 : aStatusStartCallback.callback = (XIMProc)StatusStartCallback;
214 0 : aStatusStartCallback.client_data = (XPointer)&maClientData;
215 0 : aStatusDoneCallback.callback = (XIMProc)StatusDoneCallback;
216 0 : aStatusDoneCallback.client_data = (XPointer)&maClientData;
217 0 : aStatusDrawCallback.callback = (XIMProc)StatusDrawCallback;
218 0 : aStatusDrawCallback.client_data = (XPointer)&maClientData;
219 :
220 : mpStatusAttributes = XVaCreateNestedList (
221 : 0,
222 : XNStatusStartCallback, &aStatusStartCallback,
223 : XNStatusDoneCallback, &aStatusDoneCallback,
224 : XNStatusDrawCallback, &aStatusDrawCallback,
225 0 : NULL );
226 :
227 0 : break;
228 : }
229 :
230 : case XIMStatusArea:
231 : /* not supported */
232 0 : break;
233 :
234 : case XIMStatusNone:
235 : case XIMStatusNothing:
236 : default:
237 : /* no arguments needed */
238 0 : break;
239 : }
240 :
241 : //
242 : // set preedit attributes
243 : //
244 :
245 0 : switch ( mnPreeditStyle )
246 : {
247 : case XIMPreeditCallbacks:
248 :
249 0 : maPreeditCaretCallback.callback = (XIMProc)PreeditCaretCallback;
250 0 : maPreeditStartCallback.callback = (XIMProc)PreeditStartCallback;
251 0 : maPreeditDoneCallback.callback = (XIMProc)PreeditDoneCallback;
252 0 : maPreeditDrawCallback.callback = (XIMProc)PreeditDrawCallback;
253 0 : maPreeditCaretCallback.client_data = (XPointer)&maClientData;
254 0 : maPreeditStartCallback.client_data = (XPointer)&maClientData;
255 0 : maPreeditDoneCallback.client_data = (XPointer)&maClientData;
256 0 : maPreeditDrawCallback.client_data = (XPointer)&maClientData;
257 :
258 : mpPreeditAttributes = XVaCreateNestedList (
259 : 0,
260 : XNPreeditStartCallback, &maPreeditStartCallback,
261 : XNPreeditDoneCallback, &maPreeditDoneCallback,
262 : XNPreeditDrawCallback, &maPreeditDrawCallback,
263 : XNPreeditCaretCallback, &maPreeditCaretCallback,
264 0 : NULL );
265 :
266 0 : break;
267 :
268 : case XIMPreeditArea:
269 : /* not supported */
270 0 : break;
271 :
272 : case XIMPreeditPosition:
273 : {
274 : // spot location
275 : SalExtTextInputPosEvent aPosEvent;
276 0 : pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent);
277 :
278 : static XPoint aSpot;
279 0 : aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth;
280 0 : aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight;
281 :
282 : // create attributes for preedit position style
283 : mpPreeditAttributes = XVaCreateNestedList (
284 : 0,
285 : XNSpotLocation, &aSpot,
286 0 : NULL );
287 :
288 : // XCreateIC() fails on Redflag Linux 2.0 if there is no
289 : // fontset though the data itself is not evaluated nor is
290 : // it required according to the X specs.
291 0 : Display* pDisplay = GetGenericData()->GetSalDisplay()->GetDisplay();
292 0 : XFontSet pFontSet = get_font_set(pDisplay);
293 :
294 0 : if (pFontSet != NULL)
295 : {
296 : mpPreeditAttributes = XVaAddToNestedList( mpPreeditAttributes,
297 0 : const_cast<char*>(XNFontSet), (XPointer)pFontSet);
298 : }
299 :
300 : break;
301 : }
302 :
303 : case XIMPreeditNone:
304 : case XIMPreeditNothing:
305 : default:
306 : /* no arguments needed */
307 0 : break;
308 : }
309 :
310 : // Create the InputContext by giving it exactly the information it
311 : // deserves, because inappropriate attributes
312 : // let XCreateIC fail on Solaris (eg. for C locale)
313 :
314 : mpAttributes = XVaCreateNestedList(
315 : 0,
316 : XNFocusWindow, aFocusWindow,
317 : XNClientWindow, aClientWindow,
318 : XNInputStyle, mnPreeditStyle | mnStatusStyle,
319 0 : NULL );
320 :
321 0 : if ( mnPreeditStyle != XIMPreeditNone )
322 : {
323 : #if defined LINUX || defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY
324 0 : if ( mpPreeditAttributes != NULL )
325 : #endif
326 : mpAttributes = XVaAddToNestedList( mpAttributes,
327 0 : const_cast<char*>(XNPreeditAttributes), (XPointer)mpPreeditAttributes );
328 : }
329 0 : if ( mnStatusStyle != XIMStatusNone )
330 : {
331 : #if defined LINUX || defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY
332 0 : if ( mpStatusAttributes != NULL )
333 : #endif
334 : mpAttributes = XVaAddToNestedList( mpAttributes,
335 0 : const_cast<char*>(XNStatusAttributes), (XPointer)mpStatusAttributes );
336 : }
337 : maContext = XCreateIC( pInputMethod->GetMethod(),
338 : XNVaNestedList, mpAttributes,
339 0 : NULL );
340 : }
341 :
342 0 : if ( maContext == NULL )
343 : {
344 : #if OSL_DEBUG_LEVEL > 1
345 : fprintf(stderr, "input context creation failed\n");
346 : #endif
347 :
348 0 : mbUseable = False;
349 :
350 0 : if ( mpAttributes != NULL )
351 0 : XFree( mpAttributes );
352 0 : if ( mpStatusAttributes != NULL )
353 0 : XFree( mpStatusAttributes );
354 0 : if ( mpPreeditAttributes != NULL )
355 0 : XFree( mpPreeditAttributes );
356 0 : if ( maClientData.aText.pUnicodeBuffer != NULL )
357 0 : free ( maClientData.aText.pUnicodeBuffer );
358 0 : if ( maClientData.aText.pCharStyle != NULL )
359 0 : free ( maClientData.aText.pCharStyle );
360 :
361 0 : mpAttributes = NULL;
362 0 : mpStatusAttributes = NULL;
363 0 : mpPreeditAttributes = NULL;
364 0 : maClientData.aText.pUnicodeBuffer = NULL;
365 0 : maClientData.aText.pCharStyle = NULL;
366 : }
367 :
368 0 : if ( maContext != NULL)
369 : {
370 0 : maDestroyCallback.callback = (XIMProc)IC_IMDestroyCallback;
371 0 : maDestroyCallback.client_data = (XPointer)this;
372 : XSetICValues( maContext,
373 : XNDestroyCallback, &maDestroyCallback,
374 0 : NULL );
375 : }
376 0 : }
377 :
378 : // ---------------------------------------------------------------------------
379 : //
380 : // In Solaris 8 the status window does not unmap if the frame unmapps, so
381 : // unmap it the hard way
382 : //
383 : // ---------------------------------------------------------------------------
384 :
385 : void
386 0 : SalI18N_InputContext::Unmap( SalFrame* pFrame )
387 : {
388 0 : if ( maContext != NULL )
389 : {
390 0 : I18NStatus& rStatus( I18NStatus::get() );
391 0 : if( rStatus.getParent() == pFrame )
392 0 : rStatus.show( false, I18NStatus::contextmap );
393 :
394 : }
395 0 : UnsetICFocus( pFrame );
396 0 : maClientData.pFrame = NULL;
397 0 : }
398 :
399 : void
400 0 : SalI18N_InputContext::Map( SalFrame *pFrame )
401 : {
402 0 : if( mbUseable )
403 : {
404 0 : I18NStatus& rStatus(I18NStatus::get() );
405 0 : rStatus.setParent( pFrame );
406 0 : if( pFrame )
407 : {
408 0 : rStatus.show( true, I18NStatus::contextmap );
409 0 : if ( maContext == NULL )
410 : {
411 : SalI18N_InputMethod *pInputMethod;
412 0 : pInputMethod = GetGenericData()->GetSalDisplay()->GetInputMethod();
413 :
414 : maContext = XCreateIC( pInputMethod->GetMethod(),
415 : XNVaNestedList, mpAttributes,
416 0 : NULL );
417 : }
418 0 : if( maClientData.pFrame != pFrame )
419 0 : SetICFocus( pFrame );
420 : }
421 : }
422 0 : }
423 :
424 : // --------------------------------------------------------------------------
425 : //
426 : // Handle DestroyCallbacks
427 : // in fact this is a callback called from the XNDestroyCallback
428 : //
429 : // --------------------------------------------------------------------------
430 :
431 : void
432 0 : SalI18N_InputContext::HandleDestroyIM()
433 : {
434 0 : maContext = 0; // noli me tangere
435 0 : mbUseable = False;
436 0 : }
437 :
438 : // ---------------------------------------------------------------------------
439 : //
440 : // make sure, the input method gets all the X-Events it needs, this is only
441 : // called once on each frame, it relys on a valid maContext
442 : //
443 : // ---------------------------------------------------------------------------
444 :
445 : void
446 0 : SalI18N_InputContext::ExtendEventMask( XLIB_Window aFocusWindow )
447 : {
448 : unsigned long nIMEventMask;
449 : XWindowAttributes aWindowAttributes;
450 :
451 0 : if ( mbUseable )
452 : {
453 0 : Display *pDisplay = XDisplayOfIM( XIMOfIC(maContext) );
454 :
455 : XGetWindowAttributes( pDisplay, aFocusWindow,
456 0 : &aWindowAttributes );
457 : XGetICValues ( maContext,
458 : XNFilterEvents, &nIMEventMask,
459 0 : NULL);
460 0 : nIMEventMask |= aWindowAttributes.your_event_mask;
461 0 : XSelectInput ( pDisplay, aFocusWindow, nIMEventMask );
462 : }
463 0 : }
464 :
465 : // ---------------------------------------------------------------------------
466 : //
467 : // tune the styles provided by the input method with the supported one
468 : //
469 : // ---------------------------------------------------------------------------
470 :
471 : unsigned int
472 0 : SalI18N_InputContext::GetWeightingOfIMStyle( XIMStyle nStyle ) const
473 : {
474 : struct StyleWeightingT {
475 : const XIMStyle nStyle;
476 : const unsigned int nWeight;
477 : };
478 :
479 : StyleWeightingT const *pWeightPtr;
480 : const StyleWeightingT pWeight[] = {
481 : { XIMPreeditCallbacks, 0x10000000 },
482 : { XIMPreeditPosition, 0x02000000 },
483 : { XIMPreeditArea, 0x01000000 },
484 : { XIMPreeditNothing, 0x00100000 },
485 : { XIMPreeditNone, 0x00010000 },
486 : { XIMStatusCallbacks, 0x1000 },
487 : { XIMStatusArea, 0x0100 },
488 : { XIMStatusNothing, 0x0010 },
489 : { XIMStatusNone, 0x0001 },
490 : { 0, 0x0 }
491 0 : };
492 :
493 0 : int nWeight = 0;
494 0 : for ( pWeightPtr = pWeight; pWeightPtr->nStyle != 0; pWeightPtr++ )
495 : {
496 0 : if ( (pWeightPtr->nStyle & nStyle) != 0 )
497 0 : nWeight += pWeightPtr->nWeight;
498 : }
499 0 : return nWeight;
500 : }
501 :
502 : Bool
503 0 : SalI18N_InputContext::IsSupportedIMStyle( XIMStyle nStyle ) const
504 : {
505 0 : if ( (nStyle & mnSupportedPreeditStyle)
506 : && (nStyle & mnSupportedStatusStyle) )
507 : {
508 0 : return True;
509 : }
510 0 : return False;
511 : }
512 :
513 : Bool
514 0 : SalI18N_InputContext::SupportInputMethodStyle( XIMStyles *pIMStyles )
515 : {
516 0 : mnPreeditStyle = 0;
517 0 : mnStatusStyle = 0;
518 :
519 0 : if ( pIMStyles != NULL )
520 : {
521 0 : int nBestScore = 0;
522 0 : int nActualScore = 0;
523 :
524 : // check whether the XIM supports one of the desired styles
525 : // only a single preedit and a single status style must occure
526 : // in a inpuut method style. Hideki said so, so i trust him
527 0 : for ( int nStyle = 0; nStyle < pIMStyles->count_styles; nStyle++ )
528 : {
529 0 : XIMStyle nProvidedStyle = pIMStyles->supported_styles[ nStyle ];
530 0 : if ( IsSupportedIMStyle(nProvidedStyle) )
531 : {
532 0 : nActualScore = GetWeightingOfIMStyle( nProvidedStyle );
533 0 : if ( nActualScore >= nBestScore )
534 : {
535 0 : nBestScore = nActualScore;
536 0 : mnPreeditStyle = nProvidedStyle & mnSupportedPreeditStyle;
537 0 : mnStatusStyle = nProvidedStyle & mnSupportedStatusStyle;
538 : }
539 : }
540 : }
541 : }
542 :
543 : #if OSL_DEBUG_LEVEL > 1
544 : char pBuf[ 128 ];
545 : fprintf( stderr, "selected inputmethod style = %s\n",
546 : GetMethodName(mnPreeditStyle | mnStatusStyle, pBuf, sizeof(pBuf)) );
547 : #endif
548 :
549 0 : return (mnPreeditStyle != 0) && (mnStatusStyle != 0) ;
550 : }
551 :
552 : // ---------------------------------------------------------------------------
553 : //
554 : // handle extended and normal key input
555 : //
556 : // ---------------------------------------------------------------------------
557 :
558 : int
559 0 : SalI18N_InputContext::CommitKeyEvent(sal_Unicode* pText, sal_Size nLength)
560 : {
561 0 : if (nLength == 1 && IsControlCode(pText[0]))
562 0 : return 0;
563 :
564 0 : if( maClientData.pFrame )
565 : {
566 0 : SalExtTextInputEvent aTextEvent;
567 :
568 0 : aTextEvent.mnTime = 0;
569 0 : aTextEvent.mpTextAttr = 0;
570 0 : aTextEvent.mnCursorPos = nLength;
571 0 : aTextEvent.maText = rtl::OUString(pText, nLength);
572 0 : aTextEvent.mnCursorFlags = 0;
573 0 : aTextEvent.mnDeltaStart = 0;
574 0 : aTextEvent.mbOnlyCursor = False;
575 :
576 0 : maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aTextEvent);
577 0 : maClientData.pFrame->CallCallback(SALEVENT_ENDEXTTEXTINPUT, (void*)NULL);
578 : }
579 : #if OSL_DEBUG_LEVEL > 1
580 : else
581 : fprintf(stderr, "CommitKeyEvent without frame\n" );
582 : #endif
583 :
584 0 : return 0;
585 : }
586 :
587 : int
588 0 : SalI18N_InputContext::UpdateSpotLocation()
589 : {
590 0 : if (maContext == 0 || maClientData.pFrame == NULL)
591 0 : return -1;
592 :
593 : SalExtTextInputPosEvent aPosEvent;
594 0 : maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent);
595 :
596 : XPoint aSpot;
597 0 : aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth;
598 0 : aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight;
599 :
600 0 : XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &aSpot, NULL);
601 0 : XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL);
602 0 : XFree(preedit_attr);
603 :
604 0 : I18NStatus::get().show( true, I18NStatus::contextmap );
605 :
606 0 : return 0;
607 : }
608 :
609 : // ---------------------------------------------------------------------------
610 : //
611 : // set and unset the focus for the Input Context
612 : // the context may be NULL despite it is useable if the framewindow is
613 : // in unmapped state
614 : //
615 : // ---------------------------------------------------------------------------
616 :
617 : void
618 0 : SalI18N_InputContext::SetICFocus( SalFrame* pFocusFrame )
619 : {
620 0 : I18NStatus::get().setParent( pFocusFrame );
621 0 : if ( mbUseable && (maContext != NULL) )
622 : {
623 0 : maClientData.pFrame = pFocusFrame;
624 :
625 0 : const SystemEnvData* pEnv = pFocusFrame->GetSystemData();
626 0 : XLIB_Window aClientWindow = pEnv->aShellWindow;
627 0 : XLIB_Window aFocusWindow = pEnv->aWindow;
628 :
629 : XSetICValues( maContext,
630 : XNFocusWindow, aFocusWindow,
631 : XNClientWindow, aClientWindow,
632 0 : NULL );
633 :
634 0 : if( maClientData.aInputEv.mpTextAttr )
635 : {
636 0 : sendEmptyCommit(pFocusFrame);
637 : // begin preedit again
638 0 : GetGenericData()->GetSalDisplay()->SendInternalEvent( pFocusFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
639 : }
640 :
641 0 : XSetICFocus( maContext );
642 : }
643 0 : }
644 :
645 : void
646 0 : SalI18N_InputContext::UnsetICFocus( SalFrame* pFrame )
647 : {
648 0 : I18NStatus& rStatus( I18NStatus::get() );
649 0 : if( rStatus.getParent() == pFrame )
650 0 : rStatus.setParent( NULL );
651 :
652 0 : if ( mbUseable && (maContext != NULL) )
653 : {
654 : // cancel an eventual event posted to begin preedit again
655 0 : GetGenericData()->GetSalDisplay()->CancelInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
656 0 : maClientData.pFrame = NULL;
657 0 : XUnsetICFocus( maContext );
658 : }
659 0 : }
660 :
661 : // ---------------------------------------------------------------------------
662 : //
663 : // multi byte input method only
664 : //
665 : // ---------------------------------------------------------------------------
666 :
667 : void
668 0 : SalI18N_InputContext::SetLanguage(LanguageType)
669 : {
670 : // not yet implemented
671 0 : return;
672 : }
673 :
674 : void
675 0 : SalI18N_InputContext::EndExtTextInput( sal_uInt16 /*nFlags*/ )
676 : {
677 0 : if ( mbUseable && (maContext != NULL) && maClientData.pFrame )
678 : {
679 0 : vcl::DeletionListener aDel( maClientData.pFrame );
680 : // delete preedit in sal (commit an empty string)
681 0 : sendEmptyCommit( maClientData.pFrame );
682 0 : if( ! aDel.isDeleted() )
683 : {
684 : // mark previous preedit state again (will e.g. be sent at focus gain)
685 0 : maClientData.aInputEv.mpTextAttr = &maClientData.aInputFlags[0];
686 0 : if( static_cast<X11SalFrame*>(maClientData.pFrame)->hasFocus() )
687 : {
688 : // begin preedit again
689 0 : GetGenericData()->GetSalDisplay()->SendInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
690 : }
691 0 : }
692 : }
693 0 : }
694 :
695 :
696 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|