xref: /aoo41x/main/vcl/unx/generic/app/i18n_im.cxx (revision c82f2877)
1*c82f2877SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*c82f2877SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*c82f2877SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*c82f2877SAndrew Rist  * distributed with this work for additional information
6*c82f2877SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*c82f2877SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*c82f2877SAndrew Rist  * "License"); you may not use this file except in compliance
9*c82f2877SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*c82f2877SAndrew Rist  *
11*c82f2877SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*c82f2877SAndrew Rist  *
13*c82f2877SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*c82f2877SAndrew Rist  * software distributed under the License is distributed on an
15*c82f2877SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*c82f2877SAndrew Rist  * KIND, either express or implied.  See the License for the
17*c82f2877SAndrew Rist  * specific language governing permissions and limitations
18*c82f2877SAndrew Rist  * under the License.
19*c82f2877SAndrew Rist  *
20*c82f2877SAndrew Rist  *************************************************************/
21*c82f2877SAndrew Rist 
22*c82f2877SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_vcl.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <stdio.h>
28cdf0e10cSrcweir #include <string.h>
29cdf0e10cSrcweir 
30cdf0e10cSrcweir #ifdef LINUX
31cdf0e10cSrcweir #  ifndef __USE_XOPEN
32cdf0e10cSrcweir #    define __USE_XOPEN
33cdf0e10cSrcweir #  endif
34cdf0e10cSrcweir #endif
35cdf0e10cSrcweir #include <poll.h>
36cdf0e10cSrcweir 
37cdf0e10cSrcweir #include <tools/prex.h>
38cdf0e10cSrcweir #include <X11/Xlocale.h>
39cdf0e10cSrcweir #include <X11/Xlib.h>
40cdf0e10cSrcweir #include <unx/XIM.h>
41cdf0e10cSrcweir #include <tools/postx.h>
42cdf0e10cSrcweir 
43cdf0e10cSrcweir #include "unx/salunx.h"
44cdf0e10cSrcweir #include "unx/saldisp.hxx"
45cdf0e10cSrcweir #include "unx/i18n_im.hxx"
46cdf0e10cSrcweir #include "unx/i18n_status.hxx"
47cdf0e10cSrcweir 
48cdf0e10cSrcweir #include <osl/thread.h>
49cdf0e10cSrcweir #include <osl/process.h>
50cdf0e10cSrcweir 
51cdf0e10cSrcweir using namespace vcl;
52cdf0e10cSrcweir #include "unx/i18n_cb.hxx"
53cdf0e10cSrcweir #if defined(SOLARIS) ||  defined(LINUX)
54cdf0e10cSrcweir extern "C" char * XSetIMValues(XIM im, ...);
55cdf0e10cSrcweir #endif
56cdf0e10cSrcweir 
57cdf0e10cSrcweir // ------------------------------------------------------------------------------------
58cdf0e10cSrcweir //
59cdf0e10cSrcweir // kinput2 IME needs special key handling since key release events are filtered in
60cdf0e10cSrcweir // preeditmode and XmbResetIC does not work
61cdf0e10cSrcweir //
62cdf0e10cSrcweir // ------------------------------------------------------------------------------------
63cdf0e10cSrcweir 
64cdf0e10cSrcweir Bool
IMServerKinput2()65cdf0e10cSrcweir IMServerKinput2 ()
66cdf0e10cSrcweir {
67cdf0e10cSrcweir     const static char* p_xmodifiers = getenv ("XMODIFIERS");
68cdf0e10cSrcweir     const static Bool  b_kinput2    =    (p_xmodifiers != NULL)
69cdf0e10cSrcweir                                       && (strcmp(p_xmodifiers, "@im=kinput2") == 0);
70cdf0e10cSrcweir 
71cdf0e10cSrcweir     return b_kinput2;
72cdf0e10cSrcweir }
73cdf0e10cSrcweir 
74cdf0e10cSrcweir class XKeyEventOp : XKeyEvent
75cdf0e10cSrcweir {
76cdf0e10cSrcweir     private:
77cdf0e10cSrcweir         void            init();
78cdf0e10cSrcweir 
79cdf0e10cSrcweir     public:
80cdf0e10cSrcweir                         XKeyEventOp();
81cdf0e10cSrcweir                         ~XKeyEventOp();
82cdf0e10cSrcweir 
83cdf0e10cSrcweir         XKeyEventOp&    operator= (const XKeyEvent &rEvent);
84cdf0e10cSrcweir         void            erase ();
85cdf0e10cSrcweir         Bool            match (const XKeyEvent &rEvent) const;
86cdf0e10cSrcweir };
87cdf0e10cSrcweir 
88cdf0e10cSrcweir void
init()89cdf0e10cSrcweir XKeyEventOp::init()
90cdf0e10cSrcweir {
91cdf0e10cSrcweir     type        = 0; /* serial = 0; */
92cdf0e10cSrcweir     send_event  = 0; display   = 0;
93cdf0e10cSrcweir     window      = 0; root      = 0;
94cdf0e10cSrcweir     subwindow   = 0; /* time   = 0; */
95cdf0e10cSrcweir  /* x           = 0; y         = 0; */
96cdf0e10cSrcweir  /* x_root      = 0; y_root    = 0; */
97cdf0e10cSrcweir     state       = 0; keycode   = 0;
98cdf0e10cSrcweir     same_screen = 0;
99cdf0e10cSrcweir }
100cdf0e10cSrcweir 
XKeyEventOp()101cdf0e10cSrcweir XKeyEventOp::XKeyEventOp()
102cdf0e10cSrcweir {
103cdf0e10cSrcweir     init();
104cdf0e10cSrcweir }
105cdf0e10cSrcweir 
~XKeyEventOp()106cdf0e10cSrcweir XKeyEventOp::~XKeyEventOp()
107cdf0e10cSrcweir {
108cdf0e10cSrcweir }
109cdf0e10cSrcweir 
110cdf0e10cSrcweir XKeyEventOp&
operator =(const XKeyEvent & rEvent)111cdf0e10cSrcweir XKeyEventOp::operator= (const XKeyEvent &rEvent)
112cdf0e10cSrcweir {
113cdf0e10cSrcweir     type        = rEvent.type;     /* serial  = rEvent.serial; */
114cdf0e10cSrcweir     send_event  = rEvent.send_event;  display = rEvent.display;
115cdf0e10cSrcweir     window      = rEvent.window;      root    = rEvent.root;
116cdf0e10cSrcweir     subwindow   = rEvent.subwindow;/* time    = rEvent.time;   */
117cdf0e10cSrcweir  /* x           = rEvent.x,           y       = rEvent.y;      */
118cdf0e10cSrcweir  /* x_root      = rEvent.x_root,      y_root  = rEvent.y_root; */
119cdf0e10cSrcweir     state       = rEvent.state;       keycode = rEvent.keycode;
120cdf0e10cSrcweir     same_screen = rEvent.same_screen;
121cdf0e10cSrcweir 
122cdf0e10cSrcweir     return *this;
123cdf0e10cSrcweir }
124cdf0e10cSrcweir 
125cdf0e10cSrcweir void
erase()126cdf0e10cSrcweir XKeyEventOp::erase ()
127cdf0e10cSrcweir {
128cdf0e10cSrcweir     init();
129cdf0e10cSrcweir }
130cdf0e10cSrcweir 
131cdf0e10cSrcweir Bool
match(const XKeyEvent & rEvent) const132cdf0e10cSrcweir XKeyEventOp::match (const XKeyEvent &rEvent) const
133cdf0e10cSrcweir {
134cdf0e10cSrcweir     return (   (type == XLIB_KeyPress   && rEvent.type == KeyRelease)
135cdf0e10cSrcweir             || (type == KeyRelease && rEvent.type == XLIB_KeyPress  ))
136cdf0e10cSrcweir          /* && serial      == rEvent.serial */
137cdf0e10cSrcweir             && send_event  == rEvent.send_event
138cdf0e10cSrcweir             && display     == rEvent.display
139cdf0e10cSrcweir             && window      == rEvent.window
140cdf0e10cSrcweir             && root        == rEvent.root
141cdf0e10cSrcweir             && subwindow   == rEvent.subwindow
142cdf0e10cSrcweir          /* && time        == rEvent.time
143cdf0e10cSrcweir             && x           == rEvent.x
144cdf0e10cSrcweir             && y           == rEvent.y
145cdf0e10cSrcweir             && x_root      == rEvent.x_root
146cdf0e10cSrcweir             && y_root      == rEvent.y_root */
147cdf0e10cSrcweir             && state       == rEvent.state
148cdf0e10cSrcweir             && keycode     == rEvent.keycode
149cdf0e10cSrcweir             && same_screen == rEvent.same_screen;
150cdf0e10cSrcweir }
151cdf0e10cSrcweir 
152cdf0e10cSrcweir // -------------------------------------------------------------------------
153cdf0e10cSrcweir //
154cdf0e10cSrcweir // locale handling
155cdf0e10cSrcweir //
156cdf0e10cSrcweir // -------------------------------------------------------------------------
157cdf0e10cSrcweir 
158cdf0e10cSrcweir //  Locale handling of the operating system layer
159cdf0e10cSrcweir 
160cdf0e10cSrcweir static char*
SetSystemLocale(const char * p_inlocale)161cdf0e10cSrcweir SetSystemLocale( const char* p_inlocale )
162cdf0e10cSrcweir {
163cdf0e10cSrcweir 	char *p_outlocale;
164cdf0e10cSrcweir 
165cdf0e10cSrcweir 	if ( (p_outlocale = setlocale(LC_ALL, p_inlocale)) == NULL )
166cdf0e10cSrcweir 	{
167cdf0e10cSrcweir 		fprintf( stderr, "I18N: Operating system doesn't support locale \"%s\"\n",
168cdf0e10cSrcweir 			p_inlocale );
169cdf0e10cSrcweir 	}
170cdf0e10cSrcweir 
171cdf0e10cSrcweir 	return p_outlocale;
172cdf0e10cSrcweir }
173cdf0e10cSrcweir 
174cdf0e10cSrcweir #ifdef SOLARIS
175cdf0e10cSrcweir static void
SetSystemEnvironment(const rtl::OUString & rLocale)176cdf0e10cSrcweir SetSystemEnvironment( const rtl::OUString& rLocale )
177cdf0e10cSrcweir {
178cdf0e10cSrcweir     rtl::OUString LC_ALL_Var(RTL_CONSTASCII_USTRINGPARAM("LC_ALL"));
179cdf0e10cSrcweir     osl_setEnvironment(LC_ALL_Var.pData, rLocale.pData);
180cdf0e10cSrcweir 
181cdf0e10cSrcweir     rtl::OUString LANG_Var(RTL_CONSTASCII_USTRINGPARAM("LANG"));
182cdf0e10cSrcweir     osl_setEnvironment(LANG_Var.pData, rLocale.pData);
183cdf0e10cSrcweir }
184cdf0e10cSrcweir #endif
185cdf0e10cSrcweir 
186cdf0e10cSrcweir static Bool
IsPosixLocale(const char * p_locale)187cdf0e10cSrcweir IsPosixLocale( const char* p_locale )
188cdf0e10cSrcweir {
189cdf0e10cSrcweir 	if ( p_locale == NULL )
190cdf0e10cSrcweir 		return False;
191cdf0e10cSrcweir 	if ( (p_locale[ 0 ] == 'C') && (p_locale[ 1 ] == '\0') )
192cdf0e10cSrcweir 		return True;
193cdf0e10cSrcweir 	if ( strncmp(p_locale, "POSIX", sizeof("POSIX")) == 0 )
194cdf0e10cSrcweir 		return True;
195cdf0e10cSrcweir 
196cdf0e10cSrcweir 	return False;
197cdf0e10cSrcweir }
198cdf0e10cSrcweir 
199cdf0e10cSrcweir //  Locale handling of the X Window System layer
200cdf0e10cSrcweir 
201cdf0e10cSrcweir static Bool
IsXWindowCompatibleLocale(const char * p_locale)202cdf0e10cSrcweir IsXWindowCompatibleLocale( const char* p_locale )
203cdf0e10cSrcweir {
204cdf0e10cSrcweir 	if ( p_locale == NULL )
205cdf0e10cSrcweir 		return False;
206cdf0e10cSrcweir 
207cdf0e10cSrcweir 	if ( !XSupportsLocale() )
208cdf0e10cSrcweir 	{
209cdf0e10cSrcweir 		fprintf (stderr, "I18N: X Window System doesn't support locale \"%s\"\n",
210cdf0e10cSrcweir 				p_locale );
211cdf0e10cSrcweir 		return False;
212cdf0e10cSrcweir 	}
213cdf0e10cSrcweir 	return True;
214cdf0e10cSrcweir }
215cdf0e10cSrcweir 
216cdf0e10cSrcweir // Set the operating system locale prior to trying to open an
217cdf0e10cSrcweir // XIM InputMethod.
218cdf0e10cSrcweir // Handle the cases where the current locale is either not supported by the
219cdf0e10cSrcweir // operating system (LANG=gaga) or by the XWindow system (LANG=aa_ER@saaho)
220cdf0e10cSrcweir // by providing a fallback.
221cdf0e10cSrcweir // Upgrade "C" or "POSIX" to "en_US" locale to allow umlauts and accents
222cdf0e10cSrcweir // see i8988, i9188, i8930, i16318
223cdf0e10cSrcweir // on Solaris the environment needs to be set equivalent to the locale (#i37047#)
224cdf0e10cSrcweir 
225cdf0e10cSrcweir Bool
SetLocale(const char * pLocale)226cdf0e10cSrcweir SalI18N_InputMethod::SetLocale( const char* pLocale )
227cdf0e10cSrcweir {
228cdf0e10cSrcweir 	// check whether we want an Input Method engine, if we don't we
229cdf0e10cSrcweir 	// do not need to set the locale
230cdf0e10cSrcweir 	if ( mbUseable )
231cdf0e10cSrcweir 	{
232cdf0e10cSrcweir 		char *locale = SetSystemLocale( pLocale );
233cdf0e10cSrcweir 		if ( (!IsXWindowCompatibleLocale(locale)) || IsPosixLocale(locale) )
234cdf0e10cSrcweir 		{
235cdf0e10cSrcweir             osl_setThreadTextEncoding (RTL_TEXTENCODING_ISO_8859_1);
236cdf0e10cSrcweir             locale = SetSystemLocale( "en_US" );
237cdf0e10cSrcweir             #ifdef SOLARIS
238cdf0e10cSrcweir             SetSystemEnvironment( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en_US")) );
239cdf0e10cSrcweir             #endif
240cdf0e10cSrcweir 		    if (! IsXWindowCompatibleLocale(locale))
241cdf0e10cSrcweir             {
242cdf0e10cSrcweir 			    locale = SetSystemLocale( "C" );
243cdf0e10cSrcweir                 #ifdef SOLARIS
244cdf0e10cSrcweir                 SetSystemEnvironment( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("C")) );
245cdf0e10cSrcweir                 #endif
246cdf0e10cSrcweir 		        if (! IsXWindowCompatibleLocale(locale))
247cdf0e10cSrcweir 				    mbUseable = False;
248cdf0e10cSrcweir             }
249cdf0e10cSrcweir 		}
250cdf0e10cSrcweir 
251cdf0e10cSrcweir         // must not fail if mbUseable since XSupportsLocale() asserts success
252cdf0e10cSrcweir 		if ( mbUseable && XSetLocaleModifiers("") == NULL )
253cdf0e10cSrcweir 		{
254cdf0e10cSrcweir 			fprintf (stderr, "I18N: Can't set X modifiers for locale \"%s\"\n",
255cdf0e10cSrcweir 				locale);
256cdf0e10cSrcweir 			mbUseable = False;
257cdf0e10cSrcweir 		}
258cdf0e10cSrcweir 	}
259cdf0e10cSrcweir 
260cdf0e10cSrcweir 	return mbUseable;
261cdf0e10cSrcweir }
262cdf0e10cSrcweir 
263cdf0e10cSrcweir Bool
PosixLocale()264cdf0e10cSrcweir SalI18N_InputMethod::PosixLocale()
265cdf0e10cSrcweir {
266cdf0e10cSrcweir     if (mbMultiLingual)
267cdf0e10cSrcweir         return False;
268cdf0e10cSrcweir     if (maMethod)
269cdf0e10cSrcweir         return IsPosixLocale (XLocaleOfIM (maMethod));
270cdf0e10cSrcweir     return False;
271cdf0e10cSrcweir }
272cdf0e10cSrcweir 
273cdf0e10cSrcweir // ------------------------------------------------------------------------
274cdf0e10cSrcweir //
275cdf0e10cSrcweir // Constructor / Destructor / Initialisation
276cdf0e10cSrcweir //
277cdf0e10cSrcweir // ------------------------------------------------------------------------
278cdf0e10cSrcweir 
SalI18N_InputMethod()279cdf0e10cSrcweir SalI18N_InputMethod::SalI18N_InputMethod( ) : mbUseable( bUseInputMethodDefault ),
280cdf0e10cSrcweir 											  mbMultiLingual( False ),
281cdf0e10cSrcweir                                               maMethod( (XIM)NULL ),
282cdf0e10cSrcweir 								  			  mpStyles( (XIMStyles*)NULL )
283cdf0e10cSrcweir {
284cdf0e10cSrcweir 	const char *pUseInputMethod = getenv( "SAL_USEINPUTMETHOD" );
285cdf0e10cSrcweir 	if ( pUseInputMethod != NULL )
286cdf0e10cSrcweir 		mbUseable = pUseInputMethod[0] != '\0' ;
287cdf0e10cSrcweir }
288cdf0e10cSrcweir 
~SalI18N_InputMethod()289cdf0e10cSrcweir SalI18N_InputMethod::~SalI18N_InputMethod()
290cdf0e10cSrcweir {
291cdf0e10cSrcweir     ::vcl::I18NStatus::free();
292cdf0e10cSrcweir 	if ( mpStyles != NULL )
293cdf0e10cSrcweir 		XFree( mpStyles );
294cdf0e10cSrcweir 	if ( maMethod != NULL )
295cdf0e10cSrcweir 		XCloseIM ( maMethod );
296cdf0e10cSrcweir }
297cdf0e10cSrcweir 
298cdf0e10cSrcweir //
299cdf0e10cSrcweir // XXX
300cdf0e10cSrcweir // debug routine: lets have a look at the provided method styles
301cdf0e10cSrcweir //
302cdf0e10cSrcweir 
303cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
304cdf0e10cSrcweir 
305cdf0e10cSrcweir extern "C" char*
GetMethodName(XIMStyle nStyle,char * pBuf,int nBufSize)306cdf0e10cSrcweir GetMethodName( XIMStyle nStyle, char *pBuf, int nBufSize)
307cdf0e10cSrcweir {
308cdf0e10cSrcweir 	struct StyleName {
309cdf0e10cSrcweir 		const XIMStyle nStyle;
310cdf0e10cSrcweir 		const char    *pName;
311cdf0e10cSrcweir 		const int      nNameLen;
312cdf0e10cSrcweir 	};
313cdf0e10cSrcweir 
314cdf0e10cSrcweir 	StyleName *pDescPtr;
315cdf0e10cSrcweir 	static const StyleName pDescription[] = {
316cdf0e10cSrcweir 		{ XIMPreeditArea, 	   "PreeditArea ", 	   sizeof("PreeditArea ")	},
317cdf0e10cSrcweir 		{ XIMPreeditCallbacks, "PreeditCallbacks ",sizeof("PreeditCallbacks ")},
318cdf0e10cSrcweir 		{ XIMPreeditPosition,  "PreeditPosition ", sizeof("PreeditPosition ") },
319cdf0e10cSrcweir 		{ XIMPreeditNothing,   "PreeditNothing ",  sizeof("PreeditNothing ")  },
320cdf0e10cSrcweir 		{ XIMPreeditNone, 	   "PreeditNone ",	   sizeof("PreeditNone ")	},
321cdf0e10cSrcweir 		{ XIMStatusArea, 	   "StatusArea ",      sizeof("StatusArea ")	},
322cdf0e10cSrcweir 		{ XIMStatusCallbacks,  "StatusCallbacks ", sizeof("StatusCallbacks ") },
323cdf0e10cSrcweir 		{ XIMStatusNothing,    "StatusNothing ",   sizeof("StatusNothing ")	},
324cdf0e10cSrcweir 		{ XIMStatusNone, 	   "StatusNone ",      sizeof("StatusNone ")	},
325cdf0e10cSrcweir 		{ 0, "NULL", 0 }
326cdf0e10cSrcweir 	};
327cdf0e10cSrcweir 
328cdf0e10cSrcweir 	if ( nBufSize > 0 )
329cdf0e10cSrcweir 		pBuf[0] = '\0';
330cdf0e10cSrcweir 
331cdf0e10cSrcweir 	char *pBufPtr = pBuf;
332cdf0e10cSrcweir 	for ( pDescPtr = const_cast<StyleName*>(pDescription); pDescPtr->nStyle != 0; pDescPtr++ )
333cdf0e10cSrcweir 	{
334cdf0e10cSrcweir 		int nSize = pDescPtr->nNameLen - 1;
335cdf0e10cSrcweir 		if ( (nStyle & pDescPtr->nStyle) && (nBufSize > nSize) )
336cdf0e10cSrcweir 		{
337cdf0e10cSrcweir 			strncpy( pBufPtr, pDescPtr->pName, nSize + 1);
338cdf0e10cSrcweir 			pBufPtr  += nSize;
339cdf0e10cSrcweir 			nBufSize -= nSize;
340cdf0e10cSrcweir 		}
341cdf0e10cSrcweir 	}
342cdf0e10cSrcweir 
343cdf0e10cSrcweir 	return pBuf;
344cdf0e10cSrcweir }
345cdf0e10cSrcweir 
346cdf0e10cSrcweir extern "C" void
PrintInputStyle(XIMStyles * pStyle)347cdf0e10cSrcweir PrintInputStyle( XIMStyles *pStyle )
348cdf0e10cSrcweir {
349cdf0e10cSrcweir 	char pBuf[ 128 ];
350cdf0e10cSrcweir 	int  nBuf = sizeof( pBuf );
351cdf0e10cSrcweir 
352cdf0e10cSrcweir 	if ( pStyle == NULL )
353cdf0e10cSrcweir 		fprintf( stderr, "no input method styles\n");
354cdf0e10cSrcweir 	else
355cdf0e10cSrcweir 	for ( int nStyle = 0; nStyle < pStyle->count_styles; nStyle++ )
356cdf0e10cSrcweir 	{
357cdf0e10cSrcweir 		fprintf( stderr, "style #%i = %s\n", nStyle,
358cdf0e10cSrcweir 		  	GetMethodName(pStyle->supported_styles[nStyle], pBuf, nBuf) );
359cdf0e10cSrcweir 	}
360cdf0e10cSrcweir }
361cdf0e10cSrcweir 
362cdf0e10cSrcweir #endif
363cdf0e10cSrcweir 
364cdf0e10cSrcweir //
365cdf0e10cSrcweir // this is the real constructing routine, since locale setting has to be done
366cdf0e10cSrcweir // prior to xopendisplay, the xopenim call has to be delayed
367cdf0e10cSrcweir //
368cdf0e10cSrcweir 
369cdf0e10cSrcweir Bool
CreateMethod(Display * pDisplay)370cdf0e10cSrcweir SalI18N_InputMethod::CreateMethod ( Display *pDisplay )
371cdf0e10cSrcweir {
372cdf0e10cSrcweir 	if ( mbUseable )
373cdf0e10cSrcweir 	{
374cdf0e10cSrcweir         const bool bTryMultiLingual =
375cdf0e10cSrcweir         #ifdef LINUX
376cdf0e10cSrcweir                         false;
377cdf0e10cSrcweir         #else
378cdf0e10cSrcweir                         true;
379cdf0e10cSrcweir         #endif
380cdf0e10cSrcweir 		if ( bTryMultiLingual && getenv("USE_XOPENIM") == NULL )
381cdf0e10cSrcweir 		{
382cdf0e10cSrcweir 			mbMultiLingual = True; // set ml-input flag to create input-method
383cdf0e10cSrcweir 	    	maMethod = XvaOpenIM(pDisplay, NULL, NULL, NULL,
384cdf0e10cSrcweir 					XNMultiLingualInput, mbMultiLingual, /* dummy */
385cdf0e10cSrcweir 			 		(void *)0);
386cdf0e10cSrcweir 			// get ml-input flag from input-method
387cdf0e10cSrcweir 			if ( maMethod == (XIM)NULL )
388cdf0e10cSrcweir 				mbMultiLingual = False;
389cdf0e10cSrcweir 			else
390cdf0e10cSrcweir 			if ( XGetIMValues(maMethod,
391cdf0e10cSrcweir 					XNMultiLingualInput, &mbMultiLingual, NULL ) != NULL )
392cdf0e10cSrcweir 				mbMultiLingual = False;
393cdf0e10cSrcweir             if( mbMultiLingual )
394cdf0e10cSrcweir             {
395cdf0e10cSrcweir                 XIMUnicodeCharacterSubsets* subsets;
396cdf0e10cSrcweir                 if( XGetIMValues( maMethod,
397cdf0e10cSrcweir                                   XNQueryUnicodeCharacterSubset, &subsets, NULL ) == NULL )
398cdf0e10cSrcweir                 {
399cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
400cdf0e10cSrcweir                     fprintf( stderr, "IM reports %d subsets: ", subsets->count_subsets );
401cdf0e10cSrcweir #endif
402cdf0e10cSrcweir                     I18NStatus& rStatus( I18NStatus::get() );
403cdf0e10cSrcweir                     rStatus.clearChoices();
404cdf0e10cSrcweir                     for( int i = 0; i < subsets->count_subsets; i++ )
405cdf0e10cSrcweir                     {
406cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
407cdf0e10cSrcweir                         fprintf( stderr,"\"%s\" ", subsets->supported_subsets[i].name );
408cdf0e10cSrcweir #endif
409cdf0e10cSrcweir                         rStatus.addChoice( String( subsets->supported_subsets[i].name, RTL_TEXTENCODING_UTF8 ), &subsets->supported_subsets[i] );
410cdf0e10cSrcweir                     }
411cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
412cdf0e10cSrcweir                     fprintf( stderr, "\n" );
413cdf0e10cSrcweir #endif
414cdf0e10cSrcweir                 }
415cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
416cdf0e10cSrcweir                 else
417cdf0e10cSrcweir                     fprintf( stderr, "query subsets failed\n" );
418cdf0e10cSrcweir #endif
419cdf0e10cSrcweir             }
420cdf0e10cSrcweir 		}
421cdf0e10cSrcweir 		else
422cdf0e10cSrcweir 	    {
423cdf0e10cSrcweir 		    maMethod = XOpenIM(pDisplay, NULL, NULL, NULL);
424cdf0e10cSrcweir 			mbMultiLingual = False;
425cdf0e10cSrcweir         }
426cdf0e10cSrcweir 
427cdf0e10cSrcweir         if ((maMethod == (XIM)NULL) && (getenv("XMODIFIERS") != NULL))
428cdf0e10cSrcweir         {
429cdf0e10cSrcweir 				rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("XMODIFIERS"));
430cdf0e10cSrcweir 				osl_clearEnvironment(envVar.pData);
431cdf0e10cSrcweir                 XSetLocaleModifiers("");
432cdf0e10cSrcweir                 maMethod = XOpenIM(pDisplay, NULL, NULL, NULL);
433cdf0e10cSrcweir 			    mbMultiLingual = False;
434cdf0e10cSrcweir         }
435cdf0e10cSrcweir 
436cdf0e10cSrcweir 		if ( maMethod != (XIM)NULL )
437cdf0e10cSrcweir 		{
438cdf0e10cSrcweir 			if (   XGetIMValues(maMethod, XNQueryInputStyle, &mpStyles, NULL)
439cdf0e10cSrcweir 				!= NULL)
440cdf0e10cSrcweir 				mbUseable = False;
441cdf0e10cSrcweir             #if OSL_DEBUG_LEVEL > 1
442cdf0e10cSrcweir 			fprintf(stderr, "Creating %s-Lingual InputMethod\n",
443cdf0e10cSrcweir 				mbMultiLingual ? "Multi" : "Mono" );
444cdf0e10cSrcweir 			PrintInputStyle( mpStyles );
445cdf0e10cSrcweir 			#endif
446cdf0e10cSrcweir 		}
447cdf0e10cSrcweir 		else
448cdf0e10cSrcweir 		{
449cdf0e10cSrcweir 			mbUseable = False;
450cdf0e10cSrcweir 		}
451cdf0e10cSrcweir 	}
452cdf0e10cSrcweir 
453cdf0e10cSrcweir     #if OSL_DEBUG_LEVEL > 1
454cdf0e10cSrcweir 	if ( !mbUseable )
455cdf0e10cSrcweir 		fprintf(stderr, "input method creation failed\n");
456cdf0e10cSrcweir 	#endif
457cdf0e10cSrcweir 
458cdf0e10cSrcweir     maDestroyCallback.callback	  = (XIMProc)IM_IMDestroyCallback;
459cdf0e10cSrcweir 	maDestroyCallback.client_data = (XPointer)this;
460cdf0e10cSrcweir     if (mbUseable && maMethod != NULL)
461cdf0e10cSrcweir         XSetIMValues(maMethod, XNDestroyCallback, &maDestroyCallback, NULL);
462cdf0e10cSrcweir 
463cdf0e10cSrcweir 	return mbUseable;
464cdf0e10cSrcweir }
465cdf0e10cSrcweir 
466cdf0e10cSrcweir //
467cdf0e10cSrcweir // give IM the opportunity to look at the event, and possibly hide it
468cdf0e10cSrcweir //
469cdf0e10cSrcweir 
470cdf0e10cSrcweir Bool
FilterEvent(XEvent * pEvent,XLIB_Window window)471cdf0e10cSrcweir SalI18N_InputMethod::FilterEvent( XEvent *pEvent, XLIB_Window window	)
472cdf0e10cSrcweir {
473cdf0e10cSrcweir 	if (!mbUseable)
474cdf0e10cSrcweir         return False;
475cdf0e10cSrcweir 
476cdf0e10cSrcweir     Bool bFilterEvent = XFilterEvent (pEvent, window);
477cdf0e10cSrcweir 
478cdf0e10cSrcweir     if (pEvent->type != XLIB_KeyPress && pEvent->type != KeyRelease)
479cdf0e10cSrcweir         return bFilterEvent;
480cdf0e10cSrcweir 
481cdf0e10cSrcweir     /*
482cdf0e10cSrcweir      * fix broken key release handling of some IMs
483cdf0e10cSrcweir      */
484cdf0e10cSrcweir     XKeyEvent*         pKeyEvent = &(pEvent->xkey);
485cdf0e10cSrcweir     static XKeyEventOp maLastKeyPress;
486cdf0e10cSrcweir 
487cdf0e10cSrcweir     if (bFilterEvent)
488cdf0e10cSrcweir     {
489cdf0e10cSrcweir         if (pKeyEvent->type == KeyRelease)
490cdf0e10cSrcweir             bFilterEvent = !maLastKeyPress.match (*pKeyEvent);
491cdf0e10cSrcweir         maLastKeyPress.erase();
492cdf0e10cSrcweir     }
493cdf0e10cSrcweir     else /* (!bFilterEvent) */
494cdf0e10cSrcweir     {
495cdf0e10cSrcweir         if (pKeyEvent->type == XLIB_KeyPress)
496cdf0e10cSrcweir             maLastKeyPress = *pKeyEvent;
497cdf0e10cSrcweir         else
498cdf0e10cSrcweir             maLastKeyPress.erase();
499cdf0e10cSrcweir     }
500cdf0e10cSrcweir 
501cdf0e10cSrcweir     return bFilterEvent;
502cdf0e10cSrcweir }
503cdf0e10cSrcweir 
504cdf0e10cSrcweir void
HandleDestroyIM()505cdf0e10cSrcweir SalI18N_InputMethod::HandleDestroyIM()
506cdf0e10cSrcweir {
507cdf0e10cSrcweir     mbUseable       = False;
508cdf0e10cSrcweir     mbMultiLingual  = False;
509cdf0e10cSrcweir     maMethod        = NULL;
510cdf0e10cSrcweir }
511cdf0e10cSrcweir 
512cdf0e10cSrcweir // ------------------------------------------------------------------------
513cdf0e10cSrcweir //
514cdf0e10cSrcweir // add a connection watch into the SalXLib yieldTable to allow iiimp
515cdf0e10cSrcweir // connection processing: soffice waits in select() not in XNextEvent(), so
516cdf0e10cSrcweir // there may be requests pending on the iiimp internal connection that will
517cdf0e10cSrcweir // not be processed until XNextEvent is called the next time. If we do not
518cdf0e10cSrcweir // have the focus because the atok12 lookup choice aux window has it we stay
519cdf0e10cSrcweir // deaf and dump otherwise.
520cdf0e10cSrcweir //
521cdf0e10cSrcweir // ------------------------------------------------------------------------
522cdf0e10cSrcweir 
523cdf0e10cSrcweir int
InputMethod_HasPendingEvent(int nFileDescriptor,void * pData)524cdf0e10cSrcweir InputMethod_HasPendingEvent(int nFileDescriptor, void *pData)
525cdf0e10cSrcweir {
526cdf0e10cSrcweir 	if (pData == NULL)
527cdf0e10cSrcweir 		return 0;
528cdf0e10cSrcweir 
529cdf0e10cSrcweir 	struct pollfd aFileDescriptor;
530cdf0e10cSrcweir 	#ifdef SOLARIS
531cdf0e10cSrcweir 	nfds_t 		  nNumDescriptor = 1;
532cdf0e10cSrcweir 	#else
533cdf0e10cSrcweir 	unsigned int	  nNumDescriptor = 1;
534cdf0e10cSrcweir 	#endif
535cdf0e10cSrcweir 	aFileDescriptor.fd      = nFileDescriptor;
536cdf0e10cSrcweir 	aFileDescriptor.events  = POLLRDNORM;
537cdf0e10cSrcweir 	aFileDescriptor.revents = 0;
538cdf0e10cSrcweir 
539cdf0e10cSrcweir 	int nPoll = poll (&aFileDescriptor, nNumDescriptor, 0 /* timeout */ );
540cdf0e10cSrcweir 
541cdf0e10cSrcweir 	if (nPoll > 0)
542cdf0e10cSrcweir 	{
543cdf0e10cSrcweir 		/* at least some conditions in revent are set */
544cdf0e10cSrcweir 		if (   (aFileDescriptor.revents & POLLHUP)
545cdf0e10cSrcweir 			|| (aFileDescriptor.revents & POLLERR)
546cdf0e10cSrcweir 			|| (aFileDescriptor.revents & POLLNVAL))
547cdf0e10cSrcweir 			return 0; /* oops error condition set */
548cdf0e10cSrcweir 
549cdf0e10cSrcweir 		if (aFileDescriptor.revents & POLLRDNORM)
550cdf0e10cSrcweir 			return 1; /* success */
551cdf0e10cSrcweir 	}
552cdf0e10cSrcweir 
553cdf0e10cSrcweir 	/* nPoll == 0 means timeout, nPoll < 0 means error */
554cdf0e10cSrcweir 	return 0;
555cdf0e10cSrcweir }
556cdf0e10cSrcweir 
557cdf0e10cSrcweir int
InputMethod_IsEventQueued(int nFileDescriptor,void * pData)558cdf0e10cSrcweir InputMethod_IsEventQueued(int nFileDescriptor, void *pData)
559cdf0e10cSrcweir {
560cdf0e10cSrcweir 	return InputMethod_HasPendingEvent (nFileDescriptor, pData);
561cdf0e10cSrcweir }
562cdf0e10cSrcweir 
563cdf0e10cSrcweir int
InputMethod_HandleNextEvent(int nFileDescriptor,void * pData)564cdf0e10cSrcweir InputMethod_HandleNextEvent(int nFileDescriptor, void *pData)
565cdf0e10cSrcweir {
566cdf0e10cSrcweir 	if (pData != NULL)
567cdf0e10cSrcweir 		XProcessInternalConnection((Display*)pData, nFileDescriptor);
568cdf0e10cSrcweir 
569cdf0e10cSrcweir 	return 0;
570cdf0e10cSrcweir }
571cdf0e10cSrcweir 
572cdf0e10cSrcweir extern "C" void
InputMethod_ConnectionWatchProc(Display * pDisplay,XPointer pClientData,int nFileDescriptor,Bool bOpening,XPointer *)573cdf0e10cSrcweir InputMethod_ConnectionWatchProc (Display *pDisplay, XPointer pClientData,
574cdf0e10cSrcweir 	int nFileDescriptor, Bool bOpening, XPointer*)
575cdf0e10cSrcweir {
576cdf0e10cSrcweir 	SalXLib *pConnectionHandler = (SalXLib*)pClientData;
577cdf0e10cSrcweir 
578cdf0e10cSrcweir 	if (pConnectionHandler == NULL)
579cdf0e10cSrcweir 		return;
580cdf0e10cSrcweir 
581cdf0e10cSrcweir 	if (bOpening)
582cdf0e10cSrcweir 	{
583cdf0e10cSrcweir 		pConnectionHandler->Insert (nFileDescriptor, pDisplay,
584cdf0e10cSrcweir 									InputMethod_HasPendingEvent,
585cdf0e10cSrcweir 									InputMethod_IsEventQueued,
586cdf0e10cSrcweir 									InputMethod_HandleNextEvent);
587cdf0e10cSrcweir 	}
588cdf0e10cSrcweir 	else
589cdf0e10cSrcweir 	{
590cdf0e10cSrcweir 		pConnectionHandler->Remove (nFileDescriptor);
591cdf0e10cSrcweir 	}
592cdf0e10cSrcweir }
593cdf0e10cSrcweir 
594cdf0e10cSrcweir Bool
AddConnectionWatch(Display * pDisplay,void * pConnectionHandler)595cdf0e10cSrcweir SalI18N_InputMethod::AddConnectionWatch(Display *pDisplay, void *pConnectionHandler)
596cdf0e10cSrcweir {
597cdf0e10cSrcweir 	// sanity check
598cdf0e10cSrcweir 	if (pDisplay == NULL || pConnectionHandler == NULL)
599cdf0e10cSrcweir 		return False;
600cdf0e10cSrcweir 
601cdf0e10cSrcweir 	// if we are not ml all the extended text input comes on the stock X queue,
602cdf0e10cSrcweir 	// so there is no need to monitor additional file descriptors.
603cdf0e10cSrcweir #ifndef SOLARIS
604cdf0e10cSrcweir  	if (!mbMultiLingual || !mbUseable)
605cdf0e10cSrcweir  		return False;
606cdf0e10cSrcweir #endif
607cdf0e10cSrcweir 
608cdf0e10cSrcweir 	// pConnectionHandler must be really a pointer to a SalXLib
609cdf0e10cSrcweir 	Status nStatus = XAddConnectionWatch (pDisplay, InputMethod_ConnectionWatchProc,
610cdf0e10cSrcweir 										  (XPointer)pConnectionHandler);
611cdf0e10cSrcweir 	return (Bool)nStatus;
612cdf0e10cSrcweir }
613cdf0e10cSrcweir 
614cdf0e10cSrcweir 
615cdf0e10cSrcweir 
616