LCOV - code coverage report
Current view: top level - vcl/unx/generic/app - i18n_im.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 0 124 0.0 %
Date: 2015-06-13 12:38:46 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          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             : #include <string.h>
      22             : 
      23             : #ifdef LINUX
      24             : #  ifndef __USE_XOPEN
      25             : #    define __USE_XOPEN
      26             : #  endif
      27             : #endif
      28             : #include <poll.h>
      29             : 
      30             : #include <prex.h>
      31             : #include <X11/Xlocale.h>
      32             : #include <X11/Xlib.h>
      33             : #include <unx/XIM.h>
      34             : #include <postx.h>
      35             : 
      36             : #include "unx/salunx.h"
      37             : #include "unx/saldisp.hxx"
      38             : #include "unx/i18n_im.hxx"
      39             : #include "unx/i18n_status.hxx"
      40             : 
      41             : #include <osl/thread.h>
      42             : #include <osl/process.h>
      43             : 
      44             : #include "unx/i18n_cb.hxx"
      45             : 
      46             : using namespace vcl;
      47             : 
      48             : // kinput2 IME needs special key handling since key release events are filtered in
      49             : // preeditmode and XmbResetIC does not work
      50             : 
      51             : class XKeyEventOp : XKeyEvent
      52             : {
      53             :     private:
      54             :         void            init();
      55             : 
      56             :     public:
      57             :                         XKeyEventOp();
      58             :                         ~XKeyEventOp();
      59             : 
      60             :         XKeyEventOp&    operator= (const XKeyEvent &rEvent);
      61             :         void            erase ();
      62             :         bool            match (const XKeyEvent &rEvent) const;
      63             : };
      64             : 
      65             : void
      66           0 : XKeyEventOp::init()
      67             : {
      68           0 :     type        = 0; /* serial = 0; */
      69           0 :     send_event  = 0; display   = 0;
      70           0 :     window      = 0; root      = 0;
      71           0 :     subwindow   = 0; /* time   = 0; */
      72             :  /* x           = 0; y         = 0; */
      73             :  /* x_root      = 0; y_root    = 0; */
      74           0 :     state       = 0; keycode   = 0;
      75           0 :     same_screen = 0;
      76           0 : }
      77             : 
      78           0 : XKeyEventOp::XKeyEventOp()
      79             : {
      80           0 :     init();
      81           0 : }
      82             : 
      83           0 : XKeyEventOp::~XKeyEventOp()
      84             : {
      85           0 : }
      86             : 
      87             : XKeyEventOp&
      88           0 : XKeyEventOp::operator= (const XKeyEvent &rEvent)
      89             : {
      90           0 :     type        = rEvent.type;     /* serial  = rEvent.serial; */
      91           0 :     send_event  = rEvent.send_event;  display = rEvent.display;
      92           0 :     window      = rEvent.window;      root    = rEvent.root;
      93           0 :     subwindow   = rEvent.subwindow;/* time    = rEvent.time;   */
      94             :  /* x           = rEvent.x,           y       = rEvent.y;      */
      95             :  /* x_root      = rEvent.x_root,      y_root  = rEvent.y_root; */
      96           0 :     state       = rEvent.state;       keycode = rEvent.keycode;
      97           0 :     same_screen = rEvent.same_screen;
      98             : 
      99           0 :     return *this;
     100             : }
     101             : 
     102             : void
     103           0 : XKeyEventOp::erase ()
     104             : {
     105           0 :     init();
     106           0 : }
     107             : 
     108             : bool
     109           0 : XKeyEventOp::match (const XKeyEvent &rEvent) const
     110             : {
     111           0 :     return (   (type == KeyPress   && rEvent.type == KeyRelease)
     112           0 :             || (type == KeyRelease && rEvent.type == KeyPress  ))
     113             :          /* && serial      == rEvent.serial */
     114           0 :             && send_event  == rEvent.send_event
     115           0 :             && display     == rEvent.display
     116           0 :             && window      == rEvent.window
     117           0 :             && root        == rEvent.root
     118           0 :             && subwindow   == rEvent.subwindow
     119             :          /* && time        == rEvent.time
     120             :             && x           == rEvent.x
     121             :             && y           == rEvent.y
     122             :             && x_root      == rEvent.x_root
     123             :             && y_root      == rEvent.y_root */
     124           0 :             && state       == rEvent.state
     125           0 :             && keycode     == rEvent.keycode
     126           0 :             && same_screen == rEvent.same_screen;
     127             : }
     128             : 
     129             : // locale handling
     130             : 
     131             : //  Locale handling of the operating system layer
     132             : 
     133             : static char*
     134           0 : SetSystemLocale( const char* p_inlocale )
     135             : {
     136             :     char *p_outlocale;
     137             : 
     138           0 :     if ( (p_outlocale = setlocale(LC_ALL, p_inlocale)) == NULL )
     139             :     {
     140             :         fprintf( stderr, "I18N: Operating system doesn't support locale \"%s\"\n",
     141           0 :             p_inlocale );
     142             :     }
     143             : 
     144           0 :     return p_outlocale;
     145             : }
     146             : 
     147             : #ifdef SOLARIS
     148             : static void
     149             : SetSystemEnvironment( const OUString& rLocale )
     150             : {
     151             :     OUString LC_ALL_Var("LC_ALL");
     152             :     osl_setEnvironment(LC_ALL_Var.pData, rLocale.pData);
     153             : 
     154             :     OUString LANG_Var("LANG");
     155             :     osl_setEnvironment(LANG_Var.pData, rLocale.pData);
     156             : }
     157             : #endif
     158             : 
     159             : static Bool
     160           0 : IsPosixLocale( const char* p_locale )
     161             : {
     162           0 :     if ( p_locale == NULL )
     163           0 :         return False;
     164           0 :     if ( (p_locale[ 0 ] == 'C') && (p_locale[ 1 ] == '\0') )
     165           0 :         return True;
     166           0 :     if ( strncmp(p_locale, "POSIX", sizeof("POSIX")) == 0 )
     167           0 :         return True;
     168             : 
     169           0 :     return False;
     170             : }
     171             : 
     172             : //  Locale handling of the X Window System layer
     173             : 
     174             : static Bool
     175           0 : IsXWindowCompatibleLocale( const char* p_locale )
     176             : {
     177           0 :     if ( p_locale == NULL )
     178           0 :         return False;
     179             : 
     180           0 :     if ( !XSupportsLocale() )
     181             :     {
     182             :         fprintf (stderr, "I18N: X Window System doesn't support locale \"%s\"\n",
     183           0 :                 p_locale );
     184           0 :         return False;
     185             :     }
     186           0 :     return True;
     187             : }
     188             : 
     189             : // Set the operating system locale prior to trying to open an
     190             : // XIM InputMethod.
     191             : // Handle the cases where the current locale is either not supported by the
     192             : // operating system (LANG=gaga) or by the XWindow system (LANG=aa_ER@saaho)
     193             : // by providing a fallback.
     194             : // Upgrade "C" or "POSIX" to "en_US" locale to allow umlauts and accents
     195             : // see i8988, i9188, i8930, i16318
     196             : // on Solaris the environment needs to be set equivalent to the locale (#i37047#)
     197             : 
     198             : bool
     199           0 : SalI18N_InputMethod::SetLocale( const char* pLocale )
     200             : {
     201             :     // check whether we want an Input Method engine, if we don't we
     202             :     // do not need to set the locale
     203           0 :     if ( mbUseable )
     204             :     {
     205           0 :         char *locale = SetSystemLocale( pLocale );
     206           0 :         if ( (!IsXWindowCompatibleLocale(locale)) || IsPosixLocale(locale) )
     207             :         {
     208           0 :             osl_setThreadTextEncoding (RTL_TEXTENCODING_ISO_8859_1);
     209           0 :             locale = SetSystemLocale( "en_US" );
     210             :             #ifdef SOLARIS
     211             :             SetSystemEnvironment( "en_US" );
     212             :             #endif
     213           0 :             if (! IsXWindowCompatibleLocale(locale))
     214             :             {
     215           0 :                 locale = SetSystemLocale( "C" );
     216             :                 #ifdef SOLARIS
     217             :                 SetSystemEnvironment( "C" );
     218             :                 #endif
     219           0 :                 if (! IsXWindowCompatibleLocale(locale))
     220           0 :                     mbUseable = False;
     221             :             }
     222             :         }
     223             : 
     224             :         // must not fail if mbUseable since XSupportsLocale() asserts success
     225           0 :         if ( mbUseable && XSetLocaleModifiers("") == NULL )
     226             :         {
     227             :             fprintf (stderr, "I18N: Can't set X modifiers for locale \"%s\"\n",
     228           0 :                 locale);
     229           0 :             mbUseable = False;
     230             :         }
     231             :     }
     232             : 
     233           0 :     return mbUseable;
     234             : }
     235             : 
     236             : Bool
     237           0 : SalI18N_InputMethod::PosixLocale()
     238             : {
     239           0 :     if (maMethod)
     240           0 :         return IsPosixLocale (XLocaleOfIM (maMethod));
     241           0 :     return False;
     242             : }
     243             : 
     244             : // Constructor / Destructor / Initialisation
     245             : 
     246           0 : SalI18N_InputMethod::SalI18N_InputMethod( )
     247             :     : mbUseable( bUseInputMethodDefault )
     248             :     , maMethod( nullptr )
     249           0 :     , mpStyles( nullptr )
     250             : {
     251           0 :     maDestroyCallback.callback = nullptr;
     252           0 :     maDestroyCallback.client_data = nullptr;
     253           0 :     const char *pUseInputMethod = getenv( "SAL_USEINPUTMETHOD" );
     254           0 :     if ( pUseInputMethod != NULL )
     255           0 :         mbUseable = pUseInputMethod[0] != '\0' ;
     256           0 : }
     257             : 
     258           0 : SalI18N_InputMethod::~SalI18N_InputMethod()
     259             : {
     260           0 :     vcl::I18NStatus::free();
     261           0 :     if ( mpStyles != NULL )
     262           0 :         XFree( mpStyles );
     263           0 :     if ( maMethod != NULL )
     264           0 :         XCloseIM ( maMethod );
     265           0 : }
     266             : 
     267             : // XXX
     268             : // debug routine: lets have a look at the provided method styles
     269             : 
     270             : #if OSL_DEBUG_LEVEL > 1
     271             : 
     272             : extern "C" char*
     273             : GetMethodName( XIMStyle nStyle, char *pBuf, int nBufSize)
     274             : {
     275             :     struct StyleName {
     276             :         const XIMStyle nStyle;
     277             :         const char    *pName;
     278             :         const int      nNameLen;
     279             :     };
     280             : 
     281             :     StyleName *pDescPtr;
     282             :     static const StyleName pDescription[] = {
     283             :         { XIMPreeditArea,      "PreeditArea ",     sizeof("PreeditArea ")   },
     284             :         { XIMPreeditCallbacks, "PreeditCallbacks ",sizeof("PreeditCallbacks ")},
     285             :         { XIMPreeditPosition,  "PreeditPosition ", sizeof("PreeditPosition ") },
     286             :         { XIMPreeditNothing,   "PreeditNothing ",  sizeof("PreeditNothing ")  },
     287             :         { XIMPreeditNone,      "PreeditNone ",     sizeof("PreeditNone ")   },
     288             :         { XIMStatusArea,       "StatusArea ",      sizeof("StatusArea ")    },
     289             :         { XIMStatusCallbacks,  "StatusCallbacks ", sizeof("StatusCallbacks ") },
     290             :         { XIMStatusNothing,    "StatusNothing ",   sizeof("StatusNothing ") },
     291             :         { XIMStatusNone,       "StatusNone ",      sizeof("StatusNone ")    },
     292             :         { 0, "NULL", 0 }
     293             :     };
     294             : 
     295             :     if ( nBufSize > 0 )
     296             :         pBuf[0] = '\0';
     297             : 
     298             :     char *pBufPtr = pBuf;
     299             :     for ( pDescPtr = const_cast<StyleName*>(pDescription); pDescPtr->nStyle != 0; pDescPtr++ )
     300             :     {
     301             :         int nSize = pDescPtr->nNameLen - 1;
     302             :         if ( (nStyle & pDescPtr->nStyle) && (nBufSize > nSize) )
     303             :         {
     304             :             strncpy( pBufPtr, pDescPtr->pName, nSize + 1);
     305             :             pBufPtr  += nSize;
     306             :             nBufSize -= nSize;
     307             :         }
     308             :     }
     309             : 
     310             :     return pBuf;
     311             : }
     312             : 
     313             : extern "C" void
     314             : PrintInputStyle( XIMStyles *pStyle )
     315             : {
     316             :     char pBuf[ 128 ];
     317             :     int  nBuf = sizeof( pBuf );
     318             : 
     319             :     if ( pStyle == NULL )
     320             :         fprintf( stderr, "no input method styles\n");
     321             :     else
     322             :     for ( int nStyle = 0; nStyle < pStyle->count_styles; nStyle++ )
     323             :     {
     324             :         fprintf( stderr, "style #%i = %s\n", nStyle,
     325             :               GetMethodName(pStyle->supported_styles[nStyle], pBuf, nBuf) );
     326             :     }
     327             : }
     328             : 
     329             : #endif
     330             : 
     331             : // this is the real constructing routine, since locale setting has to be done
     332             : // prior to xopendisplay, the xopenim call has to be delayed
     333             : 
     334             : bool
     335           0 : SalI18N_InputMethod::CreateMethod ( Display *pDisplay )
     336             : {
     337           0 :     if ( mbUseable )
     338             :     {
     339           0 :         maMethod = XOpenIM(pDisplay, NULL, NULL, NULL);
     340             : 
     341           0 :         if ((maMethod == nullptr) && (getenv("XMODIFIERS") != NULL))
     342             :         {
     343           0 :                 OUString envVar("XMODIFIERS");
     344           0 :                 osl_clearEnvironment(envVar.pData);
     345           0 :                 XSetLocaleModifiers("");
     346           0 :                 maMethod = XOpenIM(pDisplay, NULL, NULL, NULL);
     347             :         }
     348             : 
     349           0 :         if ( maMethod != nullptr )
     350             :         {
     351           0 :             if (   XGetIMValues(maMethod, XNQueryInputStyle, &mpStyles, NULL)
     352             :                 != NULL)
     353           0 :                 mbUseable = False;
     354             :             #if OSL_DEBUG_LEVEL > 1
     355             :             fprintf(stderr, "Creating Mono-Lingual InputMethod\n" );
     356             :             PrintInputStyle( mpStyles );
     357             :             #endif
     358             :         }
     359             :         else
     360             :         {
     361           0 :             mbUseable = False;
     362             :         }
     363             :     }
     364             : 
     365             :     #if OSL_DEBUG_LEVEL > 1
     366             :     if ( !mbUseable )
     367             :         fprintf(stderr, "input method creation failed\n");
     368             :     #endif
     369             : 
     370           0 :     maDestroyCallback.callback    = static_cast<XIMProc>(IM_IMDestroyCallback);
     371           0 :     maDestroyCallback.client_data = reinterpret_cast<XPointer>(this);
     372           0 :     if (mbUseable && maMethod != NULL)
     373           0 :         XSetIMValues(maMethod, XNDestroyCallback, &maDestroyCallback, NULL);
     374             : 
     375           0 :     return mbUseable;
     376             : }
     377             : 
     378             : // give IM the opportunity to look at the event, and possibly hide it
     379             : 
     380             : bool
     381           0 : SalI18N_InputMethod::FilterEvent( XEvent *pEvent, ::Window window    )
     382             : {
     383           0 :     if (!mbUseable)
     384           0 :         return False;
     385             : 
     386           0 :     bool bFilterEvent = XFilterEvent (pEvent, window);
     387             : 
     388           0 :     if (pEvent->type != KeyPress && pEvent->type != KeyRelease)
     389           0 :         return bFilterEvent;
     390             : 
     391             :     /*
     392             :      * fix broken key release handling of some IMs
     393             :      */
     394           0 :     XKeyEvent*         pKeyEvent = &(pEvent->xkey);
     395           0 :     static XKeyEventOp maLastKeyPress;
     396             : 
     397           0 :     if (bFilterEvent)
     398             :     {
     399           0 :         if (pKeyEvent->type == KeyRelease)
     400           0 :             bFilterEvent = !maLastKeyPress.match (*pKeyEvent);
     401           0 :         maLastKeyPress.erase();
     402             :     }
     403             :     else /* (!bFilterEvent) */
     404             :     {
     405           0 :         if (pKeyEvent->type == KeyPress)
     406           0 :             maLastKeyPress = *pKeyEvent;
     407             :         else
     408           0 :             maLastKeyPress.erase();
     409             :     }
     410             : 
     411           0 :     return bFilterEvent;
     412             : }
     413             : 
     414             : void
     415           0 : SalI18N_InputMethod::HandleDestroyIM()
     416             : {
     417           0 :     mbUseable       = False;
     418           0 :     maMethod        = NULL;
     419           0 : }
     420             : 
     421             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11