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