summaryrefslogtreecommitdiff
path: root/vcl/unx/source/app/i18n_ic.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/source/app/i18n_ic.cxx')
-rw-r--r--vcl/unx/source/app/i18n_ic.cxx686
1 files changed, 686 insertions, 0 deletions
diff --git a/vcl/unx/source/app/i18n_ic.cxx b/vcl/unx/source/app/i18n_ic.cxx
new file mode 100644
index 000000000000..4e2f34b77d22
--- /dev/null
+++ b/vcl/unx/source/app/i18n_ic.cxx
@@ -0,0 +1,686 @@
+/*************************************************************************
+ *
+ * $RCSfile: i18n_ic.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 17:05:42 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <stdio.h>
+#include <alloca.h>
+
+#include <prex.h>
+#include <X11/Xlocale.h>
+#include <X11/Xlib.h>
+#include <postx.h>
+
+#include <salunx.h>
+
+#include <XIM.h>
+
+#ifndef _SAL_I18N_INPUTCONTEXT_HXX
+#include "i18n_ic.hxx"
+#endif
+#ifndef _SAL_I18N_INPUTMETHOD_HXX
+#include "i18n_im.hxx"
+#endif
+#ifndef _SV_SALFRAME_HXX
+#include <salframe.hxx>
+#endif
+#ifndef _SV_SALDISP_HXX
+#include <saldisp.hxx>
+#endif
+
+// ---------------------------------------------------------------------------
+//
+// Constructor / Destructor, the InputContext is bound to the SalFrame, as it
+// needs the shell window as a focus window
+//
+// ----------------------------------------------------------------------------
+
+SalI18N_InputContext::~SalI18N_InputContext()
+{
+ if ( maContext != NULL )
+ XDestroyIC( maContext );
+ if ( mpAttributes != NULL )
+ XFree( mpAttributes );
+ if ( mpStatusAttributes != NULL )
+ XFree( mpStatusAttributes );
+ if ( mpPreeditAttributes != NULL )
+ XFree( mpPreeditAttributes );
+ #ifdef SOLARIS
+ if ( mpFontSet != NULL )
+ XFreeFontSet( mpDisplay, mpFontSet );
+ #endif
+}
+
+#ifdef DEBUG
+
+// ----------------------------------------------------------------------------
+// debug routines, that keep track of fonts we've chosen in a fontset
+// ----------------------------------------------------------------------------
+
+// report which fonts are missing for the requested
+// basefont and which fonts are actually selected
+
+static void
+v_print_missing_fonts( char **pp_list, int n_listsz, const char *p_pattern )
+{
+ if ( !(n_listsz > 0) || (pp_list == NULL) || (p_pattern == NULL) )
+ return;
+
+ for (int i = 0; i < n_listsz; i++ )
+ fprintf(stderr, "missing charset@%s:\"%s\"\n", p_pattern, pp_list[i] );
+}
+
+static void
+v_print_chosen_fonts( XFontSet a_fontset )
+{
+ if ( a_fontset == 0 )
+ return;
+
+ char *p_locale_name;
+ XFontStruct **pp_font_struct_list;
+ char **pp_font_name_list;
+ int n_listsz;
+
+ p_locale_name = XLocaleOfFontSet( a_fontset );
+ n_listsz = XFontsOfFontSet( a_fontset,
+ &pp_font_struct_list,
+ &pp_font_name_list );
+ for ( int i = 0; i < n_listsz; i++ )
+ {
+ fprintf( stderr, "font@%s:\"%s\"\n",
+ p_locale_name, pp_font_name_list[i] );
+ }
+}
+
+#endif // DEBUG
+
+// Wrapper for XCreateFontSet to create a default font set
+static XFontSet
+p_create_fontset( Display *p_display )
+{
+ // a fontset, as there is no valid default for russian and all other
+ // eastern european locales in solaris 8
+ const char *p_base_font[] = {
+ "-*-application-medium-r-*-sans-12-*",
+ "-*-application-*-r-*-*-12-*",
+ "-*-*-*-r-*-*-12-*",
+ "-*" };
+ char **pp_missing_charset_list = NULL;
+ int n_missing_charset_count = 0;
+ char *p_def_string = NULL;
+
+ XFontSet a_fontset;
+
+ for (int i = 0; i < (sizeof(p_base_font) / sizeof(char*)); i++ )
+ {
+ a_fontset = XCreateFontSet( p_display, p_base_font[i],
+ &pp_missing_charset_list,
+ &n_missing_charset_count, &p_def_string);
+ #ifdef DEBUG
+ v_print_missing_fonts ( pp_missing_charset_list,
+ n_missing_charset_count, p_base_font[i] );
+ #endif
+
+ if ( a_fontset != 0 )
+ break;
+ }
+
+ #ifdef DEBUG
+ v_print_chosen_fonts( a_fontset );
+ #endif
+
+ return a_fontset;
+}
+
+// ----------------------------------------------------------------------------
+// convenience routine to add items to a XVaNestedList
+// ----------------------------------------------------------------------------
+
+static XVaNestedList
+XVaAddToNestedList( XVaNestedList a_srclist, char* name, XPointer value )
+{
+ XVaNestedList a_dstlist;
+
+ // if ( value == NULL )
+ // return a_srclist;
+
+ if ( a_srclist == NULL )
+ {
+ a_dstlist = XVaCreateNestedList(
+ 0,
+ name, value,
+ 0 );
+ }
+ else
+ {
+ a_dstlist = XVaCreateNestedList(
+ 0,
+ XNVaNestedList, a_srclist,
+ name, value,
+ 0 );
+ }
+
+ return a_dstlist != NULL ? a_dstlist : a_srclist ;
+}
+
+// ---------------------------------------------------------------------------
+//
+// Constructor for a InputContext (IC)
+//
+// ----------------------------------------------------------------------------
+
+SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) :
+ mbUseable( True ),
+ maContext( (XIC)NULL ),
+ mpAttributes( NULL ),
+ mpStatusAttributes( NULL ),
+ mpPreeditAttributes( NULL ),
+ #ifdef SOLARIS
+ mpFontSet( NULL ),
+ #endif
+ mnStatusStyle( 0 ),
+ mnPreeditStyle( 0 ),
+ mnSupportedPreeditStyle( XIMPreeditCallbacks |
+ XIMPreeditNothing | XIMPreeditNone
+ /* | XIMPreeditCallbacks
+ | XIMPreeditArea
+ | XIMPreeditPosition */ ),
+ mnSupportedStatusStyle( // XIMStatusCallbacks |
+ XIMStatusNothing | XIMStatusNone
+ /* | XIMStatusCallbacks
+ | XIMStatusArea */ )
+{
+ SalI18N_InputMethod *pInputMethod;
+ pInputMethod = pFrame->maFrameData.GetDisplay()->GetInputMethod();
+ mbMultiLingual = pInputMethod->IsMultiLingual();
+
+ if ( pInputMethod->UseMethod()
+ && SupportInputMethodStyle( pInputMethod->GetSupportedStyles() ) )
+ {
+ XLIB_Window aClientWindow= pFrame->maFrameData.GetShellWindow();
+ XLIB_Window aFocusWindow= pFrame->maFrameData.GetWindow();
+ Display *pDisplay = XDisplayOfIM( pInputMethod->GetMethod() );
+
+ // for status callbacks and commit string callbacks
+ maClientData.bIsMultilingual = mbMultiLingual;
+ maClientData.eState = ePreeditStatusStartPending;
+ maClientData.pFrame = pFrame;
+ maClientData.aText.pUnicodeBuffer = NULL;
+ maClientData.aText.pCharStyle = NULL;
+ maClientData.aText.nCursorPos = 0;
+ maClientData.aText.nLength = 0;
+ maClientData.aText.nSize = 0;
+
+ // set status attributes
+ // only none and nothing are supported which do not need special
+ // arguments, area and position are just hacks, preedit callback
+ // does work but cannot be connected without unicode/multibyte
+ // support of independent vcl layer
+
+ switch ( mnStatusStyle )
+ {
+ case XIMStatusArea:
+ {
+ XRectangle *pStatusArea = new XRectangle;
+ pStatusArea->x = 0;
+ pStatusArea->y = 64;
+ pStatusArea->width = 256;
+ pStatusArea->height = 64;
+
+ mpStatusAttributes = XVaCreateNestedList (
+ 0,
+ XNAreaNeeded, pStatusArea,
+ XNArea, pStatusArea,
+ 0 );
+
+ break;
+ }
+
+ case XIMStatusNone:
+ case XIMStatusNothing:
+ default:
+
+ break;
+ }
+
+ //
+ // set preedit attributes
+ //
+
+ switch ( mnPreeditStyle )
+ {
+ case XIMPreeditCallbacks:
+
+ maPreeditCaretCallback.callback = (XIMProc)PreeditCaretCallback;
+ maPreeditStartCallback.callback = (XIMProc)PreeditStartCallback;
+ maPreeditDoneCallback.callback = (XIMProc)PreeditDoneCallback;
+ maPreeditDrawCallback.callback = (XIMProc)PreeditDrawCallback;
+ maPreeditCaretCallback.client_data = (XPointer)&maClientData;
+ maPreeditStartCallback.client_data = (XPointer)&maClientData;
+ maPreeditDoneCallback.client_data = (XPointer)&maClientData;
+ maPreeditDrawCallback.client_data = (XPointer)&maClientData;
+
+ mpPreeditAttributes = XVaCreateNestedList (
+ 0,
+ XNPreeditStartCallback, &maPreeditStartCallback,
+ XNPreeditDoneCallback, &maPreeditDoneCallback,
+ XNPreeditDrawCallback, &maPreeditDrawCallback,
+ XNPreeditCaretCallback, &maPreeditCaretCallback,
+ 0 );
+
+ break;
+
+ case XIMPreeditPosition:
+ case XIMPreeditArea:
+ {
+ XRectangle *pPreeditArea = new XRectangle;
+ XPoint *pSpotLocation = new XPoint;
+
+ pSpotLocation->x = 16;
+ pSpotLocation->y = 32;
+
+ pPreeditArea->x = 0;
+ pPreeditArea->y = 0;
+ pPreeditArea->width = 256;
+ pPreeditArea->height = 64;
+
+ mpPreeditAttributes = XVaCreateNestedList (
+ 0,
+ XNArea, pPreeditArea,
+ XNSpotLocation, pSpotLocation,
+ 0 );
+
+ break;
+ }
+
+ case XIMPreeditNone:
+ case XIMPreeditNothing:
+ default:
+
+ break;
+ }
+
+ // Create the InputContext by given it exact the information it
+ // deserves, because inappropriate attributes
+ // let XCreateIC fail on Solaris (eg. for C locale)
+
+ mpAttributes = XVaCreateNestedList(
+ 0,
+ XNFocusWindow, aFocusWindow,
+ XNClientWindow, aClientWindow,
+ XNInputStyle, mnPreeditStyle | mnStatusStyle,
+ 0 );
+
+ #ifdef SOLARIS
+ mpDisplay = pDisplay;
+ if ( 0 && (mpFontSet = p_create_fontset(mpDisplay)) != NULL )
+ {
+ mpStatusAttributes = XVaAddToNestedList( mpStatusAttributes,
+ XNFontSet, (XPointer)mpFontSet );
+ mpPreeditAttributes = XVaAddToNestedList( mpPreeditAttributes,
+ XNFontSet, (XPointer)mpFontSet );
+ }
+ #endif
+ if ( mnPreeditStyle != XIMPreeditNone )
+ {
+ #ifdef LINUX
+ if ( mpPreeditAttributes != NULL )
+ #endif
+ mpAttributes = XVaAddToNestedList( mpAttributes,
+ XNPreeditAttributes, (XPointer)mpPreeditAttributes );
+ }
+ if ( mnStatusStyle != XIMStatusNone )
+ {
+ #ifdef LINUX
+ if ( mpStatusAttributes != NULL )
+ #endif
+ mpAttributes = XVaAddToNestedList( mpAttributes,
+ XNStatusAttributes, (XPointer)mpStatusAttributes );
+ }
+ maContext = XCreateIC( pInputMethod->GetMethod(),
+ XNVaNestedList, mpAttributes,
+ NULL );
+ }
+
+ if ( maContext == NULL )
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "input context creation failed\n");
+ #endif
+
+ mbUseable = False;
+ mbMultiLingual = False;
+
+ if ( mpAttributes != NULL )
+ XFree( mpAttributes );
+ if ( mpStatusAttributes != NULL )
+ XFree( mpStatusAttributes );
+ if ( mpPreeditAttributes != NULL )
+ XFree( mpPreeditAttributes );
+ }
+
+ if ( maContext != NULL && mbMultiLingual )
+ {
+ maCommitStringCallback.callback = (XIMProc)::CommitStringCallback;
+ maCommitStringCallback.client_data = (XPointer)&maClientData;
+ XSetICValues( maContext,
+ XNCommitStringCallback, &maCommitStringCallback,
+ NULL );
+ }
+
+}
+
+// ---------------------------------------------------------------------------
+//
+// In Solaris 8 the status window does not unmap if the frame unmapps, so
+// unmap it the hard way
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::Unmap()
+{
+ if ( maContext != NULL )
+ {
+ XDestroyIC( maContext );
+ maContext = NULL;
+ }
+}
+
+void
+SalI18N_InputContext::Map( SalFrame *pFrame )
+{
+ if ( (maContext == NULL) && mbUseable)
+ {
+ SalI18N_InputMethod *pInputMethod;
+ pInputMethod = pFrame->maFrameData.GetDisplay()->GetInputMethod();
+
+ maContext = XCreateIC( pInputMethod->GetMethod(),
+ XNVaNestedList, mpAttributes,
+ NULL );
+ if ( maContext != NULL && mbMultiLingual )
+ XSetICValues( maContext,
+ XNCommitStringCallback, &maCommitStringCallback,
+ NULL );
+ SetICFocus();
+ }
+}
+
+// ---------------------------------------------------------------------------
+//
+// make sure, the input method gets all the X-Events it needs, this is only
+// called once on each frame, it relys on a valid maContext
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::ExtendEventMask( XLIB_Window aFocusWindow )
+{
+ unsigned long nIMEventMask;
+ XWindowAttributes aWindowAttributes;
+
+ if ( mbUseable )
+ {
+ Display *pDisplay = XDisplayOfIM( XIMOfIC(maContext) );
+
+ XGetWindowAttributes( pDisplay, aFocusWindow,
+ &aWindowAttributes );
+ XGetICValues ( maContext,
+ XNFilterEvents, &nIMEventMask,
+ NULL);
+ nIMEventMask |= aWindowAttributes.your_event_mask;
+ XSelectInput ( pDisplay, aFocusWindow, nIMEventMask );
+ }
+}
+
+// ---------------------------------------------------------------------------
+//
+// tune the styles provided by the input method with the supported one
+//
+// ---------------------------------------------------------------------------
+
+unsigned int
+SalI18N_InputContext::GetWeightingOfIMStyle( XIMStyle nStyle ) const
+{
+ struct StyleWeightingT {
+ const XIMStyle nStyle;
+ const unsigned int nWeight;
+ };
+
+ StyleWeightingT const *pWeightPtr;
+ const StyleWeightingT pWeight[] = {
+ { XIMPreeditCallbacks, 0x10000000 },
+ { XIMPreeditPosition, 0x02000000 },
+ { XIMPreeditArea, 0x01000000 },
+ { XIMPreeditNothing, 0x00100000 },
+ { XIMPreeditNone, 0x00010000 },
+ { XIMStatusCallbacks, 0x1000 },
+ { XIMStatusArea, 0x0100 },
+ { XIMStatusNothing, 0x0010 },
+ { XIMStatusNone, 0x0001 },
+ { 0, 0x0 }
+ };
+
+ int nWeight = 0;
+ for ( pWeightPtr = pWeight; pWeightPtr->nStyle != 0; pWeightPtr++ )
+ {
+ if ( (pWeightPtr->nStyle & nStyle) != 0 )
+ nWeight += pWeightPtr->nWeight;
+ }
+ return nWeight;
+}
+
+Bool
+SalI18N_InputContext::IsSupportedIMStyle( XIMStyle nStyle ) const
+{
+ if ( (nStyle & mnSupportedPreeditStyle)
+ && (nStyle & mnSupportedStatusStyle) )
+ {
+ return True;
+ }
+ return False;
+}
+
+Bool
+SalI18N_InputContext::SupportInputMethodStyle( XIMStyles *pIMStyles )
+{
+ int nBestScore = 0;
+ int nActualScore = 0;
+
+ mnPreeditStyle = 0;
+ mnStatusStyle = 0;
+
+ if ( pIMStyles != NULL )
+ {
+ // check whether the XIM supports one of the desired styles
+ // only a single preedit and a single status style must occure
+ // in a inpuut method style. Hideki said so, so i trust him
+ for ( int nStyle = 0; nStyle < pIMStyles->count_styles; nStyle++ )
+ {
+ XIMStyle nProvidedStyle = pIMStyles->supported_styles[ nStyle ];
+ if ( IsSupportedIMStyle(nProvidedStyle) )
+ {
+ nActualScore = GetWeightingOfIMStyle( nProvidedStyle );
+ if ( nActualScore >= nBestScore )
+ {
+ nBestScore = nActualScore;
+ mnPreeditStyle = nProvidedStyle & mnSupportedPreeditStyle;
+ mnStatusStyle = nProvidedStyle & mnSupportedStatusStyle;
+ }
+ }
+ }
+ }
+
+ #ifdef DEBUG
+ char pBuf[ 128 ];
+ fprintf( stderr, "selected inputmethod style = %s\n",
+ GetMethodName(mnPreeditStyle | mnStatusStyle, pBuf, sizeof(pBuf)) );
+ #endif
+
+ return (mnPreeditStyle != 0) && (mnStatusStyle != 0) ;
+}
+
+int
+SalI18N_InputContext::CommitStringCallback( sal_Unicode* pText, sal_Size nLength )
+{
+ XIMUnicodeText call_data;
+
+ call_data.string.utf16_char = pText;
+ call_data.length = nLength;
+ call_data.annotations = NULL;
+ call_data.count_annotations = 0;
+ call_data.feedback = NULL;
+
+ return ::CommitStringCallback( maContext,
+ (XPointer)&maClientData, (XPointer)&call_data );
+}
+
+// ---------------------------------------------------------------------------
+//
+// set and unset the focus for the Input Context
+// the context may be NULL despite it is useable if the framewindow is
+// in unmapped state
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::SetICFocus()
+{
+ if ( mbUseable && (maContext != NULL) )
+ XSetICFocus( maContext );
+}
+
+void
+SalI18N_InputContext::UnsetICFocus()
+{
+ if ( mbUseable && (maContext != NULL) )
+ XUnsetICFocus( maContext );
+}
+
+// ---------------------------------------------------------------------------
+//
+// not used, multi byte input method only
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::EndExtTextInput( USHORT nFlags )
+{
+ if ( mbUseable && (maContext != NULL) )
+ {
+ char *pPendingChars = XmbResetIC( maContext );
+
+ // text is unicode
+ if ( (pPendingChars != NULL)
+ && (nFlags & SAL_FRAME_ENDEXTTEXTINPUT_COMPLETE) )
+ {
+ XIMUnicodeText aPendingText;
+ int nLen;
+ sal_Unicode* pPtr;
+ rtl_TextEncoding nEncoding = gsl_getSystemTextEncoding();
+
+ // buffer is already unicode
+ if ( mbMultiLingual || nEncoding == RTL_TEXTENCODING_UNICODE )
+ {
+ pPtr = (sal_Unicode*)pPendingChars;
+ for ( nLen = 0; pPtr[ nLen ] != (sal_Unicode)0; nLen++ )
+ ;
+ }
+ // else convert buffer to unicode
+ else
+ {
+ for ( nLen = 0; pPendingChars[ nLen ] != (char)0; nLen++ )
+ ;
+
+ // create text converter
+ rtl_TextToUnicodeConverter aConverter =
+ rtl_createTextToUnicodeConverter( nEncoding );
+ rtl_TextToUnicodeContext aContext =
+ rtl_createTextToUnicodeContext( aConverter );
+
+ sal_Size nBufferSize = nLen * 2;
+ sal_uInt32 nConversionInfo;
+ sal_Size nConvertedChars;
+
+ pPtr = (sal_Unicode*) alloca( nBufferSize );
+
+ // convert to single byte text stream
+ nLen = rtl_convertTextToUnicode(
+ aConverter, aContext, (char*)pPendingChars,
+ nLen, pPtr, nBufferSize,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
+ &nConversionInfo, &nConvertedChars );
+
+ // destroy converter
+ rtl_destroyTextToUnicodeContext( aConverter, aContext );
+ rtl_destroyTextToUnicodeConverter( aConverter );
+ }
+ aPendingText.length = nLen;
+ aPendingText.string.utf16_char = pPtr;
+
+ ::CommitStringCallback( maContext,
+ (XPointer)&maClientData, (XPointer)&aPendingText );
+ }
+ if ( pPendingChars != NULL )
+ XFree ( (void*)pPendingChars );
+ }
+}
+
+