summaryrefslogtreecommitdiff
path: root/vcl/unx/generic/app
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/generic/app')
-rw-r--r--vcl/unx/generic/app/i18n_cb.cxx664
-rw-r--r--vcl/unx/generic/app/i18n_ic.cxx781
-rw-r--r--vcl/unx/generic/app/i18n_im.cxx619
-rw-r--r--vcl/unx/generic/app/i18n_keysym.cxx365
-rw-r--r--vcl/unx/generic/app/i18n_status.cxx733
-rw-r--r--vcl/unx/generic/app/i18n_wrp.cxx260
-rw-r--r--vcl/unx/generic/app/i18n_xkb.cxx163
-rw-r--r--vcl/unx/generic/app/keysymnames.cxx688
-rw-r--r--vcl/unx/generic/app/makefile.mk110
-rw-r--r--vcl/unx/generic/app/randrwrapper.cxx360
-rw-r--r--vcl/unx/generic/app/saldata.cxx867
-rw-r--r--vcl/unx/generic/app/saldisp.cxx3435
-rw-r--r--vcl/unx/generic/app/salinst.cxx452
-rw-r--r--vcl/unx/generic/app/salsys.cxx226
-rw-r--r--vcl/unx/generic/app/saltimer.cxx96
-rw-r--r--vcl/unx/generic/app/sm.cxx801
-rw-r--r--vcl/unx/generic/app/soicon.cxx116
-rw-r--r--vcl/unx/generic/app/wmadaptor.cxx2548
18 files changed, 13284 insertions, 0 deletions
diff --git a/vcl/unx/generic/app/i18n_cb.cxx b/vcl/unx/generic/app/i18n_cb.cxx
new file mode 100644
index 000000000000..5a314c19d3e5
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_cb.cxx
@@ -0,0 +1,664 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sal/alloca.h>
+#include <osl/thread.h>
+
+#include <tools/prex.h>
+#include <X11/Xlocale.h>
+#include <X11/Xlib.h>
+#include <tools/postx.h>
+
+#include "unx/salunx.h"
+#include "unx/XIM.h"
+#include "unx/i18n_cb.hxx"
+#include "unx/i18n_status.hxx"
+#include "unx/i18n_ic.hxx"
+#include "unx/i18n_im.hxx"
+#include "salframe.hxx"
+
+// -------------------------------------------------------------------------
+//
+// i. preedit start callback
+//
+// -------------------------------------------------------------------------
+
+int
+PreeditStartCallback ( XIC, XPointer client_data, XPointer )
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+ if ( pPreeditData->eState == ePreeditStatusActivationRequired )
+ {
+ pPreeditData->eState = ePreeditStatusActive;
+ pPreeditData->aText.nCursorPos = 0;
+ pPreeditData->aText.nLength = 0;
+ }
+
+ return -1;
+}
+
+// -------------------------------------------------------------------------
+//
+// ii. preedit done callback
+//
+// -------------------------------------------------------------------------
+
+void
+PreeditDoneCallback ( XIC, XPointer client_data, XPointer )
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+ if (pPreeditData->eState == ePreeditStatusActive )
+ {
+ if( pPreeditData->pFrame )
+ pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ pPreeditData->eState = ePreeditStatusStartPending;
+}
+
+// -------------------------------------------------------------------------
+//
+// iii. preedit draw callback
+//
+// -------------------------------------------------------------------------
+
+//
+// Handle deletion of text in a preedit_draw_callback
+// from and howmuch are guaranteed to be nonnegative
+//
+
+void
+Preedit_DeleteText(preedit_text_t *ptext, int from, int howmuch)
+{
+ // If we've been asked to delete no text then just set
+ // nLength correctly and return
+ if (ptext->nLength == 0)
+ {
+ ptext->nLength = from;
+ return;
+ }
+
+ int to = from + howmuch;
+
+ if (to == (int)ptext->nLength)
+ {
+ // delete from the end of the text
+ ptext->nLength = from;
+ }
+ else
+ if (to < (int)ptext->nLength)
+ {
+ // cut out of the middle of the text
+ memmove( (void*)(ptext->pUnicodeBuffer + from),
+ (void*)(ptext->pUnicodeBuffer + to),
+ (ptext->nLength - to) * sizeof(sal_Unicode));
+ memmove( (void*)(ptext->pCharStyle + from),
+ (void*)(ptext->pCharStyle + to),
+ (ptext->nLength - to) * sizeof(XIMFeedback));
+ ptext->nLength -= howmuch;
+ }
+ else
+ // if ( to > pText->nLength )
+ {
+ // XXX this indicates an error, are we out of sync ?
+ fprintf(stderr, "Preedit_DeleteText( from=%i to=%i length=%i )\n",
+ from, to, ptext->nLength );
+ fprintf (stderr, "\t XXX internal error, out of sync XXX\n");
+
+ ptext->nLength = from;
+ }
+
+ // NULL-terminate the string
+ ptext->pUnicodeBuffer[ptext->nLength] = (sal_Unicode)0;
+}
+
+// reallocate the textbuffer with sufficiently large size 2^x
+// nnewlimit is presupposed to be larger than ptext->size
+void
+enlarge_buffer ( preedit_text_t *ptext, int nnewlimit )
+{
+ size_t nnewsize = ptext->nSize;
+
+ while ( nnewsize <= (size_t)nnewlimit )
+ nnewsize *= 2;
+
+ ptext->nSize = nnewsize;
+ ptext->pUnicodeBuffer = (sal_Unicode*)realloc((void*)ptext->pUnicodeBuffer,
+ nnewsize * sizeof(sal_Unicode));
+ ptext->pCharStyle = (XIMFeedback*)realloc((void*)ptext->pCharStyle,
+ nnewsize * sizeof(XIMFeedback));
+}
+
+//
+// Handle insertion of text in a preedit_draw_callback
+// string field of XIMText struct is guaranteed to be != NULL
+//
+
+void
+Preedit_InsertText(preedit_text_t *pText, XIMText *pInsertText, int where,
+ Bool isMultilingual)
+{
+ sal_Unicode *pInsertTextString;
+ int nInsertTextLength = 0;
+ XIMFeedback *pInsertTextCharStyle = pInsertText->feedback;
+
+ nInsertTextLength = pInsertText->length;
+
+ if (isMultilingual)
+ {
+ XIMUnicodeText *pUniText = (XIMUnicodeText*)pInsertText;
+ pInsertTextString = pUniText->string.utf16_char;
+ }
+ else
+ {
+ // can't handle wchar_t strings, so convert to multibyte chars first
+ char *pMBString;
+ size_t nMBLength;
+ if (pInsertText->encoding_is_wchar)
+ {
+ wchar_t *pWCString = pInsertText->string.wide_char;
+ size_t nBytes = wcstombs ( NULL, pWCString, 1024 /* dont care */);
+ pMBString = (char*)alloca( nBytes + 1 );
+ nMBLength = wcstombs ( pMBString, pWCString, nBytes + 1);
+ }
+ else
+ {
+ pMBString = pInsertText->string.multi_byte;
+ nMBLength = strlen(pMBString); // xxx
+ }
+
+ // convert multibyte chars to unicode
+ rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
+
+ if (nEncoding != RTL_TEXTENCODING_UNICODE)
+ {
+ rtl_TextToUnicodeConverter aConverter =
+ rtl_createTextToUnicodeConverter( nEncoding );
+ rtl_TextToUnicodeContext aContext =
+ rtl_createTextToUnicodeContext(aConverter);
+
+ sal_Size nBufferSize = nInsertTextLength * 2;
+
+ pInsertTextString = (sal_Unicode*)alloca(nBufferSize);
+
+ sal_uInt32 nConversionInfo;
+ sal_Size nConvertedChars;
+
+ rtl_convertTextToUnicode( aConverter, aContext,
+ pMBString, nMBLength,
+ pInsertTextString, nBufferSize,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
+ &nConversionInfo, &nConvertedChars );
+
+ rtl_destroyTextToUnicodeContext(aConverter, aContext);
+ rtl_destroyTextToUnicodeConverter(aConverter);
+
+ }
+ else
+ {
+ pInsertTextString = (sal_Unicode*)pMBString;
+ }
+ }
+
+ // enlarge target text-buffer if necessary
+ if (pText->nSize <= (pText->nLength + nInsertTextLength))
+ enlarge_buffer(pText, pText->nLength + nInsertTextLength);
+
+ // insert text: displace old mem and put new bytes in
+ int from = where;
+ int to = where + nInsertTextLength;
+ int howmany = pText->nLength - where;
+
+ memmove((void*)(pText->pUnicodeBuffer + to),
+ (void*)(pText->pUnicodeBuffer + from),
+ howmany * sizeof(sal_Unicode));
+ memmove((void*)(pText->pCharStyle + to),
+ (void*)(pText->pCharStyle + from),
+ howmany * sizeof(XIMFeedback));
+
+ to = from;
+ howmany = nInsertTextLength;
+
+ memcpy((void*)(pText->pUnicodeBuffer + to), (void*)pInsertTextString,
+ howmany * sizeof(sal_Unicode));
+ memcpy((void*)(pText->pCharStyle + to), (void*)pInsertTextCharStyle,
+ howmany * sizeof(XIMFeedback));
+
+ pText->nLength += howmany;
+
+ // NULL-terminate the string
+ pText->pUnicodeBuffer[pText->nLength] = (sal_Unicode)0;
+}
+
+//
+// Handle the change of attributes in a preedit_draw_callback
+//
+void
+Preedit_UpdateAttributes ( preedit_text_t* ptext, XIMFeedback* feedback,
+ int from, int amount )
+{
+ if ( (from + amount) > (int)ptext->nLength )
+ {
+ // XXX this indicates an error, are we out of sync ?
+ fprintf (stderr, "Preedit_UpdateAttributes( %i + %i > %i )\n",
+ from, amount, ptext->nLength );
+ fprintf (stderr, "\t XXX internal error, out of sync XXX\n");
+
+ return;
+ }
+
+ memcpy ( ptext->pCharStyle + from,
+ feedback, amount * sizeof(XIMFeedback) );
+}
+
+// Convert the XIM feedback values into appropriate VCL
+// SAL_EXTTEXTINPUT_ATTR values
+// returns an allocate list of attributes, which must be freed by caller
+USHORT*
+Preedit_FeedbackToSAL ( XIMFeedback* pfeedback, int nlength, std::vector<USHORT>& rSalAttr )
+{
+ USHORT *psalattr;
+ USHORT nval;
+ USHORT noldval = 0;
+ XIMFeedback nfeedback;
+
+ // only work with reasonable length
+ if (nlength > 0 && nlength > sal::static_int_cast<int>(rSalAttr.size()) )
+ {
+ rSalAttr.reserve( nlength );
+ psalattr = &rSalAttr[0];
+ }
+ else
+ return (USHORT*)NULL;
+
+ for (int npos = 0; npos < nlength; npos++)
+ {
+ nval = 0;
+ nfeedback = pfeedback[npos];
+
+ // means to use the feedback of the previous char
+ if (nfeedback == 0)
+ {
+ nval = noldval;
+ }
+ // convert feedback to attributes
+ else
+ {
+ if (nfeedback & XIMReverse)
+ nval |= SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ if (nfeedback & XIMUnderline)
+ nval |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ if (nfeedback & XIMHighlight)
+ nval |= SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ if (nfeedback & XIMPrimary)
+ nval |= SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ if (nfeedback & XIMSecondary)
+ nval |= SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
+ if (nfeedback & XIMTertiary) // same as 2ery
+ nval |= SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
+
+ /*
+ // visibility feedback not supported now
+ if ( (nfeedback & XIMVisibleToForward)
+ || (nfeedback & XIMVisibleToBackward)
+ || (nfeedback & XIMVisibleCenter) )
+ { }
+ */
+ }
+ // copy in list
+ psalattr[npos] = nval;
+ noldval = nval;
+ }
+ // return list of sal attributes
+ return psalattr;
+}
+
+void
+PreeditDrawCallback(XIC ic, XPointer client_data,
+ XIMPreeditDrawCallbackStruct *call_data)
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+
+ // if there's nothing to change then change nothing
+ if ( ( (call_data->text == NULL) && (call_data->chg_length == 0) )
+ || pPreeditData->pFrame == NULL )
+ return;
+
+ // #88564# Solaris 7 deletes the preedit buffer after commit
+ // since the next call to preeditstart will have the same effect just skip this.
+ // if (pPreeditData->eState == ePreeditStatusStartPending && call_data->text == NULL)
+ // return;
+
+ if ( pPreeditData->eState == ePreeditStatusStartPending )
+ pPreeditData->eState = ePreeditStatusActivationRequired;
+ PreeditStartCallback( ic, client_data, NULL );
+
+ // Edit the internal textbuffer as indicated by the call_data,
+ // chg_first and chg_length are guaranteed to be nonnegative
+
+ // handle text deletion
+ if (call_data->text == NULL)
+ {
+ Preedit_DeleteText(&(pPreeditData->aText),
+ call_data->chg_first, call_data->chg_length );
+ }
+ else
+ {
+ // handle text insertion
+ if ( (call_data->chg_length == 0)
+ && (call_data->text->string.wide_char != NULL))
+ {
+ Preedit_InsertText(&(pPreeditData->aText), call_data->text,
+ call_data->chg_first, pPreeditData->bIsMultilingual);
+ }
+ else
+ // handle text replacement by deletion and insertion of text,
+ // not smart, just good enough
+ if ( (call_data->chg_length != 0)
+ && (call_data->text->string.wide_char != NULL))
+ {
+ Preedit_DeleteText(&(pPreeditData->aText),
+ call_data->chg_first, call_data->chg_length);
+ Preedit_InsertText(&(pPreeditData->aText), call_data->text,
+ call_data->chg_first, pPreeditData->bIsMultilingual);
+ }
+ else
+ // not really a text update, only attributes are concerned
+ if ( (call_data->chg_length != 0)
+ && (call_data->text->string.wide_char == NULL))
+ {
+ Preedit_UpdateAttributes(&(pPreeditData->aText),
+ call_data->text->feedback,
+ call_data->chg_first, call_data->chg_length);
+ }
+ }
+
+ //
+ // build the SalExtTextInputEvent and send it up
+ //
+ pPreeditData->aInputEv.mnTime = 0;
+ pPreeditData->aInputEv.mpTextAttr = Preedit_FeedbackToSAL(
+ pPreeditData->aText.pCharStyle, pPreeditData->aText.nLength, pPreeditData->aInputFlags);
+ pPreeditData->aInputEv.mnCursorPos = call_data->caret;
+ pPreeditData->aInputEv.maText = String (pPreeditData->aText.pUnicodeBuffer,
+ pPreeditData->aText.nLength);
+ pPreeditData->aInputEv.mnCursorFlags = 0; // default: make cursor visible
+ pPreeditData->aInputEv.mnDeltaStart = 0; // call_data->chg_first;
+ pPreeditData->aInputEv.mbOnlyCursor = False;
+
+ if ( pPreeditData->eState == ePreeditStatusActive && pPreeditData->pFrame )
+ pPreeditData->pFrame->CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&pPreeditData->aInputEv);
+ if (pPreeditData->aText.nLength == 0 && pPreeditData->pFrame )
+ pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+
+ if (pPreeditData->aText.nLength == 0)
+ pPreeditData->eState = ePreeditStatusStartPending;
+
+ GetPreeditSpotLocation(ic, (XPointer)pPreeditData);
+}
+
+void
+GetPreeditSpotLocation(XIC ic, XPointer client_data)
+{
+ //
+ // Send SalEventExtTextInputPos event to get spotlocation
+ //
+ SalExtTextInputPosEvent mPosEvent;
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+
+ if( pPreeditData->pFrame )
+ pPreeditData->pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&mPosEvent);
+
+ XPoint point;
+ point.x = mPosEvent.mnX + mPosEvent.mnWidth;
+ point.y = mPosEvent.mnY + mPosEvent.mnHeight;
+
+ XVaNestedList preedit_attr;
+ preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &point, NULL);
+ XSetICValues(ic, XNPreeditAttributes, preedit_attr, NULL);
+ XFree(preedit_attr);
+
+ return;
+}
+
+// -------------------------------------------------------------------------
+//
+// iv. preedit caret callback
+//
+// -------------------------------------------------------------------------
+
+#if OSL_DEBUG_LEVEL > 1
+void
+PreeditCaretCallback ( XIC ic, XPointer client_data,
+ XIMPreeditCaretCallbackStruct *call_data )
+#else
+void
+PreeditCaretCallback ( XIC, XPointer,XIMPreeditCaretCallbackStruct* )
+#endif
+{
+ #if OSL_DEBUG_LEVEL > 1
+ // XXX PreeditCaretCallback is pure debug code for now
+ const char *direction = "?";
+ const char *style = "?";
+
+ switch ( call_data->style )
+ {
+ case XIMIsInvisible: style = "Invisible"; break;
+ case XIMIsPrimary: style = "Primary"; break;
+ case XIMIsSecondary: style = "Secondary"; break;
+ }
+ switch ( call_data->direction )
+ {
+ case XIMForwardChar: direction = "Forward char"; break;
+ case XIMBackwardChar: direction = "Backward char"; break;
+ case XIMForwardWord: direction = "Forward word"; break;
+ case XIMBackwardWord: direction = "Backward word"; break;
+ case XIMCaretUp: direction = "Caret up"; break;
+ case XIMCaretDown: direction = "Caret down"; break;
+ case XIMNextLine: direction = "Next line"; break;
+ case XIMPreviousLine: direction = "Previous line"; break;
+ case XIMLineStart: direction = "Line start"; break;
+ case XIMLineEnd: direction = "Line end"; break;
+ case XIMAbsolutePosition: direction = "Absolute"; break;
+ case XIMDontChange: direction = "Dont change"; break;
+ }
+
+ fprintf (stderr, "PreeditCaretCallback( ic=%p, client=%p,\n",
+ ic, client_data );
+ fprintf (stderr, "\t position=%i, direction=\"%s\", style=\"%s\" )\n",
+ call_data->position, direction, style );
+ #endif
+}
+
+// -----------------------------------------------------------------------
+//
+// v. commit string callback: convert an extended text input (iiimp ... )
+// into an ordinary key-event
+//
+// -----------------------------------------------------------------------
+
+Bool
+IsControlCode(sal_Unicode nChar)
+{
+ if ( nChar <= 0x1F // C0 controls
+ /* || (0x80 <= nChar && nChar <= 0x9F) C1 controls */ )
+ return True;
+ else
+ return False;
+}
+
+int
+CommitStringCallback( XIC ic, XPointer client_data, XPointer call_data )
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+
+ XIMUnicodeText *cbtext = (XIMUnicodeText *)call_data;
+ sal_Unicode *p_unicode_data = (sal_Unicode*)cbtext->string.utf16_char;
+
+ // #86964# filter unexpected pure control events
+ if (cbtext->length == 1 && IsControlCode(p_unicode_data[0]) )
+ {
+ if( pPreeditData->pFrame )
+ {
+ pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ }
+ else
+ {
+ if( pPreeditData->pFrame )
+ {
+ pPreeditData->aInputEv.mnTime = 0;
+ pPreeditData->aInputEv.mpTextAttr = 0;
+ pPreeditData->aInputEv.mnCursorPos = cbtext->length;
+ pPreeditData->aInputEv.maText = UniString(p_unicode_data, cbtext->length);
+ pPreeditData->aInputEv.mnCursorFlags = 0; // default: make cursor visible
+ pPreeditData->aInputEv.mnDeltaStart = 0;
+ pPreeditData->aInputEv.mbOnlyCursor = False;
+
+ pPreeditData->pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pPreeditData->aInputEv);
+ pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ }
+ pPreeditData->eState = ePreeditStatusStartPending;
+
+ GetPreeditSpotLocation(ic, (XPointer)pPreeditData);
+
+ return 0;
+}
+
+// ----------------------------------------------------------------------------------
+//
+// vi. status callbacks: for now these are empty, they are just needed for turbo linux
+//
+// ----------------------------------------------------------------------------------
+
+void
+StatusStartCallback (XIC, XPointer, XPointer)
+{
+ return;
+}
+
+void
+StatusDoneCallback (XIC, XPointer, XPointer)
+{
+ return;
+}
+
+void
+StatusDrawCallback (XIC ic, XPointer client_data, XIMStatusDrawCallbackStruct *call_data)
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+ if( pPreeditData->bIsMultilingual )
+ {
+ // IIIMP
+ XIMUnicodeText *cbtext = (XIMUnicodeText *)call_data->data.text;
+ ::vcl::I18NStatus::get().setStatusText( String( cbtext->string.utf16_char, call_data->data.text->length ) );
+ XIMUnicodeCharacterSubset* pSubset = NULL;
+ if( ! XGetICValues( ic,
+ XNUnicodeCharacterSubset, & pSubset,
+ NULL )
+ && pSubset )
+ {
+ ::vcl::I18NStatus::get().changeIM( String( ByteString( pSubset->name ), RTL_TEXTENCODING_UTF8 ) );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "got XNUnicodeCharacterSubset\n %d\n %d\n %s\n %d\n", pSubset->index, pSubset->subset_id, pSubset->name, pSubset->is_active );
+#endif
+ }
+ }
+ else if( call_data->type == XIMTextType )
+ {
+ String aText;
+ if( call_data->data.text )
+ {
+ // XIM with text
+ sal_Char* pMBString = NULL;
+ size_t nLength = 0;
+ if( call_data->data.text->encoding_is_wchar )
+ {
+ if( call_data->data.text->string.wide_char )
+ {
+ wchar_t* pWString = call_data->data.text->string.wide_char;
+ size_t nBytes = wcstombs( NULL, pWString, 1024 );
+ pMBString = (sal_Char*)alloca( nBytes+1 );
+ nLength = wcstombs( pMBString, pWString, nBytes+1 );
+ }
+ }
+ else
+ {
+ if( call_data->data.text->string.multi_byte )
+ {
+ pMBString = call_data->data.text->string.multi_byte;
+ nLength = strlen( pMBString );
+ }
+ }
+ if( nLength )
+ aText = String( pMBString, nLength, gsl_getSystemTextEncoding() );
+ }
+ ::vcl::I18NStatus::get().setStatusText( aText );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "XIMStatusDataType %s not supported\n",
+ call_data->type == XIMBitmapType ? "XIMBitmapType" : ByteString::CreateFromInt32( call_data->type ).GetBuffer() );
+#endif
+ return;
+}
+
+void
+SwitchIMCallback (XIC, XPointer, XPointer call_data)
+{
+ XIMSwitchIMNotifyCallbackStruct* pCallData = (XIMSwitchIMNotifyCallbackStruct*)call_data;
+ ::vcl::I18NStatus::get().changeIM( String( ByteString( pCallData->to->name ), RTL_TEXTENCODING_UTF8 ) );
+}
+
+// ----------------------------------------------------------------------------------
+//
+// vii. destroy callbacks: internally disable all IC/IM calls
+//
+// ----------------------------------------------------------------------------------
+
+void
+IC_IMDestroyCallback (XIM, XPointer client_data, XPointer)
+{
+ SalI18N_InputContext *pContext = (SalI18N_InputContext*)client_data;
+ if (pContext != NULL)
+ pContext->HandleDestroyIM();
+}
+
+void
+IM_IMDestroyCallback (XIM, XPointer client_data, XPointer)
+{
+ SalI18N_InputMethod *pMethod = (SalI18N_InputMethod*)client_data;
+ if (pMethod != NULL)
+ pMethod->HandleDestroyIM();
+}
diff --git a/vcl/unx/generic/app/i18n_ic.cxx b/vcl/unx/generic/app/i18n_ic.cxx
new file mode 100644
index 000000000000..517eb37a1b2e
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_ic.cxx
@@ -0,0 +1,781 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+
+#include <sal/alloca.h>
+#include <osl/thread.h>
+
+#include <tools/prex.h>
+#include <X11/Xlocale.h>
+#include <X11/Xlib.h>
+#include <tools/postx.h>
+
+#include <unx/salunx.h>
+#include <unx/XIM.h>
+#include <unx/i18n_ic.hxx>
+#include <unx/i18n_im.hxx>
+#include <unx/i18n_status.hxx>
+
+#include <unx/salframe.h>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+
+using namespace vcl;
+
+static void sendEmptyCommit( SalFrame* pFrame )
+{
+ vcl::DeletionListener aDel( pFrame );
+
+ SalExtTextInputEvent aEmptyEv;
+ aEmptyEv.mnTime = 0;
+ aEmptyEv.mpTextAttr = 0;
+ aEmptyEv.maText = String();
+ aEmptyEv.mnCursorPos = 0;
+ aEmptyEv.mnCursorFlags = 0;
+ aEmptyEv.mnDeltaStart = 0;
+ aEmptyEv.mbOnlyCursor = False;
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
+ if( ! aDel.isDeleted() )
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+// ---------------------------------------------------------------------------
+//
+// 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 );
+
+ if (maClientData.aText.pUnicodeBuffer != NULL)
+ free(maClientData.aText.pUnicodeBuffer);
+ if (maClientData.aText.pCharStyle != NULL)
+ free(maClientData.aText.pCharStyle);
+}
+
+// ----------------------------------------------------------------------------
+// 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,
+ NULL );
+ }
+ else
+ {
+ a_dstlist = XVaCreateNestedList(
+ 0,
+ XNVaNestedList, a_srclist,
+ name, value,
+ NULL );
+ }
+
+ return a_dstlist != NULL ? a_dstlist : a_srclist ;
+}
+
+// ----------------------------------------------------------------------------
+// convenience routine to create a fontset
+// ----------------------------------------------------------------------------
+
+static XFontSet
+get_font_set( Display *p_display )
+{
+ static XFontSet p_font_set = NULL;
+
+ if (p_font_set == NULL)
+ {
+ char **pp_missing_list;
+ int n_missing_count;
+ char *p_default_string;
+
+ p_font_set = XCreateFontSet(p_display, "-*",
+ &pp_missing_list, &n_missing_count, &p_default_string);
+ }
+
+ return p_font_set;
+}
+
+// ---------------------------------------------------------------------------
+//
+// Constructor for a InputContext (IC)
+//
+// ----------------------------------------------------------------------------
+
+SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) :
+ mbUseable( True ),
+ maContext( (XIC)NULL ),
+ mnSupportedStatusStyle(
+ XIMStatusCallbacks |
+ XIMStatusNothing |
+ XIMStatusNone
+ ),
+ mnSupportedPreeditStyle(
+ XIMPreeditCallbacks |
+ XIMPreeditNothing |
+ XIMPreeditNone
+ ),
+ mnStatusStyle( 0 ),
+ mnPreeditStyle( 0 ),
+ mpAttributes( NULL ),
+ mpStatusAttributes( NULL ),
+ mpPreeditAttributes( NULL )
+{
+#ifdef SOLARIS
+ static const char* pIIIMPEnable = getenv( "SAL_DISABLE_OWN_IM_STATUS" );
+ if( pIIIMPEnable && *pIIIMPEnable )
+ mnSupportedStatusStyle &= ~XIMStatusCallbacks;
+#endif
+
+ maClientData.aText.pUnicodeBuffer = NULL;
+ maClientData.aText.pCharStyle = NULL;
+ maClientData.aInputEv.mnTime = 0;
+ maClientData.aInputEv.mpTextAttr = NULL;
+ maClientData.aInputEv.mnCursorPos = 0;
+ maClientData.aInputEv.mnDeltaStart = 0;
+ maClientData.aInputEv.mnCursorFlags = 0;
+ maClientData.aInputEv.mbOnlyCursor = FALSE;
+
+ SalI18N_InputMethod *pInputMethod;
+ pInputMethod = GetX11SalData()->GetDisplay()->GetInputMethod();
+ mbMultiLingual = pInputMethod->IsMultiLingual();
+
+ mnSupportedPreeditStyle = XIMPreeditCallbacks | XIMPreeditPosition
+ | XIMPreeditNothing | XIMPreeditNone;
+ if (pInputMethod->UseMethod()
+ && SupportInputMethodStyle( pInputMethod->GetSupportedStyles() ) )
+ {
+ const SystemEnvData* pEnv = pFrame->GetSystemData();
+ XLIB_Window aClientWindow = pEnv->aShellWindow;
+ XLIB_Window aFocusWindow = pEnv->aWindow;
+
+ // for status callbacks and commit string callbacks
+#define PREEDIT_BUFSZ 16
+ maClientData.bIsMultilingual = mbMultiLingual;
+ maClientData.eState = ePreeditStatusStartPending;
+ maClientData.pFrame = pFrame;
+ maClientData.aText.pUnicodeBuffer =
+ (sal_Unicode*)malloc(PREEDIT_BUFSZ * sizeof(sal_Unicode));
+ maClientData.aText.pCharStyle =
+ (XIMFeedback*)malloc(PREEDIT_BUFSZ * sizeof(XIMFeedback));;
+ maClientData.aText.nSize = PREEDIT_BUFSZ;
+ maClientData.aText.nCursorPos = 0;
+ maClientData.aText.nLength = 0;
+
+ //
+ // Status attributes
+ //
+
+ switch ( mnStatusStyle )
+ {
+ case XIMStatusCallbacks:
+ {
+ static XIMCallback aStatusStartCallback;
+ static XIMCallback aStatusDoneCallback;
+ static XIMCallback aStatusDrawCallback;
+
+ aStatusStartCallback.callback = (XIMProc)StatusStartCallback;
+ aStatusStartCallback.client_data = (XPointer)&maClientData;
+ aStatusDoneCallback.callback = (XIMProc)StatusDoneCallback;
+ aStatusDoneCallback.client_data = (XPointer)&maClientData;
+ aStatusDrawCallback.callback = (XIMProc)StatusDrawCallback;
+ aStatusDrawCallback.client_data = (XPointer)&maClientData;
+
+ mpStatusAttributes = XVaCreateNestedList (
+ 0,
+ XNStatusStartCallback, &aStatusStartCallback,
+ XNStatusDoneCallback, &aStatusDoneCallback,
+ XNStatusDrawCallback, &aStatusDrawCallback,
+ NULL );
+
+ break;
+ }
+
+ case XIMStatusArea:
+ /* not supported */
+ break;
+
+ case XIMStatusNone:
+ case XIMStatusNothing:
+ default:
+ /* no arguments needed */
+ 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,
+ NULL );
+
+ break;
+
+ case XIMPreeditArea:
+ /* not supported */
+ break;
+
+ case XIMPreeditPosition:
+ {
+ // spot location
+ SalExtTextInputPosEvent aPosEvent;
+ pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent);
+
+ static XPoint aSpot;
+ aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth;
+ aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight;
+
+ // create attributes for preedit position style
+ mpPreeditAttributes = XVaCreateNestedList (
+ 0,
+ XNSpotLocation, &aSpot,
+ NULL );
+
+ // XCreateIC() fails on Redflag Linux 2.0 if there is no
+ // fontset though the data itself is not evaluated nor is
+ // it required according to the X specs.
+ Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+ XFontSet pFontSet = get_font_set(pDisplay);
+
+ if (pFontSet != NULL)
+ {
+ mpPreeditAttributes = XVaAddToNestedList( mpPreeditAttributes,
+ const_cast<char*>(XNFontSet), (XPointer)pFontSet);
+ }
+
+ break;
+ }
+
+ case XIMPreeditNone:
+ case XIMPreeditNothing:
+ default:
+ /* no arguments needed */
+ break;
+ }
+
+ // Create the InputContext by giving it exactly 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,
+ NULL );
+
+ if ( mnPreeditStyle != XIMPreeditNone )
+ {
+#if defined LINUX || defined FREEBSD || defined NETBSD
+ if ( mpPreeditAttributes != NULL )
+#endif
+ mpAttributes = XVaAddToNestedList( mpAttributes,
+ const_cast<char*>(XNPreeditAttributes), (XPointer)mpPreeditAttributes );
+ }
+ if ( mnStatusStyle != XIMStatusNone )
+ {
+#if defined LINUX || defined FREEBSD || defined NETBSD
+ if ( mpStatusAttributes != NULL )
+#endif
+ mpAttributes = XVaAddToNestedList( mpAttributes,
+ const_cast<char*>(XNStatusAttributes), (XPointer)mpStatusAttributes );
+ }
+ maContext = XCreateIC( pInputMethod->GetMethod(),
+ XNVaNestedList, mpAttributes,
+ NULL );
+ }
+
+ if ( maContext == NULL )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ 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 ( maClientData.aText.pUnicodeBuffer != NULL )
+ free ( maClientData.aText.pUnicodeBuffer );
+ if ( maClientData.aText.pCharStyle != NULL )
+ free ( maClientData.aText.pCharStyle );
+
+ mpAttributes = NULL;
+ mpStatusAttributes = NULL;
+ mpPreeditAttributes = NULL;
+ maClientData.aText.pUnicodeBuffer = NULL;
+ maClientData.aText.pCharStyle = NULL;
+ }
+
+ if ( maContext != NULL && mbMultiLingual )
+ {
+ maCommitStringCallback.callback = (XIMProc)::CommitStringCallback;
+ maCommitStringCallback.client_data = (XPointer)&maClientData;
+ maSwitchIMCallback.callback = (XIMProc)::SwitchIMCallback;
+ maSwitchIMCallback.client_data = (XPointer)&maClientData;
+ XSetICValues( maContext,
+ XNCommitStringCallback, &maCommitStringCallback,
+ XNSwitchIMNotifyCallback, &maSwitchIMCallback,
+ NULL );
+ }
+ if ( maContext != NULL)
+ {
+ maDestroyCallback.callback = (XIMProc)IC_IMDestroyCallback;
+ maDestroyCallback.client_data = (XPointer)this;
+ XSetICValues( maContext,
+ XNDestroyCallback, &maDestroyCallback,
+ NULL );
+ }
+
+ if( mbMultiLingual )
+ {
+ // set initial IM status
+ XIMUnicodeCharacterSubset* pSubset = NULL;
+ if( ! XGetICValues( maContext,
+ XNUnicodeCharacterSubset, & pSubset,
+ NULL )
+ && pSubset )
+ {
+ String aCurrent( ByteString( pSubset->name ), RTL_TEXTENCODING_UTF8 );
+ ::vcl::I18NStatus::get().changeIM( aCurrent );
+ ::vcl::I18NStatus::get().setStatusText( aCurrent );
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+//
+// In Solaris 8 the status window does not unmap if the frame unmapps, so
+// unmap it the hard way
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::Unmap( SalFrame* pFrame )
+{
+ if ( maContext != NULL )
+ {
+ I18NStatus& rStatus( I18NStatus::get() );
+ if( rStatus.getParent() == pFrame )
+ rStatus.show( false, I18NStatus::contextmap );
+
+ }
+ UnsetICFocus( pFrame );
+ maClientData.pFrame = NULL;
+}
+
+void
+SalI18N_InputContext::Map( SalFrame *pFrame )
+{
+ if( mbUseable )
+ {
+ I18NStatus& rStatus(I18NStatus::get() );
+ rStatus.setParent( pFrame );
+ if( pFrame )
+ {
+ rStatus.show( true, I18NStatus::contextmap );
+ if ( maContext == NULL )
+ {
+ SalI18N_InputMethod *pInputMethod;
+ pInputMethod = GetX11SalData()->GetDisplay()->GetInputMethod();
+
+ maContext = XCreateIC( pInputMethod->GetMethod(),
+ XNVaNestedList, mpAttributes,
+ NULL );
+ if ( maContext != NULL && mbMultiLingual )
+ XSetICValues( maContext,
+ XNCommitStringCallback, &maCommitStringCallback,
+ XNSwitchIMNotifyCallback, &maSwitchIMCallback,
+ NULL );
+ }
+ if( maClientData.pFrame != pFrame )
+ SetICFocus( pFrame );
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Handle DestroyCallbacks
+// in fact this is a callback called from the XNDestroyCallback
+//
+// --------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::HandleDestroyIM()
+{
+ maContext = 0; // noli me tangere
+ mbUseable = False;
+}
+
+// ---------------------------------------------------------------------------
+//
+// 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;
+ }
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ char pBuf[ 128 ];
+ fprintf( stderr, "selected inputmethod style = %s\n",
+ GetMethodName(mnPreeditStyle | mnStatusStyle, pBuf, sizeof(pBuf)) );
+#endif
+
+ return (mnPreeditStyle != 0) && (mnStatusStyle != 0) ;
+}
+
+// ---------------------------------------------------------------------------
+//
+// handle extended and normal key input
+//
+// ---------------------------------------------------------------------------
+
+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 );
+}
+
+int
+SalI18N_InputContext::CommitKeyEvent(sal_Unicode* pText, sal_Size nLength)
+{
+ if (nLength == 1 && IsControlCode(pText[0]))
+ return 0;
+
+ if( maClientData.pFrame )
+ {
+ SalExtTextInputEvent aTextEvent;
+
+ aTextEvent.mnTime = 0;
+ aTextEvent.mpTextAttr = 0;
+ aTextEvent.mnCursorPos = nLength;
+ aTextEvent.maText = UniString(pText, nLength);
+ aTextEvent.mnCursorFlags = 0;
+ aTextEvent.mnDeltaStart = 0;
+ aTextEvent.mbOnlyCursor = False;
+
+ maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aTextEvent);
+ maClientData.pFrame->CallCallback(SALEVENT_ENDEXTTEXTINPUT, (void*)NULL);
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf(stderr, "CommitKeyEvent without frame\n" );
+#endif
+
+ return 0;
+}
+
+int
+SalI18N_InputContext::UpdateSpotLocation()
+{
+ if (maContext == 0 || maClientData.pFrame == NULL)
+ return -1;
+
+ SalExtTextInputPosEvent aPosEvent;
+ maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent);
+
+ XPoint aSpot;
+ aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth;
+ aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight;
+
+ XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &aSpot, NULL);
+ XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL);
+ XFree(preedit_attr);
+
+ I18NStatus::get().show( true, I18NStatus::contextmap );
+
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+//
+// 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( SalFrame* pFocusFrame )
+{
+ I18NStatus::get().setParent( pFocusFrame );
+ if ( mbUseable && (maContext != NULL) )
+ {
+ maClientData.pFrame = pFocusFrame;
+
+ const SystemEnvData* pEnv = pFocusFrame->GetSystemData();
+ XLIB_Window aClientWindow = pEnv->aShellWindow;
+ XLIB_Window aFocusWindow = pEnv->aWindow;
+
+ XSetICValues( maContext,
+ XNFocusWindow, aFocusWindow,
+ XNClientWindow, aClientWindow,
+ NULL );
+
+ if( maClientData.aInputEv.mpTextAttr )
+ {
+ sendEmptyCommit(pFocusFrame);
+ // begin preedit again
+ GetX11SalData()->GetDisplay()->SendInternalEvent( pFocusFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
+ }
+
+ XSetICFocus( maContext );
+ }
+}
+
+void
+SalI18N_InputContext::UnsetICFocus( SalFrame* pFrame )
+{
+ I18NStatus& rStatus( I18NStatus::get() );
+ if( rStatus.getParent() == pFrame )
+ rStatus.setParent( NULL );
+
+ if ( mbUseable && (maContext != NULL) )
+ {
+ // cancel an eventual event posted to begin preedit again
+ GetX11SalData()->GetDisplay()->CancelInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
+ maClientData.pFrame = NULL;
+ XUnsetICFocus( maContext );
+ }
+}
+
+// ---------------------------------------------------------------------------
+//
+// multi byte input method only
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::SetPreeditState(Bool aPreeditState)
+{
+ XIMPreeditState preedit_state = XIMPreeditUnKnown;
+ XVaNestedList preedit_attr;
+
+ preedit_attr = XVaCreateNestedList(
+ 0,
+ XNPreeditState, &preedit_state,
+ NULL);
+ if (!XGetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL))
+ {
+ XFree(preedit_attr);
+
+ preedit_state = aPreeditState? XIMPreeditEnable : XIMPreeditDisable;
+ preedit_attr = XVaCreateNestedList(
+ 0,
+ XNPreeditState, preedit_state,
+ NULL);
+ XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL);
+ }
+
+ XFree(preedit_attr);
+
+ return;
+}
+
+void
+SalI18N_InputContext::SetLanguage(LanguageType)
+{
+ // not yet implemented
+ return;
+}
+
+void
+SalI18N_InputContext::EndExtTextInput( USHORT /*nFlags*/ )
+{
+ if ( mbUseable && (maContext != NULL) && maClientData.pFrame )
+ {
+ vcl::DeletionListener aDel( maClientData.pFrame );
+ // delete preedit in sal (commit an empty string)
+ sendEmptyCommit( maClientData.pFrame );
+ if( ! aDel.isDeleted() )
+ {
+ // mark previous preedit state again (will e.g. be sent at focus gain)
+ maClientData.aInputEv.mpTextAttr = &maClientData.aInputFlags[0];
+ if( static_cast<X11SalFrame*>(maClientData.pFrame)->hasFocus() )
+ {
+ // begin preedit again
+ GetX11SalData()->GetDisplay()->SendInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ }
+}
+
+
diff --git a/vcl/unx/generic/app/i18n_im.cxx b/vcl/unx/generic/app/i18n_im.cxx
new file mode 100644
index 000000000000..176212f681d5
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_im.cxx
@@ -0,0 +1,619 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef LINUX
+# ifndef __USE_XOPEN
+# define __USE_XOPEN
+# endif
+#endif
+#include <poll.h>
+
+#include <tools/prex.h>
+#include <X11/Xlocale.h>
+#include <X11/Xlib.h>
+#include <unx/XIM.h>
+#include <tools/postx.h>
+
+#include "unx/salunx.h"
+#include "unx/saldisp.hxx"
+#include "unx/i18n_im.hxx"
+#include "unx/i18n_status.hxx"
+
+#include <osl/thread.h>
+#include <osl/process.h>
+
+using namespace vcl;
+#include "unx/i18n_cb.hxx"
+#if defined(SOLARIS) || defined(LINUX)
+extern "C" char * XSetIMValues(XIM im, ...);
+#endif
+
+// ------------------------------------------------------------------------------------
+//
+// kinput2 IME needs special key handling since key release events are filtered in
+// preeditmode and XmbResetIC does not work
+//
+// ------------------------------------------------------------------------------------
+
+Bool
+IMServerKinput2 ()
+{
+ const static char* p_xmodifiers = getenv ("XMODIFIERS");
+ const static Bool b_kinput2 = (p_xmodifiers != NULL)
+ && (strcmp(p_xmodifiers, "@im=kinput2") == 0);
+
+ return b_kinput2;
+}
+
+class XKeyEventOp : XKeyEvent
+{
+ private:
+ void init();
+
+ public:
+ XKeyEventOp();
+ ~XKeyEventOp();
+
+ XKeyEventOp& operator= (const XKeyEvent &rEvent);
+ void erase ();
+ Bool match (const XKeyEvent &rEvent) const;
+};
+
+void
+XKeyEventOp::init()
+{
+ type = 0; /* serial = 0; */
+ send_event = 0; display = 0;
+ window = 0; root = 0;
+ subwindow = 0; /* time = 0; */
+ /* x = 0; y = 0; */
+ /* x_root = 0; y_root = 0; */
+ state = 0; keycode = 0;
+ same_screen = 0;
+}
+
+XKeyEventOp::XKeyEventOp()
+{
+ init();
+}
+
+XKeyEventOp::~XKeyEventOp()
+{
+}
+
+XKeyEventOp&
+XKeyEventOp::operator= (const XKeyEvent &rEvent)
+{
+ type = rEvent.type; /* serial = rEvent.serial; */
+ send_event = rEvent.send_event; display = rEvent.display;
+ window = rEvent.window; root = rEvent.root;
+ subwindow = rEvent.subwindow;/* time = rEvent.time; */
+ /* x = rEvent.x, y = rEvent.y; */
+ /* x_root = rEvent.x_root, y_root = rEvent.y_root; */
+ state = rEvent.state; keycode = rEvent.keycode;
+ same_screen = rEvent.same_screen;
+
+ return *this;
+}
+
+void
+XKeyEventOp::erase ()
+{
+ init();
+}
+
+Bool
+XKeyEventOp::match (const XKeyEvent &rEvent) const
+{
+ return ( (type == XLIB_KeyPress && rEvent.type == KeyRelease)
+ || (type == KeyRelease && rEvent.type == XLIB_KeyPress ))
+ /* && serial == rEvent.serial */
+ && send_event == rEvent.send_event
+ && display == rEvent.display
+ && window == rEvent.window
+ && root == rEvent.root
+ && subwindow == rEvent.subwindow
+ /* && time == rEvent.time
+ && x == rEvent.x
+ && y == rEvent.y
+ && x_root == rEvent.x_root
+ && y_root == rEvent.y_root */
+ && state == rEvent.state
+ && keycode == rEvent.keycode
+ && same_screen == rEvent.same_screen;
+}
+
+// -------------------------------------------------------------------------
+//
+// locale handling
+//
+// -------------------------------------------------------------------------
+
+// Locale handling of the operating system layer
+
+static char*
+SetSystemLocale( const char* p_inlocale )
+{
+ char *p_outlocale;
+
+ if ( (p_outlocale = setlocale(LC_ALL, p_inlocale)) == NULL )
+ {
+ fprintf( stderr, "I18N: Operating system doesn't support locale \"%s\"\n",
+ p_inlocale );
+ }
+
+ return p_outlocale;
+}
+
+#ifdef SOLARIS
+static void
+SetSystemEnvironment( const rtl::OUString& rLocale )
+{
+ rtl::OUString LC_ALL_Var(RTL_CONSTASCII_USTRINGPARAM("LC_ALL"));
+ osl_setEnvironment(LC_ALL_Var.pData, rLocale.pData);
+
+ rtl::OUString LANG_Var(RTL_CONSTASCII_USTRINGPARAM("LANG"));
+ osl_setEnvironment(LANG_Var.pData, rLocale.pData);
+}
+#endif
+
+static Bool
+IsPosixLocale( const char* p_locale )
+{
+ if ( p_locale == NULL )
+ return False;
+ if ( (p_locale[ 0 ] == 'C') && (p_locale[ 1 ] == '\0') )
+ return True;
+ if ( strncmp(p_locale, "POSIX", sizeof("POSIX")) == 0 )
+ return True;
+
+ return False;
+}
+
+// Locale handling of the X Window System layer
+
+static Bool
+IsXWindowCompatibleLocale( const char* p_locale )
+{
+ if ( p_locale == NULL )
+ return False;
+
+ if ( !XSupportsLocale() )
+ {
+ fprintf (stderr, "I18N: X Window System doesn't support locale \"%s\"\n",
+ p_locale );
+ return False;
+ }
+ return True;
+}
+
+// Set the operating system locale prior to trying to open an
+// XIM InputMethod.
+// Handle the cases where the current locale is either not supported by the
+// operating system (LANG=gaga) or by the XWindow system (LANG=aa_ER@saaho)
+// by providing a fallback.
+// Upgrade "C" or "POSIX" to "en_US" locale to allow umlauts and accents
+// see i8988, i9188, i8930, i16318
+// on Solaris the environment needs to be set equivalent to the locale (#i37047#)
+
+Bool
+SalI18N_InputMethod::SetLocale( const char* pLocale )
+{
+ // check whether we want an Input Method engine, if we don't we
+ // do not need to set the locale
+ if ( mbUseable )
+ {
+ char *locale = SetSystemLocale( pLocale );
+ if ( (!IsXWindowCompatibleLocale(locale)) || IsPosixLocale(locale) )
+ {
+ osl_setThreadTextEncoding (RTL_TEXTENCODING_ISO_8859_1);
+ locale = SetSystemLocale( "en_US" );
+ #ifdef SOLARIS
+ SetSystemEnvironment( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en_US")) );
+ #endif
+ if (! IsXWindowCompatibleLocale(locale))
+ {
+ locale = SetSystemLocale( "C" );
+ #ifdef SOLARIS
+ SetSystemEnvironment( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("C")) );
+ #endif
+ if (! IsXWindowCompatibleLocale(locale))
+ mbUseable = False;
+ }
+ }
+
+ // must not fail if mbUseable since XSupportsLocale() asserts success
+ if ( mbUseable && XSetLocaleModifiers("") == NULL )
+ {
+ fprintf (stderr, "I18N: Can't set X modifiers for locale \"%s\"\n",
+ locale);
+ mbUseable = False;
+ }
+ }
+
+ return mbUseable;
+}
+
+Bool
+SalI18N_InputMethod::PosixLocale()
+{
+ if (mbMultiLingual)
+ return False;
+ if (maMethod)
+ return IsPosixLocale (XLocaleOfIM (maMethod));
+ return False;
+}
+
+// ------------------------------------------------------------------------
+//
+// Constructor / Destructor / Initialisation
+//
+// ------------------------------------------------------------------------
+
+SalI18N_InputMethod::SalI18N_InputMethod( ) : mbUseable( bUseInputMethodDefault ),
+ mbMultiLingual( False ),
+ maMethod( (XIM)NULL ),
+ mpStyles( (XIMStyles*)NULL )
+{
+ const char *pUseInputMethod = getenv( "SAL_USEINPUTMETHOD" );
+ if ( pUseInputMethod != NULL )
+ mbUseable = pUseInputMethod[0] != '\0' ;
+}
+
+SalI18N_InputMethod::~SalI18N_InputMethod()
+{
+ ::vcl::I18NStatus::free();
+ if ( mpStyles != NULL )
+ XFree( mpStyles );
+ if ( maMethod != NULL )
+ XCloseIM ( maMethod );
+}
+
+//
+// XXX
+// debug routine: lets have a look at the provided method styles
+//
+
+#if OSL_DEBUG_LEVEL > 1
+
+extern "C" char*
+GetMethodName( XIMStyle nStyle, char *pBuf, int nBufSize)
+{
+ struct StyleName {
+ const XIMStyle nStyle;
+ const char *pName;
+ const int nNameLen;
+ };
+
+ StyleName *pDescPtr;
+ static const StyleName pDescription[] = {
+ { XIMPreeditArea, "PreeditArea ", sizeof("PreeditArea ") },
+ { XIMPreeditCallbacks, "PreeditCallbacks ",sizeof("PreeditCallbacks ")},
+ { XIMPreeditPosition, "PreeditPosition ", sizeof("PreeditPosition ") },
+ { XIMPreeditNothing, "PreeditNothing ", sizeof("PreeditNothing ") },
+ { XIMPreeditNone, "PreeditNone ", sizeof("PreeditNone ") },
+ { XIMStatusArea, "StatusArea ", sizeof("StatusArea ") },
+ { XIMStatusCallbacks, "StatusCallbacks ", sizeof("StatusCallbacks ") },
+ { XIMStatusNothing, "StatusNothing ", sizeof("StatusNothing ") },
+ { XIMStatusNone, "StatusNone ", sizeof("StatusNone ") },
+ { 0, "NULL", 0 }
+ };
+
+ if ( nBufSize > 0 )
+ pBuf[0] = '\0';
+
+ char *pBufPtr = pBuf;
+ for ( pDescPtr = const_cast<StyleName*>(pDescription); pDescPtr->nStyle != 0; pDescPtr++ )
+ {
+ int nSize = pDescPtr->nNameLen - 1;
+ if ( (nStyle & pDescPtr->nStyle) && (nBufSize > nSize) )
+ {
+ strncpy( pBufPtr, pDescPtr->pName, nSize + 1);
+ pBufPtr += nSize;
+ nBufSize -= nSize;
+ }
+ }
+
+ return pBuf;
+}
+
+extern "C" void
+PrintInputStyle( XIMStyles *pStyle )
+{
+ char pBuf[ 128 ];
+ int nBuf = sizeof( pBuf );
+
+ if ( pStyle == NULL )
+ fprintf( stderr, "no input method styles\n");
+ else
+ for ( int nStyle = 0; nStyle < pStyle->count_styles; nStyle++ )
+ {
+ fprintf( stderr, "style #%i = %s\n", nStyle,
+ GetMethodName(pStyle->supported_styles[nStyle], pBuf, nBuf) );
+ }
+}
+
+#endif
+
+//
+// this is the real constructing routine, since locale setting has to be done
+// prior to xopendisplay, the xopenim call has to be delayed
+//
+
+Bool
+SalI18N_InputMethod::CreateMethod ( Display *pDisplay )
+{
+ if ( mbUseable )
+ {
+ const bool bTryMultiLingual =
+ #ifdef LINUX
+ false;
+ #else
+ true;
+ #endif
+ if ( bTryMultiLingual && getenv("USE_XOPENIM") == NULL )
+ {
+ mbMultiLingual = True; // set ml-input flag to create input-method
+ maMethod = XvaOpenIM(pDisplay, NULL, NULL, NULL,
+ XNMultiLingualInput, mbMultiLingual, /* dummy */
+ (void *)0);
+ // get ml-input flag from input-method
+ if ( maMethod == (XIM)NULL )
+ mbMultiLingual = False;
+ else
+ if ( XGetIMValues(maMethod,
+ XNMultiLingualInput, &mbMultiLingual, NULL ) != NULL )
+ mbMultiLingual = False;
+ if( mbMultiLingual )
+ {
+ XIMUnicodeCharacterSubsets* subsets;
+ if( XGetIMValues( maMethod,
+ XNQueryUnicodeCharacterSubset, &subsets, NULL ) == NULL )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "IM reports %d subsets: ", subsets->count_subsets );
+#endif
+ I18NStatus& rStatus( I18NStatus::get() );
+ rStatus.clearChoices();
+ for( int i = 0; i < subsets->count_subsets; i++ )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"\"%s\" ", subsets->supported_subsets[i].name );
+#endif
+ rStatus.addChoice( String( subsets->supported_subsets[i].name, RTL_TEXTENCODING_UTF8 ), &subsets->supported_subsets[i] );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "\n" );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "query subsets failed\n" );
+#endif
+ }
+ }
+ else
+ {
+ maMethod = XOpenIM(pDisplay, NULL, NULL, NULL);
+ mbMultiLingual = False;
+ }
+
+ if ((maMethod == (XIM)NULL) && (getenv("XMODIFIERS") != NULL))
+ {
+ rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("XMODIFIERS"));
+ osl_clearEnvironment(envVar.pData);
+ XSetLocaleModifiers("");
+ maMethod = XOpenIM(pDisplay, NULL, NULL, NULL);
+ mbMultiLingual = False;
+ }
+
+ if ( maMethod != (XIM)NULL )
+ {
+ if ( XGetIMValues(maMethod, XNQueryInputStyle, &mpStyles, NULL)
+ != NULL)
+ mbUseable = False;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "Creating %s-Lingual InputMethod\n",
+ mbMultiLingual ? "Multi" : "Mono" );
+ PrintInputStyle( mpStyles );
+ #endif
+ }
+ else
+ {
+ mbUseable = False;
+ }
+ }
+
+ #if OSL_DEBUG_LEVEL > 1
+ if ( !mbUseable )
+ fprintf(stderr, "input method creation failed\n");
+ #endif
+
+ maDestroyCallback.callback = (XIMProc)IM_IMDestroyCallback;
+ maDestroyCallback.client_data = (XPointer)this;
+ if (mbUseable && maMethod != NULL)
+ XSetIMValues(maMethod, XNDestroyCallback, &maDestroyCallback, NULL);
+
+ return mbUseable;
+}
+
+//
+// give IM the opportunity to look at the event, and possibly hide it
+//
+
+Bool
+SalI18N_InputMethod::FilterEvent( XEvent *pEvent, XLIB_Window window )
+{
+ if (!mbUseable)
+ return False;
+
+ Bool bFilterEvent = XFilterEvent (pEvent, window);
+
+ if (pEvent->type != XLIB_KeyPress && pEvent->type != KeyRelease)
+ return bFilterEvent;
+
+ /*
+ * fix broken key release handling of some IMs
+ */
+ XKeyEvent* pKeyEvent = &(pEvent->xkey);
+ static XKeyEventOp maLastKeyPress;
+
+ if (bFilterEvent)
+ {
+ if (pKeyEvent->type == KeyRelease)
+ bFilterEvent = !maLastKeyPress.match (*pKeyEvent);
+ maLastKeyPress.erase();
+ }
+ else /* (!bFilterEvent) */
+ {
+ if (pKeyEvent->type == XLIB_KeyPress)
+ maLastKeyPress = *pKeyEvent;
+ else
+ maLastKeyPress.erase();
+ }
+
+ return bFilterEvent;
+}
+
+void
+SalI18N_InputMethod::HandleDestroyIM()
+{
+ mbUseable = False;
+ mbMultiLingual = False;
+ maMethod = NULL;
+}
+
+// ------------------------------------------------------------------------
+//
+// add a connection watch into the SalXLib yieldTable to allow iiimp
+// connection processing: soffice waits in select() not in XNextEvent(), so
+// there may be requests pending on the iiimp internal connection that will
+// not be processed until XNextEvent is called the next time. If we do not
+// have the focus because the atok12 lookup choice aux window has it we stay
+// deaf and dump otherwise.
+//
+// ------------------------------------------------------------------------
+
+int
+InputMethod_HasPendingEvent(int nFileDescriptor, void *pData)
+{
+ if (pData == NULL)
+ return 0;
+
+ struct pollfd aFileDescriptor;
+ #ifdef SOLARIS
+ nfds_t nNumDescriptor = 1;
+ #else
+ unsigned int nNumDescriptor = 1;
+ #endif
+ aFileDescriptor.fd = nFileDescriptor;
+ aFileDescriptor.events = POLLRDNORM;
+ aFileDescriptor.revents = 0;
+
+ int nPoll = poll (&aFileDescriptor, nNumDescriptor, 0 /* timeout */ );
+
+ if (nPoll > 0)
+ {
+ /* at least some conditions in revent are set */
+ if ( (aFileDescriptor.revents & POLLHUP)
+ || (aFileDescriptor.revents & POLLERR)
+ || (aFileDescriptor.revents & POLLNVAL))
+ return 0; /* oops error condition set */
+
+ if (aFileDescriptor.revents & POLLRDNORM)
+ return 1; /* success */
+ }
+
+ /* nPoll == 0 means timeout, nPoll < 0 means error */
+ return 0;
+}
+
+int
+InputMethod_IsEventQueued(int nFileDescriptor, void *pData)
+{
+ return InputMethod_HasPendingEvent (nFileDescriptor, pData);
+}
+
+int
+InputMethod_HandleNextEvent(int nFileDescriptor, void *pData)
+{
+ if (pData != NULL)
+ XProcessInternalConnection((Display*)pData, nFileDescriptor);
+
+ return 0;
+}
+
+extern "C" void
+InputMethod_ConnectionWatchProc (Display *pDisplay, XPointer pClientData,
+ int nFileDescriptor, Bool bOpening, XPointer*)
+{
+ SalXLib *pConnectionHandler = (SalXLib*)pClientData;
+
+ if (pConnectionHandler == NULL)
+ return;
+
+ if (bOpening)
+ {
+ pConnectionHandler->Insert (nFileDescriptor, pDisplay,
+ InputMethod_HasPendingEvent,
+ InputMethod_IsEventQueued,
+ InputMethod_HandleNextEvent);
+ }
+ else
+ {
+ pConnectionHandler->Remove (nFileDescriptor);
+ }
+}
+
+Bool
+SalI18N_InputMethod::AddConnectionWatch(Display *pDisplay, void *pConnectionHandler)
+{
+ // sanity check
+ if (pDisplay == NULL || pConnectionHandler == NULL)
+ return False;
+
+ // if we are not ml all the extended text input comes on the stock X queue,
+ // so there is no need to monitor additional file descriptors.
+#ifndef SOLARIS
+ if (!mbMultiLingual || !mbUseable)
+ return False;
+#endif
+
+ // pConnectionHandler must be really a pointer to a SalXLib
+ Status nStatus = XAddConnectionWatch (pDisplay, InputMethod_ConnectionWatchProc,
+ (XPointer)pConnectionHandler);
+ return (Bool)nStatus;
+}
+
+
+
diff --git a/vcl/unx/generic/app/i18n_keysym.cxx b/vcl/unx/generic/app/i18n_keysym.cxx
new file mode 100644
index 000000000000..122a88517baf
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_keysym.cxx
@@ -0,0 +1,365 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <X11/X.h>
+#include <sal/types.h>
+
+#include <unx/i18n_keysym.hxx>
+
+// convert keysyms to unicode
+// for all keysyms with byte1 and byte2 equal zero, and of course only for
+// keysyms that have a unicode counterpart
+
+typedef const sal_Unicode unicode_t;
+typedef struct {
+ const int first; const int last;
+ unicode_t *map;
+} keymap_t;
+
+// Latin-1 Byte 3 = 0x00
+unicode_t keymap00_map[] = {
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff };
+const keymap_t keymap00 = { 32, 255, keymap00_map };
+
+// Latin-2 Byte 3 = 0x01
+unicode_t keymap01_map[] = {
+ 0x0104, 0x02d8, 0x0141, 0x0000, 0x013d, 0x015a, 0x0000, 0x0000,
+ 0x0160, 0x015e, 0x0164, 0x0179, 0x0000, 0x017d, 0x017b, 0x0000,
+ 0x0105, 0x02db, 0x0142, 0x0000, 0x013e, 0x015b, 0x02c7, 0x0000,
+ 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, 0x0154,
+ 0x0000, 0x0000, 0x0102, 0x0000, 0x0139, 0x0106, 0x0000, 0x010c,
+ 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x0000, 0x010e, 0x0110,
+ 0x0143, 0x0147, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000, 0x0158,
+ 0x016e, 0x0000, 0x0170, 0x0000, 0x0000, 0x0162, 0x0000, 0x0155,
+ 0x0000, 0x0000, 0x0103, 0x0000, 0x013a, 0x0107, 0x0000, 0x010d,
+ 0x0000, 0x0119, 0x0000, 0x011b, 0x0000, 0x0000, 0x010f, 0x0111,
+ 0x0144, 0x0148, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, 0x0159,
+ 0x016f, 0x0000, 0x0171, 0x0000, 0x0000, 0x0163, 0x02d9 };
+const keymap_t keymap01 = { 161, 255, keymap01_map };
+
+// Latin-3 Byte 3 = 0x02
+unicode_t keymap02_map[] = {
+ 0x0126, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0000, 0x0000,
+ 0x0130, 0x0000, 0x011e, 0x0134, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0127, 0x0000, 0x0000, 0x0000, 0x0000, 0x0125, 0x0000, 0x0000,
+ 0x0131, 0x0000, 0x011f, 0x0135, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x010a, 0x0108, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0120, 0x0000, 0x0000, 0x011c,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x015c, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x010b, 0x0109, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0121, 0x0000, 0x0000, 0x011d,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x015d };
+const keymap_t keymap02 = { 161, 254, keymap02_map };
+
+// Latin-4 Byte 3 = 0x03
+unicode_t keymap03_map[] = {
+ 0x0138, 0x0156, 0x0000, 0x0128, 0x013b, 0x0000, 0x0000, 0x0000,
+ 0x0112, 0x0122, 0x0166, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0157, 0x0000, 0x0129, 0x013c, 0x0000, 0x0000, 0x0000,
+ 0x0113, 0x0123, 0x0167, 0x014a, 0x0000, 0x014b, 0x0100, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012e, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0116, 0x0000, 0x0000, 0x012a, 0x0000, 0x0145,
+ 0x014c, 0x0136, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0172,
+ 0x0000, 0x0000, 0x0000, 0x0168, 0x016a, 0x0000, 0x0101, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012f, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0117, 0x0000, 0x0000, 0x012b, 0x0000, 0x0146,
+ 0x014d, 0x0137, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0173,
+ 0x0000, 0x0000, 0x0000, 0x0169, 0x016b };
+const keymap_t keymap03 = { 162, 254, keymap03_map };
+
+// Kana Byte 3 = 0x04
+unicode_t keymap04_map[] = {
+ 0x203e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb,
+ 0x30f2, 0x30a1, 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5,
+ 0x30e7, 0x30c3, 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa,
+ 0x30ab, 0x30ad, 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9,
+ 0x30bb, 0x30bd, 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca,
+ 0x30cb, 0x30cc, 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8,
+ 0x30db, 0x30de, 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6,
+ 0x30e8, 0x30e9, 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3,
+ 0x309b, 0x309c };
+const keymap_t keymap04 = { 126, 223, keymap04_map };
+
+// Arabic Byte 3 = 0x05
+unicode_t keymap05_map[] = {
+ 0x060c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x061b,
+ 0x0000, 0x0000, 0x0000, 0x061f, 0x0000, 0x0621, 0x0622, 0x0623,
+ 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062a, 0x062b,
+ 0x062c, 0x062d, 0x062e, 0x062f, 0x0630, 0x0631, 0x0632, 0x0633,
+ 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063a, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0640, 0x0641, 0x0642, 0x0643,
+ 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064a, 0x064b,
+ 0x064c, 0x064d, 0x064e, 0x064f, 0x0650, 0x0651, 0x0652 };
+const keymap_t keymap05 = { 172, 242, keymap05_map };
+
+// Cyrillic Byte 3 = 0x06
+unicode_t keymap06_map[] = {
+ 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458,
+ 0x0459, 0x045a, 0x045b, 0x045c, 0x0000, 0x045e, 0x045f, 0x2116,
+ 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408,
+ 0x0409, 0x040a, 0x040b, 0x040c, 0x0000, 0x040e, 0x040f, 0x044e,
+ 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044c,
+ 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, 0x042e,
+ 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425,
+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+ 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c,
+ 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a };
+const keymap_t keymap06 = { 161, 255, keymap06_map };
+
+// Greek Byte 3 = 0x07
+unicode_t keymap07_map[] = {
+ 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, 0x038e,
+ 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, 0x0000,
+ 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, 0x03cd,
+ 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
+ 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0,
+ 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8,
+ 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8,
+ 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0,
+ 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8,
+ 0x03c9 };
+const keymap_t keymap07 = { 161, 249, keymap07_map };
+
+// Technical Byte 3 = 0x08
+unicode_t keymap08_map[] = {
+ 0x23b7, 0x250c, 0x2500, 0x2320, 0x2321, 0x2502, 0x23a1, 0x23a3,
+ 0x23a4, 0x23a6, 0x239b, 0x239d, 0x239e, 0x23a0, 0x23a8, 0x23ac,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222b, 0x2234,
+ 0x221d, 0x221e, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, 0x223c,
+ 0x2243, 0x0000, 0x0000, 0x0000, 0x21d4, 0x21d2, 0x2261, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221a, 0x0000, 0x0000,
+ 0x0000, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193 };
+const keymap_t keymap08 = { 161, 254, keymap08_map };
+
+// Special Byte 3 = 0x09
+unicode_t keymap09_map[] = {
+ 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x0000, 0x0000,
+ 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
+ 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
+ 0x2502 };
+const keymap_t keymap09 = { 224, 248, keymap09_map };
+
+// Publishing Byte 3 = 0x0a = 10
+unicode_t keymap10_map[] = {
+ 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, 0x200a,
+ 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, 0x2153,
+ 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x2105,
+ 0x0000, 0x0000, 0x2012, 0x2329, 0x0000, 0x232a, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, 0x0000,
+ 0x2122, 0x2613, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25af, 0x2018,
+ 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033, 0x0000,
+ 0x271d, 0x0000, 0x25ac, 0x25c0, 0x25b6, 0x25cf, 0x25ae, 0x25e6,
+ 0x25ab, 0x25ad, 0x25b3, 0x25bd, 0x2606, 0x2022, 0x25aa, 0x25b2,
+ 0x25bc, 0x261c, 0x261e, 0x2663, 0x2666, 0x2665, 0x0000, 0x2720,
+ 0x2020, 0x2021, 0x2713, 0x2717, 0x266f, 0x266d, 0x2642, 0x2640,
+ 0x260e, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e };
+const keymap_t keymap10 = { 161, 254, keymap10_map };
+
+// APL Byte 3 = 0x0b = 11
+unicode_t keymap11_map[] = {
+ 0x003c, 0x0000, 0x0000, 0x003e, 0x0000, 0x2228, 0x2227, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00af, 0x0000, 0x22a5,
+ 0x2229, 0x230a, 0x0000, 0x005f, 0x0000, 0x0000, 0x0000, 0x2218,
+ 0x0000, 0x2395, 0x0000, 0x22a4, 0x25cb, 0x0000, 0x0000, 0x0000,
+ 0x2308, 0x0000, 0x0000, 0x222a, 0x0000, 0x2283, 0x0000, 0x2282,
+ 0x0000, 0x22a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x22a3 };
+const keymap_t keymap11 = { 163, 252, keymap11_map };
+
+// Hebrew Byte 3 = 0x0c = 12
+unicode_t keymap12_map[] = {
+ 0x2017, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6,
+ 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de,
+ 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6,
+ 0x05e7, 0x05e8, 0x05e9, 0x05ea };
+const keymap_t keymap12 = { 223, 250, keymap12_map };
+
+// Thai Byte 3 = 0x0d = 13
+unicode_t keymap13_map[] = {
+ 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, 0x0e08,
+ 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, 0x0e10,
+ 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, 0x0e18,
+ 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, 0x0e20,
+ 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, 0x0e28,
+ 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, 0x0e30,
+ 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, 0x0e38,
+ 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e3f, 0x0e40,
+ 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, 0x0e48,
+ 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0000, 0x0000, 0x0e50,
+ 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, 0x0e58,
+ 0x0e59 };
+const keymap_t keymap13 = { 161, 249, keymap13_map };
+
+// Korean Byte 3 = 0x0e = 14
+unicode_t keymap14_map[] = {
+ 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138,
+ 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f, 0x3140,
+ 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147, 0x3148,
+ 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x314f, 0x3150,
+ 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156, 0x3157, 0x3158,
+ 0x3159, 0x315a, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160,
+ 0x3161, 0x3162, 0x3163, 0x11a8, 0x11a9, 0x11aa, 0x11ab, 0x11ac,
+ 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4,
+ 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, 0x11bc,
+ 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x316d, 0x3171,
+ 0x3178, 0x317f, 0x3181, 0x3184, 0x3186, 0x318d, 0x318e, 0x11eb,
+ 0x11f0, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9 };
+const keymap_t keymap14 = { 161, 255, keymap14_map };
+
+// missing:
+// Latin-8 Byte 3 = 0x12 = 18
+
+// Latin-9 Byte 3 = 0x13 = 19
+unicode_t keymap19_map[] = {
+ 0x0152, 0x0153, 0x0178 };
+const keymap_t keymap19 = { 188, 190, keymap19_map };
+
+// missing:
+// Armenian Byte 3 = 0x14 = 20
+// Georgian Byte 3 = 0x15 = 21
+// Azeri Byte 3 = 0x16 = 22
+// Vietnamese Byte 3 = 0x1e = 30
+
+// Currency Byte 3 = 0x20 = 32
+unicode_t keymap32_map[] = {
+ 0x20a0, 0x20a1, 0x20a2, 0x20a3, 0x20a4, 0x20a5, 0x20a6, 0x20a7,
+ 0x20a8, 0x0000, 0x20aa, 0x20ab, 0x20ac };
+const keymap_t keymap32 = { 160, 172, keymap32_map };
+
+// Keyboard (Keypad mappings) Byte 3 = 0xff = 255
+unicode_t keymap255_map[] = {
+ 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x0000, 0x0000, 0x0000, 0x003d };
+const keymap_t keymap255 = { 128, 189, keymap255_map };
+
+#define INITIAL_KEYMAPS 33
+const keymap_t* p_keymap[INITIAL_KEYMAPS] = {
+ &keymap00, &keymap01, &keymap02, &keymap03, /* 00 -- 03 */
+ &keymap04, &keymap05, &keymap06, &keymap07, /* 04 -- 07 */
+ &keymap08, &keymap09, &keymap10, &keymap11, /* 08 -- 11 */
+ &keymap12, &keymap13, &keymap14, (keymap_t*)NULL, /* 12 -- 15 */
+ (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, &keymap19, /* 16 -- 19 */
+ (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, /* 20 -- 23 */
+ (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, /* 24 -- 27 */
+ (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, /* 28 -- 31 */
+ &keymap32 /* 32 */
+};
+
+sal_Unicode
+KeysymToUnicode (KeySym nKeySym)
+{
+ // keysym is already unicode
+ if ((nKeySym & 0xff000000) == 0x01000000)
+ {
+ // strip off group indicator and iso10646 plane
+ // FIXME can't handle chars from surrogate area.
+ if (! (nKeySym & 0x00ff0000) )
+ return (sal_Unicode)(nKeySym & 0x0000ffff);
+ }
+ // legacy keysyms, switch to appropriate codeset
+ else
+ {
+ unsigned char n_byte1 = (nKeySym & 0xff000000) >> 24;
+ unsigned char n_byte2 = (nKeySym & 0x00ff0000) >> 16;
+ unsigned char n_byte3 = (nKeySym & 0x0000ff00) >> 8;
+ unsigned char n_byte4 = (nKeySym & 0x000000ff);
+
+ if (n_byte1 != 0)
+ return 0;
+ if (n_byte2 != 0)
+ return 0;
+
+ keymap_t const* p_map = NULL;
+ if (n_byte3 < INITIAL_KEYMAPS)
+ p_map = p_keymap[n_byte3];
+ else
+ if (n_byte3 == 255)
+ p_map = &keymap255;
+
+ if ((p_map != NULL) && (n_byte4 >= p_map->first) && (n_byte4 <= p_map->last) )
+ return p_map->map[n_byte4 - p_map->first];
+ }
+
+ return 0;
+}
diff --git a/vcl/unx/generic/app/i18n_status.cxx b/vcl/unx/generic/app/i18n_status.cxx
new file mode 100644
index 000000000000..76193f0ef842
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_status.cxx
@@ -0,0 +1,733 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+#include <sal/alloca.h>
+
+#include <tools/prex.h>
+#include <X11/Xlib.h>
+#include <unx/XIM.h>
+#include <tools/postx.h>
+
+#include <unx/salunx.h>
+#include <unx/i18n_status.hxx>
+#include <unx/i18n_ic.hxx>
+#include <unx/saldisp.hxx>
+#include <unx/salframe.h>
+#include <unx/saldata.hxx>
+
+#include <vcl/wrkwin.hxx>
+#include <vcl/fixed.hxx>
+#include <vcl/menubtn.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/sysdata.hxx>
+
+#include <svdata.hxx>
+
+using namespace vcl;
+using namespace rtl;
+
+namespace vcl {
+
+class StatusWindow : public WorkWindow
+{
+protected:
+ StatusWindow( WinBits nWinBits );
+public:
+ virtual ~StatusWindow();
+
+ virtual void setPosition( SalFrame* );
+ virtual void setText( const String & ) = 0;
+ virtual String getText() const = 0;
+ virtual void show( bool bShow, I18NStatus::ShowReason eReason ) = 0;
+ virtual void toggle( bool bOn ) = 0;
+};
+
+}
+
+StatusWindow::StatusWindow( WinBits nWinBits ) :
+ WorkWindow( NULL, nWinBits )
+{
+}
+
+StatusWindow::~StatusWindow() {}
+
+void StatusWindow::setPosition( SalFrame* )
+{
+}
+
+// --------------------------------------------------------------------------
+
+namespace vcl {
+
+class XIMStatusWindow : public StatusWindow
+{
+ FixedText m_aStatusText;
+ SalFrame* m_pLastParent;
+ Size m_aWindowSize;
+ bool m_bAnchoredAtRight;
+ // true if the right edge (instead of the left edge) should stay at a
+ // fixed position when re-sizing the window
+
+ // for delayed showing
+ bool m_bDelayedShow;
+ I18NStatus::ShowReason m_eDelayedReason;
+ ULONG m_nDelayedEvent;
+ // for toggling
+ bool m_bOn;
+
+ Point updatePosition();
+ void layout();
+ bool checkLastParent() const;
+
+ DECL_LINK( DelayedShowHdl, void* );
+public:
+ XIMStatusWindow( bool bOn );
+ virtual ~XIMStatusWindow();
+
+ virtual void setPosition( SalFrame* );
+ virtual void setText( const String & );
+ virtual String getText() const;
+ virtual void show( bool bShow, I18NStatus::ShowReason eReason );
+ virtual void toggle( bool bOn );
+
+ // overload WorkWindow::DataChanged
+ virtual void DataChanged( const DataChangedEvent& rEvt );
+};
+
+}
+
+XIMStatusWindow::XIMStatusWindow( bool bOn ) :
+ StatusWindow( WB_BORDER | WB_SYSTEMFLOATWIN | WB_TOOLTIPWIN ),
+ m_aStatusText( this, 0 ),
+ m_pLastParent( NULL ),
+ m_bAnchoredAtRight( false ),
+ m_bDelayedShow( false ),
+ m_eDelayedReason( I18NStatus::contextmap ),
+ m_nDelayedEvent( 0 ),
+ m_bOn( bOn )
+{
+ layout();
+}
+
+XIMStatusWindow::~XIMStatusWindow()
+{
+ if( m_nDelayedEvent )
+ Application::RemoveUserEvent( m_nDelayedEvent );
+}
+
+void XIMStatusWindow::toggle( bool bOn )
+{
+ m_bOn = bOn;
+ show( bOn, I18NStatus::contextmap );
+}
+
+void XIMStatusWindow::layout()
+{
+ m_aWindowSize.Width() = m_aStatusText.GetTextWidth( m_aStatusText.GetText() )+8;
+ Font aFont( m_aStatusText.GetFont() );
+ m_aWindowSize.Height() = aFont.GetHeight()+10;
+ m_aWindowSize = LogicToPixel( m_aWindowSize );
+
+ Size aControlSize( m_aWindowSize );
+ aControlSize.Width() -= 4;
+ aControlSize.Height() -= 4;
+
+ m_aStatusText.SetPosSizePixel( Point( 1, 1 ), aControlSize );
+ m_aStatusText.SetFont( aFont );
+ m_aStatusText.Show( TRUE );
+
+ if (m_bAnchoredAtRight && IsVisible())
+ {
+ SalFrame* pFrame = (SalFrame*)GetSystemData()->pSalFrame;
+ long nDelta = pFrame->maGeometry.nWidth - m_aWindowSize.Width();
+ pFrame->SetPosSize( pFrame->maGeometry.nX + nDelta,
+ pFrame->maGeometry.nY,
+ m_aWindowSize.Width(),
+ m_aWindowSize.Height(),
+ SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+ else
+ SetOutputSizePixel( m_aWindowSize );
+}
+
+bool XIMStatusWindow::checkLastParent() const
+{
+ if( m_pLastParent )
+ {
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ if( *it == m_pLastParent )
+ return true;
+ }
+ }
+ return false;
+}
+
+void XIMStatusWindow::DataChanged( const DataChangedEvent& )
+{
+ m_aStatusText.SetSettings( GetSettings() );
+ layout();
+}
+
+Point XIMStatusWindow::updatePosition()
+{
+ Point aRet;
+ if( checkLastParent() )
+ {
+ const SystemEnvData* pParentEnvData = m_pLastParent->GetSystemData();
+
+ SalExtTextInputPosEvent aPosEvent;
+ m_pLastParent->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
+ int x, y;
+ XLIB_Window aChild;
+ XTranslateCoordinates( (Display*)pParentEnvData->pDisplay,
+ (XLIB_Window)pParentEnvData->aShellWindow,
+ GetX11SalData()->GetDisplay()->GetRootWindow( GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() ),
+ 0, 0,
+ &x, &y,
+ &aChild );
+
+ // TODO: Currently, place the status window to the (physical) left of
+ // the cursor iff in vertical mode (assuming that the columns in
+ // vertical mode are always written from right to left, this causes the
+ // status window to keep out of the text already written). This
+ // heuristic would break if there is ever a vertical mode in which the
+ // columns are written from left to right. Also, more elaborate
+ // positioning for (both horizontal and vertical) left-to-right and
+ // right-to-left text would be possible.
+ bool bLeft = aPosEvent.mbVertical;
+ // true if status window is to the left of the cursor
+
+ int const nGap = 4; // between cursor and status window
+ if (aPosEvent.mbVertical)
+ {
+ aRet.X() = x + aPosEvent.mnX + (bLeft
+ ? -m_aWindowSize.Width() - nGap
+ : aPosEvent.mnHeight + nGap);
+ aRet.Y() = y + aPosEvent.mnY;
+ }
+ else
+ {
+ aRet.X() = x + aPosEvent.mnX + (bLeft ? -m_aWindowSize.Width() : 0);
+ aRet.Y() = y + aPosEvent.mnY+aPosEvent.mnHeight + nGap;
+ }
+
+ m_bAnchoredAtRight = bLeft;
+ }
+ return aRet;
+}
+
+void XIMStatusWindow::setPosition( SalFrame* pParent )
+{
+ if( pParent )
+ {
+ if( pParent != m_pLastParent )
+ {
+ setText( String() );
+ m_pLastParent = pParent;
+ Show( FALSE, SHOW_NOACTIVATE );
+ }
+ if( IsVisible() )
+ {
+ const SystemEnvData* pEnvData = GetSystemData();
+ SalFrame* pStatusFrame = (SalFrame*)pEnvData->pSalFrame;
+ Point aPoint = updatePosition();
+ pStatusFrame->SetPosSize( aPoint.X(), aPoint.Y(), m_aWindowSize.Width(), m_aWindowSize.Height(), SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+ }
+}
+
+IMPL_LINK( XIMStatusWindow, DelayedShowHdl, void*, EMPTYARG )
+{
+ m_nDelayedEvent = 0;
+ const SystemEnvData* pData = GetSystemData();
+ SalFrame* pStatusFrame = (SalFrame*)pData->pSalFrame;
+ if( m_bDelayedShow )
+ {
+ Size aControlSize( m_aWindowSize.Width()-4, m_aWindowSize.Height()-4 );
+ m_aStatusText.SetPosSizePixel( Point( 1, 1 ), aControlSize );
+ Point aPoint = updatePosition();
+ pStatusFrame->SetPosSize( aPoint.X(), aPoint.Y(), m_aWindowSize.Width(), m_aWindowSize.Height(), SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+ Show( m_bDelayedShow && m_bOn, SHOW_NOACTIVATE );
+ if( m_bDelayedShow )
+ {
+ XRaiseWindow( (Display*)pData->pDisplay,
+ (XLIB_Window)pData->aShellWindow );
+ }
+ return 0;
+}
+
+void XIMStatusWindow::show( bool bShow, I18NStatus::ShowReason eReason )
+{
+ if( bShow && ! m_aStatusText.GetText().Len() )
+ bShow = false;
+
+ m_bDelayedShow = bShow;
+ m_eDelayedReason = eReason;
+ if( ! m_nDelayedEvent )
+ m_nDelayedEvent = Application::PostUserEvent( LINK( this, XIMStatusWindow, DelayedShowHdl ) );
+}
+
+void XIMStatusWindow::setText( const String& rText )
+{
+ m_aStatusText.SetText( rText );
+ m_aWindowSize.Width() = m_aStatusText.GetTextWidth( rText )+8;
+}
+
+String XIMStatusWindow::getText() const
+{
+ return m_aStatusText.GetText();
+}
+
+// --------------------------------------------------------------------------
+
+namespace vcl {
+
+class IIIMPStatusWindow : public StatusWindow
+{
+ MenuButton m_aStatusBtn;
+ PopupMenu m_aMenu;
+ SalFrame* m_pResetFocus;
+ bool m_bShow;
+ bool m_bOn;
+
+ DECL_LINK( SelectHdl, MenuButton* );
+
+ void show();
+
+public:
+ IIIMPStatusWindow( SalFrame* pParent, bool bOn ); // for initial position
+ virtual ~IIIMPStatusWindow();
+
+ virtual void setText( const String & );
+ virtual String getText() const;
+ virtual void show( bool bShow, I18NStatus::ShowReason eReason );
+ virtual void toggle( bool bOn );
+ void layout();
+
+ // overload Window focus handler
+ virtual void GetFocus();
+ // overload WorkWindow::DataChanged
+ virtual void DataChanged( const DataChangedEvent& rEvt );
+};
+
+}
+
+IIIMPStatusWindow::IIIMPStatusWindow( SalFrame* pParent, bool bOn ) :
+ StatusWindow( WB_MOVEABLE ),
+ m_aStatusBtn( this, WB_BORDER ),
+ m_pResetFocus( pParent ),
+ m_bShow( true ),
+ m_bOn( bOn )
+{
+ SetText( String( RTL_CONSTASCII_USTRINGPARAM( "IME Status" ) ) );
+
+ layout();
+
+ m_aStatusBtn.SetSelectHdl( LINK( this, IIIMPStatusWindow, SelectHdl ) );
+ m_aStatusBtn.SetPopupMenu( &m_aMenu );
+ m_aStatusBtn.Show( TRUE );
+
+ const ::std::vector< I18NStatus::ChoiceData >& rChoices( I18NStatus::get().getChoices() );
+ int i = 1;
+ for( ::std::vector< I18NStatus::ChoiceData >::const_iterator it = rChoices.begin(); it != rChoices.end(); ++it, i++ )
+ m_aMenu.InsertItem( i, it->aString );
+
+ if( pParent )
+ {
+ const SystemEnvData* pEnvData = GetSystemData();
+
+ const SalFrameGeometry& rGeom( pParent->GetUnmirroredGeometry() );
+ int nDistance = rGeom.nTopDecoration;
+ if( nDistance < 20 )
+ nDistance = 20;
+ XMoveWindow( (Display*)pEnvData->pDisplay,
+ (XLIB_Window)pEnvData->aShellWindow,
+ rGeom.nX,
+ rGeom.nY + rGeom.nHeight + nDistance
+ );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "Warning: could not reposition status window since no frame\n" );
+#endif
+ EnableAlwaysOnTop( TRUE );
+}
+
+IIIMPStatusWindow::~IIIMPStatusWindow()
+{
+}
+
+void IIIMPStatusWindow::layout()
+{
+ Font aFont( m_aStatusBtn.GetFont() );
+ Size aSize( 15*aFont.GetHeight(), aFont.GetHeight()+14 );
+ aSize = m_aStatusBtn.LogicToPixel( aSize );
+
+ m_aStatusBtn.SetPosSizePixel( Point( 0, 0 ), aSize );
+ SetOutputSizePixel( aSize );
+ if( IsVisible() )
+ Invalidate();
+}
+
+void IIIMPStatusWindow::DataChanged( const DataChangedEvent& )
+{
+ m_aStatusBtn.SetSettings( GetSettings() );
+ layout();
+}
+
+void IIIMPStatusWindow::setText( const String& rText )
+{
+ m_aStatusBtn.SetText( rText );
+}
+
+String IIIMPStatusWindow::getText() const
+{
+ return m_aStatusBtn.GetText();
+}
+
+void IIIMPStatusWindow::show( bool bShow, I18NStatus::ShowReason eReason )
+{
+ // hide IIIMPStatusWindow only in presentations
+ if( ! bShow
+ && eReason != I18NStatus::presentation
+ )
+ return;
+
+ m_bShow = bShow;
+ show();
+}
+
+void IIIMPStatusWindow::toggle( bool bOn )
+{
+ if (bOn != m_bOn)
+ {
+ m_bOn = bOn;
+ show();
+ }
+}
+
+void IIIMPStatusWindow::show()
+{
+ if (m_bOn && m_bShow && !IsVisible())
+ m_pResetFocus = I18NStatus::get().getParent();
+ Show(m_bOn && m_bShow);
+}
+
+void IIIMPStatusWindow::GetFocus()
+{
+ /*
+ * this is here just to put the focus back to the application
+ * window at startup on clickToFocus WMs
+ */
+ WorkWindow::GetFocus();
+ if( m_pResetFocus )
+ {
+ /*
+ * look if reset focus still exists
+ * since reset focus really is an internal hack there should
+ * not be a method to be called in SalFrame destructor
+ */
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it;
+ for( it = rFrames.begin(); it != rFrames.end() && *it != m_pResetFocus; ++it )
+ ;
+ if( it != rFrames.end() )
+ {
+ const SystemEnvData* pParentEnvData = m_pResetFocus->GetSystemData();
+ SalXLib* pXLib = GetX11SalData()->GetDisplay()->GetXLib();
+ pXLib->PushXErrorLevel( true );
+ XSetInputFocus( (Display*)pParentEnvData->pDisplay,
+ (XLIB_Window)pParentEnvData->aShellWindow,
+ RevertToNone,
+ CurrentTime
+ );
+ XSync( (Display*)pParentEnvData->pDisplay, False );
+ pXLib->PopXErrorLevel();
+ }
+ m_pResetFocus = NULL;
+ }
+}
+
+// --------------------------------------------------------------------------
+
+IMPL_LINK( IIIMPStatusWindow, SelectHdl, MenuButton*, pBtn )
+{
+ if( pBtn == & m_aStatusBtn )
+ {
+ const ::std::vector< I18NStatus::ChoiceData >& rChoices( I18NStatus::get().getChoices() );
+ unsigned int nIndex = m_aStatusBtn.GetCurItemId()-1;
+ if( nIndex < rChoices.size() )
+ {
+ XSetICValues( static_cast<X11SalFrame*>(I18NStatus::get().getParent())->getInputContext()->GetContext(),
+ XNUnicodeCharacterSubset,
+ rChoices[nIndex].pData,
+ NULL);
+ // FIXME: get rid of X11SalFrame
+ X11SalFrame* pParent = static_cast<X11SalFrame*>(I18NStatus::get().getParent());
+ if( pParent && pParent->isMapped() )
+ {
+ const SystemEnvData* pEnv = pParent->GetSystemData();
+ SalXLib* pXLib = GetX11SalData()->GetDisplay()->GetXLib();
+ pXLib->PushXErrorLevel( true );
+ XSetInputFocus( (Display*)pEnv->pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ RevertToNone,
+ CurrentTime
+ );
+ XSync( (Display*)pEnv->pDisplay, False );
+ pXLib->PopXErrorLevel();
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * I18NStatus
+ */
+
+I18NStatus* I18NStatus::pInstance = NULL;
+
+I18NStatus& I18NStatus::get()
+{
+ if( ! pInstance )
+ pInstance = new I18NStatus();
+ return *pInstance;
+}
+
+// --------------------------------------------------------------------------
+
+bool I18NStatus::exists()
+{
+ return pInstance != NULL;
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::free()
+{
+ if( pInstance )
+ delete pInstance, pInstance = NULL;
+}
+
+// --------------------------------------------------------------------------
+
+I18NStatus::I18NStatus() :
+ m_pParent( NULL ),
+ m_pStatusWindow( NULL )
+{
+}
+
+// --------------------------------------------------------------------------
+
+I18NStatus::~I18NStatus()
+{
+ if( m_pStatusWindow )
+ delete m_pStatusWindow, m_pStatusWindow = NULL;
+ if( pInstance == this )
+ pInstance = NULL;
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::setParent( SalFrame* pParent )
+{
+ m_pParent = pParent;
+ if( ! m_pStatusWindow )
+ {
+ bool bIIIMPmode = m_aChoices.begin() != m_aChoices.end();
+ if( bIIIMPmode )
+ m_pStatusWindow = new IIIMPStatusWindow( pParent,
+ getStatusWindowMode() );
+ else
+ m_pStatusWindow = new XIMStatusWindow( getStatusWindowMode() );
+ setStatusText( m_aCurrentIM );
+ }
+ m_pStatusWindow->setPosition( m_pParent );
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::show( bool bShow, ShowReason eReason )
+{
+ if( m_pStatusWindow )
+ {
+ m_pStatusWindow->setPosition( m_pParent );
+ m_pStatusWindow->show( bShow, eReason );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::setStatusText( const String& rText )
+{
+ if( m_pStatusWindow )
+ {
+ /*
+ * #93614# convert fullwidth ASCII forms to ascii
+ */
+ int nChars = rText.Len()+1;
+ sal_Unicode* pBuffer = (sal_Unicode*)alloca( nChars*sizeof( sal_Unicode ) );
+ const sal_Unicode* pCopy = rText.GetBuffer();
+ for( int i = 0; i < nChars; i++ )
+ {
+ if( pCopy[i] >=0xff00 && pCopy[i] <= 0xff5f )
+ pBuffer[i] = (pCopy[i] & 0xff) + 0x20;
+ else
+ pBuffer[i] = pCopy[i];
+ }
+ String aText( pBuffer );
+ m_pStatusWindow->setText( aText );
+ m_pStatusWindow->setPosition( m_pParent );
+
+ bool bVisible = true;
+ if( m_pParent )
+ {
+ long w, h;
+ m_pParent->GetClientSize( w, h );
+ if( w == 0 || h == 0 )
+ {
+ bVisible = false;
+ }
+ }
+
+ m_pStatusWindow->show( bVisible, contextmap );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::changeIM( const String& rIM )
+{
+ m_aCurrentIM = rIM;
+}
+
+// --------------------------------------------------------------------------
+
+String I18NStatus::getStatusText() const
+{
+ return m_pStatusWindow ? m_pStatusWindow->getText() : String();
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::clearChoices()
+{
+ m_aChoices.clear();
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::addChoice( const String& rChoice, void* pData )
+{
+ ChoiceData aData;
+ aData.pData = pData;
+ aData.aString = rChoice;
+ m_aChoices.push_back( aData );
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::toTop() const
+{
+ if( m_pStatusWindow )
+ {
+ const SystemEnvData* pData = m_pStatusWindow->GetSystemData();
+ XRaiseWindow( (Display*)pData->pDisplay,
+ (XLIB_Window)pData->aShellWindow );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+SalFrame* I18NStatus::getStatusFrame() const
+{
+ SalFrame* pRet = NULL;
+ if( m_pStatusWindow )
+ {
+ const SystemEnvData* pData = m_pStatusWindow->GetSystemData();
+ pRet = (SalFrame*)pData->pSalFrame;
+ }
+ return pRet;
+}
+
+bool I18NStatus::canToggleStatusWindow() const
+{
+ return true;
+}
+
+void I18NStatus::toggleStatusWindow()
+{
+ if (m_pStatusWindow != 0)
+ m_pStatusWindow->toggle(getStatusWindowMode());
+}
+
+bool I18NStatus::getStatusWindowMode()
+{
+ switch (ImplGetSVData()->maAppData.meShowImeStatusWindow)
+ {
+ default: // ImplSVAppData::ImeStatusWindowMode_UNKNOWN
+ return Application::GetShowImeStatusWindowDefault();
+ case ImplSVAppData::ImeStatusWindowMode_HIDE:
+ return false;
+ case ImplSVAppData::ImeStatusWindowMode_SHOW:
+ return true;
+ }
+}
+
+/*
+ * X11ImeStatus
+ */
+X11ImeStatus::~X11ImeStatus()
+{
+ vcl::I18NStatus::free();
+}
+
+bool X11ImeStatus::canToggle()
+{
+ return vcl::I18NStatus::get().canToggleStatusWindow();
+}
+
+void X11ImeStatus::toggle()
+{
+ vcl::I18NStatus::get().toggleStatusWindow();
+}
+
+SalI18NImeStatus* X11SalInstance::CreateI18NImeStatus()
+{
+ return new X11ImeStatus();
+}
diff --git a/vcl/unx/generic/app/i18n_wrp.cxx b/vcl/unx/generic/app/i18n_wrp.cxx
new file mode 100644
index 000000000000..ff56f0ed0647
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_wrp.cxx
@@ -0,0 +1,260 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+struct XIMArg
+{
+ char *name;
+ char *value;
+};
+
+#if defined(SOLARIS) && !defined(__GNUC__)
+#include <varargs.h>
+#else
+#include <stdarg.h>
+#endif
+#include <sal/alloca.h>
+
+#include <string.h>
+#include <dlfcn.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#include "unx/XIM.h"
+
+#define XIIIMP_LIB "xiiimp.so.2"
+
+#ifdef SOLARIS
+#define XIIIMP_PATH "/usr/openwin/lib/locale/common/" XIIIMP_LIB
+#else /* Linux */
+#define XIIIMP_PATH "/usr/lib/im/" XIIIMP_LIB
+#endif
+
+extern "C" {
+typedef XIM (*OpenFunction)(Display*, XrmDatabase, char*, char*, XIMArg*);
+}
+
+/* global variables */
+static void *g_dlmodule = 0;
+static OpenFunction g_open_im = (OpenFunction)NULL;
+
+/* utility function to transform vararg list into an array of XIMArg */
+
+int
+XvaCountArgs( XIMArg *pInArgs )
+{
+ int nArgs = 0;
+ char *pName, *pValue;
+
+ while ( (pName = pInArgs->name) != NULL )
+ {
+ pValue = pInArgs->value;
+
+ if ( strcmp(pName, XNVaNestedList) == 0 )
+ {
+ nArgs += XvaCountArgs( (XIMArg*)pValue );
+ }
+ else
+ {
+ nArgs += 1;
+ }
+ pInArgs++;
+ }
+
+ return nArgs;
+}
+
+int
+XvaCountArgs( va_list pInArgs )
+{
+ int nArgs = 0;
+ char *pName, *pValue;
+
+ while ( (pName = va_arg(pInArgs, char*)) != NULL)
+ {
+ pValue = va_arg(pInArgs, char*);
+
+ if ( strcmp(pName, XNVaNestedList) == 0 )
+ {
+ nArgs += XvaCountArgs( (XIMArg*)pValue );
+ }
+ else
+ {
+ nArgs += 1;
+ }
+ }
+
+ return nArgs;
+}
+
+XIMArg*
+XvaGetArgs( XIMArg *pInArgs, XIMArg *pOutArgs )
+{
+ char *pName, *pValue;
+
+ while ( (pName = pInArgs->name) != NULL )
+ {
+ pValue = pInArgs->value;
+
+ if ( strcmp(pName, XNVaNestedList) == 0 )
+ {
+ pOutArgs = XvaGetArgs( (XIMArg*)pValue, pOutArgs );
+ }
+ else
+ {
+ pOutArgs->name = pName;
+ pOutArgs->value = pValue;
+ pOutArgs++;
+ }
+ pInArgs++;
+ }
+
+ return pOutArgs;
+}
+
+void
+XvaGetArgs( va_list pInArgs, XIMArg *pOutArgs )
+{
+ char *pName, *pValue;
+
+ while ((pName = va_arg(pInArgs, char*)) != NULL)
+ {
+ pValue = va_arg(pInArgs, char*);
+
+ if ( strcmp(pName, XNVaNestedList) == 0 )
+ {
+ pOutArgs = XvaGetArgs( (XIMArg*)pValue, pOutArgs );
+ }
+ else
+ {
+ pOutArgs->name = pName;
+ pOutArgs->value = pValue;
+ pOutArgs++;
+ }
+ }
+
+ pOutArgs->name = NULL;
+ pOutArgs->value = NULL;
+}
+
+
+/* Puplic functions */
+
+#ifdef __cplusplus
+extern "C"
+#endif
+XIM
+XvaOpenIM(Display *display, XrmDatabase rdb,
+ char *res_name, char *res_class, ...)
+{
+ XIM xim = (XIM)0;
+ va_list variable;
+ int total_count = 0;
+
+ /*
+ * so count the stuff dangling here
+ */
+
+#if defined(SOLARIS) && !defined(__GNUC__)
+ va_start(variable);
+#else
+ va_start(variable, res_class);
+#endif
+ total_count = XvaCountArgs(variable);
+ va_end(variable);
+
+ if (total_count > 0)
+ {
+ /* call a new open IM method */
+
+ XIMArg* args = (XIMArg*)alloca( (total_count + 1) * sizeof(XIMArg) );
+
+ /*
+ * now package it up so we can set it along
+ */
+#if defined(SOLARIS) && !defined(__GNUC__)
+ va_start(variable);
+#else
+ va_start(variable, res_class);
+#endif
+ XvaGetArgs( variable, args );
+ va_end(variable);
+
+ if (!g_dlmodule)
+ {
+ g_dlmodule = dlopen(XIIIMP_LIB, RTLD_LAZY);
+ if(!g_dlmodule)
+ {
+ g_dlmodule = dlopen(XIIIMP_PATH, RTLD_LAZY);
+ if (!g_dlmodule)
+ goto legacy_XIM;
+ }
+ g_open_im = (OpenFunction)(long)dlsym(g_dlmodule, "__XOpenIM");
+ if (!g_open_im)
+ goto legacy_XIM;
+
+ xim = (*g_open_im)(display, (XrmDatabase)rdb,
+ (char*)res_name, (char *)res_class, (XIMArg*)args);
+ }
+ else
+ {
+ goto legacy_XIM;
+ }
+ }
+
+// in #if to prevent warning "warning: label 'legacy_XIM' defined but not used"
+ legacy_XIM:
+
+ if (!xim)
+ xim = XOpenIM(display, rdb, res_name, res_class);
+
+ return xim;
+}
+
+/*
+ * Close the connection to the input manager, and free the XIM structure
+ */
+
+Status XvaCloseIM(XIM)
+{
+ Status s = False;
+
+ if (!g_dlmodule)
+ {
+ /* assuming one XvaOpenIM call */
+ dlclose(g_dlmodule);
+ g_dlmodule = (void*)0;
+ g_open_im = (OpenFunction)NULL;
+ s = True;
+ }
+ return (s);
+}
+
+
+
diff --git a/vcl/unx/generic/app/i18n_xkb.cxx b/vcl/unx/generic/app/i18n_xkb.cxx
new file mode 100644
index 000000000000..5587bbf02339
--- /dev/null
+++ b/vcl/unx/generic/app/i18n_xkb.cxx
@@ -0,0 +1,163 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+
+#include <stdio.h>
+
+#include "unx/saldisp.hxx"
+#include "unx/saldata.hxx"
+#include "unx/i18n_xkb.hxx"
+
+SalI18N_KeyboardExtension::SalI18N_KeyboardExtension( Display*
+#if __XKeyboardExtension__
+pDisplay
+#endif
+)
+ : mbUseExtension( (sal_Bool)__XKeyboardExtension__ ),
+ mnDefaultGroup( 0 )
+{
+ #if __XKeyboardExtension__
+
+ mpDisplay = pDisplay;
+
+ // allow user to set the default keyboard group idx or to disable the usage
+ // of x keyboard extension at all:
+ // setenv SAL_XKEYBOARDGROUP disables keyboard extension
+ // setenv SAL_XKEYBOARDGROUP 2 sets the keyboard group index to 2
+ // keyboard group index must be in [1,4], may be specified in hex or decimal
+ static char *pUseKeyboardExtension = getenv( "SAL_XKEYBOARDGROUP" );
+ if ( pUseKeyboardExtension != NULL )
+ {
+ mbUseExtension = pUseKeyboardExtension[0] != '\0' ;
+ if ( mbUseExtension )
+ mnDefaultGroup = strtol( pUseKeyboardExtension, NULL, 0 );
+ if ( mnDefaultGroup > XkbMaxKbdGroup )
+ mnDefaultGroup = 0;
+ }
+
+ // query XServer support for XKB Extension,
+ // do not call XQueryExtension() / XInitExtension() due to possible version
+ // clashes !
+ if ( mbUseExtension )
+ {
+ int nMajorExtOpcode;
+ int nExtMajorVersion = XkbMajorVersion;
+ int nExtMinorVersion = XkbMinorVersion;
+
+ mbUseExtension = (sal_Bool)XkbQueryExtension( mpDisplay,
+ &nMajorExtOpcode, (int*)&mnEventBase, (int*)&mnErrorBase,
+ &nExtMajorVersion, &nExtMinorVersion );
+ }
+
+ // query notification for changes of the keyboard group
+ if ( mbUseExtension )
+ {
+ #define XkbGroupMask ( XkbGroupStateMask | XkbGroupBaseMask \
+ | XkbGroupLatchMask | XkbGroupLockMask )
+
+ mbUseExtension = XkbSelectEventDetails( mpDisplay,
+ XkbUseCoreKbd, XkbStateNotify, XkbGroupMask, XkbGroupMask );
+ }
+
+ // query initial keyboard group
+ if ( mbUseExtension )
+ {
+ XkbStateRec aStateRecord;
+ XkbGetState( mpDisplay, XkbUseCoreKbd, &aStateRecord );
+ mnGroup = aStateRecord.group;
+ }
+
+ #endif // __XKeyboardExtension__
+}
+
+void
+SalI18N_KeyboardExtension::Dispatch( XEvent*
+#if __XKeyboardExtension__
+pEvent
+#endif
+)
+{
+ #if __XKeyboardExtension__
+
+ // must the event be handled?
+ if ( !mbUseExtension
+ || (pEvent->type != mnEventBase) )
+ return;
+
+ // only handle state notify events for now, and only interested
+ // in group details
+ sal_uInt32 nXKBType = ((XkbAnyEvent*)pEvent)->xkb_type;
+ switch ( nXKBType )
+ {
+ case XkbStateNotify:
+
+ mnGroup = ((XkbStateNotifyEvent*)pEvent)->group;
+ break;
+
+ default:
+
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "Got unrequested XkbAnyEvent %#x/%i\n",
+ static_cast<unsigned int>(nXKBType), static_cast<int>(nXKBType) );
+ #endif
+ break;
+ }
+ #endif // __XKeyboardExtension__
+}
+
+#if __XKeyboardExtension__
+sal_uInt32
+SalI18N_KeyboardExtension::LookupKeysymInGroup( sal_uInt32 nKeyCode,
+ sal_uInt32 nShiftState,
+ sal_uInt32 nGroup ) const
+#else
+sal_uInt32
+SalI18N_KeyboardExtension::LookupKeysymInGroup( sal_uInt32,sal_uInt32,sal_uInt32 ) const
+#endif
+{
+ #if __XKeyboardExtension__
+
+ if ( !mbUseExtension )
+ return NoSymbol;
+
+ nShiftState &= ShiftMask;
+
+ KeySym nKeySymbol;
+ nKeySymbol = XkbKeycodeToKeysym( mpDisplay, nKeyCode, nGroup, nShiftState );
+ return nKeySymbol;
+
+ #else
+
+ return NoSymbol;
+
+ #endif // __XKeyboardExtension__
+}
+
+
diff --git a/vcl/unx/generic/app/keysymnames.cxx b/vcl/unx/generic/app/keysymnames.cxx
new file mode 100644
index 000000000000..45a07ac66987
--- /dev/null
+++ b/vcl/unx/generic/app/keysymnames.cxx
@@ -0,0 +1,688 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifndef SOLARIS
+#include <tools/prex.h>
+#include <X11/XKBlib.h>
+#include <tools/postx.h>
+#endif
+
+#include <unx/saldisp.hxx>
+#include <X11/keysym.h>
+
+#if !defined (SunXK_Undo)
+#define SunXK_Undo 0x0000FF65 // XK_Undo
+#define SunXK_Again 0x0000FF66 // XK_Redo
+#define SunXK_Find 0x0000FF68 // XK_Find
+#define SunXK_Stop 0x0000FF69 // XK_Cancel
+#define SunXK_Props 0x1005FF70
+#define SunXK_Front 0x1005FF71
+#define SunXK_Copy 0x1005FF72
+#define SunXK_Open 0x1005FF73
+#define SunXK_Paste 0x1005FF74
+#define SunXK_Cut 0x1005FF75
+#endif
+
+#ifdef SOLARIS
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/kbio.h>
+#include <sys/kbd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <deflt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+
+#include <string.h>
+
+namespace vcl_sal {
+
+ struct KeysymNameReplacement
+ {
+ KeySym aSymbol;
+ const char* pName;
+ };
+
+ struct KeyboardReplacements
+ {
+ const char* pKeyboardName;
+ const KeysymNameReplacement* pReplacements;
+ int nReplacements;
+ };
+
+ // ====================================================================
+ //
+ // CAUTION CAUTION CAUTION
+ // every string value in the replacements tables must be in UTF8
+ // be careful with your editor !
+ //
+ // ====================================================================
+
+ static const struct KeysymNameReplacement aImplReplacements_English[] =
+ {
+ { XK_Control_L, "Ctrl" },
+ { XK_Control_R, "Ctrl" },
+ { XK_Escape, "Esc" },
+ { XK_space, "Space" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Turkish[] =
+ {
+ { XK_Control_L, "Ctrl" },
+ { XK_Control_R, "Ctrl" },
+ { XK_Right, "SaÄŸ" },
+ { XK_Left, "Sol" },
+ { XK_Up, "Yukarı" },
+ { XK_Down, "Aşağı" },
+ { XK_space, "BoÅŸluk" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Russian[] =
+ {
+ { XK_Right, "Вправо" },
+ { XK_Left, "Влево" },
+ { XK_Up, "Вверх" },
+ { XK_Down, "Вниз" },
+ { XK_space, "Пробел" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_German[] =
+ {
+ { XK_Control_L, "Strg" },
+ { XK_Control_R, "Strg" },
+ { XK_Shift_L, "Umschalt" },
+ { XK_Shift_R, "Umschalt" },
+ { XK_Alt_L, "Alt" },
+ { XK_Alt_R, "Alt Gr" },
+ { XK_Page_Up, "Bild auf" },
+ { XK_Page_Down, "Bild ab" },
+ { XK_End, "Ende" },
+ { XK_Home, "Pos 1" },
+ { XK_Insert, "Einfg" },
+ { XK_Delete, "Entf" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Rechts" },
+ { XK_Left, "Links" },
+ { XK_Up, "Oben" },
+ { XK_Down, "Unten" },
+ { XK_BackSpace, "Rückschritt" },
+ { XK_Return, "Eingabe" },
+ { XK_slash, "Schrägstrich" },
+ { XK_space, "Leertaste" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Wiederholen" },
+ { SunXK_Props, "Eigenschaften" },
+ { SunXK_Undo, "Zurücknehmen" },
+ { SunXK_Front, "Vordergrund" },
+ { SunXK_Copy, "Kopieren" },
+ { SunXK_Open, "Öffnen" },
+ { SunXK_Paste, "Einsetzen" },
+ { SunXK_Find, "Suchen" },
+ { SunXK_Cut, "Ausschneiden" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_French[] =
+ {
+ { XK_Shift_L, "Maj" },
+ { XK_Shift_R, "Maj" },
+ { XK_Page_Up, "Pg. Préc" },
+ { XK_Page_Down, "Pg. Suiv" },
+ { XK_End, "Fin" },
+ { XK_Home, "Origine" },
+ { XK_Insert, "Insérer" },
+ { XK_Delete, "Suppr" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Droite" },
+ { XK_Left, "Gauche" },
+ { XK_Up, "Haut" },
+ { XK_Down, "Bas" },
+ { XK_BackSpace, "Ret. Arr" },
+ { XK_Return, "Retour" },
+ { XK_KP_Enter, "Entrée" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Encore" },
+ { SunXK_Props, "Props" },
+ { SunXK_Undo, "Annuler" },
+ { SunXK_Front, "Devant" },
+ { SunXK_Copy, "Copy" },
+ { SunXK_Open, "Ouvrir" },
+ { SunXK_Paste, "Coller" },
+ { SunXK_Find, "Cher." },
+ { SunXK_Cut, "Couper" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Italian[] =
+ {
+ { XK_Shift_L, "Maiusc" },
+ { XK_Shift_R, "Maiusc" },
+ { XK_Page_Up, "PgSu" },
+ { XK_Page_Down, "PgGiu" },
+ { XK_End, "Fine" },
+ { XK_Insert, "Ins" },
+ { XK_Delete, "Canc" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "A destra" },
+ { XK_Left, "A sinistra" },
+ { XK_Up, "Sposta verso l'alto" },
+ { XK_Down, "Sposta verso il basso" },
+ { XK_BackSpace, "Backspace" },
+ { XK_Return, "Invio" },
+ { XK_space, "Spazio" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Ancora" },
+ { SunXK_Props, "Proprietà" },
+ { SunXK_Undo, "Annulla" },
+ { SunXK_Front, "Davanti" },
+ { SunXK_Copy, "Copia" },
+ { SunXK_Open, "Apri" },
+ { SunXK_Paste, "Incolla" },
+ { SunXK_Find, "Trova" },
+ { SunXK_Cut, "Taglia" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Dutch[] =
+ {
+ { XK_Page_Up, "PageUp" },
+ { XK_Page_Down, "PageDown" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Rechts" },
+ { XK_Left, "Links" },
+ { XK_Up, "Boven" },
+ { XK_Down, "Onder" },
+ { XK_BackSpace, "Backspace" },
+ { XK_Return, "Return" },
+ { XK_space, "Spatiebalk" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Again" },
+ { SunXK_Props, "Props" },
+ { SunXK_Undo, "Undo" },
+ { SunXK_Front, "Front" },
+ { SunXK_Copy, "Copy" },
+ { SunXK_Open, "Open" },
+ { SunXK_Paste, "Paste" },
+ { SunXK_Find, "Find" },
+ { SunXK_Cut, "Cut" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Norwegian[] =
+ {
+ { XK_Shift_L, "Skift" },
+ { XK_Shift_R, "Skift" },
+ { XK_Page_Up, "PageUp" },
+ { XK_Page_Down, "PageDown" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Hyre" },
+ { XK_Left, "Venstre" },
+ { XK_Up, "Opp" },
+ { XK_Down, "Ned" },
+ { XK_BackSpace, "Tilbake" },
+ { XK_Return, "Enter" },
+ { SunXK_Stop, "Avbryt" },
+ { SunXK_Again, "Gjenta" },
+ { SunXK_Props, "Egenskaper" },
+ { SunXK_Undo, "Angre" },
+ { SunXK_Front, "Front" },
+ { SunXK_Copy, "Kopi" },
+ { SunXK_Open, "Ã…pne" },
+ { SunXK_Paste, "Lim" },
+ { SunXK_Find, "Søk" },
+ { SunXK_Cut, "Klipp" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Swedish[] =
+ {
+ { XK_Shift_L, "Skift" },
+ { XK_Shift_R, "Skift" },
+ { XK_Page_Up, "PageUp" },
+ { XK_Page_Down, "PageDown" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Höger" },
+ { XK_Left, "Vänster" },
+ { XK_Up, "Up" },
+ { XK_Down, "Ned" },
+ { XK_BackSpace, "Backsteg" },
+ { XK_Return, "Retur" },
+ { XK_space, "Blank" },
+ { SunXK_Stop, "Avbryt" },
+ { SunXK_Again, "Upprepa" },
+ { SunXK_Props, "Egenskaper" },
+ { SunXK_Undo, "Ã…ngra" },
+ { SunXK_Front, "Fram" },
+ { SunXK_Copy, "Kopiera" },
+ { SunXK_Open, "Öppna" },
+ { SunXK_Paste, "Klistra in" },
+ { SunXK_Find, "Sök" },
+ { SunXK_Cut, "Klipp ut" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Portuguese[] =
+ {
+ { XK_Page_Up, "PageUp" },
+ { XK_Page_Down, "PageDown" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Direita" },
+ { XK_Left, "Esquerda" },
+ { XK_Up, "Acima" },
+ { XK_Down, "Abaixo" },
+ { XK_BackSpace, "Backspace" },
+ { XK_Return, "Enter" },
+ { XK_slash, "Barra" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Again" },
+ { SunXK_Props, "Props" },
+ { SunXK_Undo, "Undo" },
+ { SunXK_Front, "Front" },
+ { SunXK_Copy, "Copy" },
+ { SunXK_Open, "Open" },
+ { SunXK_Paste, "Paste" },
+ { SunXK_Find, "Find" },
+ { SunXK_Cut, "Cut" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Spanish[] =
+ {
+ { XK_Shift_L, "Mayús" },
+ { XK_Shift_R, "Mayús" },
+ { XK_Page_Up, "RePág" },
+ { XK_Page_Down, "AvPág" },
+ { XK_End, "Fin" },
+ { XK_Home, "Inicio" },
+ { XK_Delete, "Supr" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Hacia la derecha" },
+ { XK_Left, "Hacia la izquierda" },
+ { XK_Up, "Hacia arriba" },
+ { XK_Down, "Hacia abajo" },
+ { XK_BackSpace, "Ret" },
+ { XK_Return, "Entrada" },
+ { XK_space, "Espacio" },
+ { XK_KP_Enter, "Intro" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Repetir" },
+ { SunXK_Props, "Props" },
+ { SunXK_Undo, "Anular" },
+ { SunXK_Front, "Delante" },
+ { SunXK_Copy, "Copiar" },
+ { SunXK_Open, "Abrir" },
+ { SunXK_Paste, "Pegar" },
+ { SunXK_Find, "Buscar" },
+ { SunXK_Cut, "Cortar" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeyboardReplacements aKeyboards[] =
+ {
+#ifdef SOLARIS
+ { "Germany5", aImplReplacements_German, sizeof(aImplReplacements_German)/sizeof(aImplReplacements_German[0]) },
+ { "Germany4", aImplReplacements_German, sizeof(aImplReplacements_German)/sizeof(aImplReplacements_German[0]) },
+ { "France5", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ { "France6", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ { "France_x86", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ { "Italy5", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Italy5-Hobo", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Italy4", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Italy6", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Italy_x86", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Netherland4", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Netherland5", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Netherland5-Hobo", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Netherland6", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Netherland_x86", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Norway5", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Norway5-Hobo", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Norway4", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Norway6", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Norway_x86", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Portugal5", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Portugal5-Hobo", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Portugal4", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Portugal6", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Portugal_x86", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Spain5", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spain5-Hobo", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spain4", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spain6", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spain_x86", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Sweden5", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Sweden5-Hobo", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Sweden4", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Sweden6", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Sweden_x86", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+#endif
+ { "U.S. English", aImplReplacements_English, sizeof(aImplReplacements_English)/sizeof(aImplReplacements_English[0]) },
+ { "United Kingdom", aImplReplacements_English, sizeof(aImplReplacements_English)/sizeof(aImplReplacements_English[0]) },
+ // Germany, German
+ { "German", aImplReplacements_German, sizeof(aImplReplacements_German)/sizeof(aImplReplacements_German[0]) },
+ { "France", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ { "French", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ // Italy, Italian
+ { "Ital", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ // Norway, Norwegian
+ { "Norw", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ // Portugal, Portuguese
+ { "Portu", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Spain", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spanish", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ // Sweden, Swedish
+ { "Swed", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Netherland", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Dutch", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ // Turkish, Turkey
+ { "Turk", aImplReplacements_Turkish, sizeof(aImplReplacements_Turkish)/sizeof(aImplReplacements_Turkish[0]) },
+ // Russian, Russia
+ { "Russia", aImplReplacements_Russian, sizeof(aImplReplacements_Russian)/sizeof(aImplReplacements_Russian[0]) },
+ { "English", aImplReplacements_English, sizeof(aImplReplacements_English)/sizeof(aImplReplacements_English[0]) }
+ };
+
+ String getKeysymReplacementName( const char* pKeyboard, KeySym nSymbol )
+ {
+ for( unsigned int n = 0; n < sizeof(aKeyboards)/sizeof(aKeyboards[0]); n++ )
+ {
+ if( ! strncasecmp( pKeyboard, aKeyboards[n].pKeyboardName, strlen( aKeyboards[n].pKeyboardName ) ) )
+ {
+ const struct KeysymNameReplacement* pRepl = aKeyboards[n].pReplacements;
+ for( int m = aKeyboards[n].nReplacements ; m ; )
+ {
+ if( nSymbol == pRepl[--m].aSymbol )
+ return String( pRepl[m].pName, RTL_TEXTENCODING_UTF8 );
+ }
+ }
+ }
+ // try english fallbacks
+ const struct KeysymNameReplacement* pRepl = aImplReplacements_English;
+ for( int m = sizeof(aImplReplacements_English)/sizeof(aImplReplacements_English[0]) ; m ; )
+ {
+ if( nSymbol == pRepl[--m].aSymbol )
+ return String( pRepl[m].pName, RTL_TEXTENCODING_UTF8 );
+ }
+ return String();
+ }
+
+}
+
+#ifdef SOLARIS
+typedef struct {
+ int n_layout;
+ const char* p_description;
+} keyboard_layout;
+
+static const keyboard_layout type0_layout[] =
+{
+ { 0, "US4" },
+ { -1, NULL }
+};
+
+static const keyboard_layout type3_layout[] =
+{
+ { 0, "US3" },
+ { -1, NULL }
+};
+
+static const keyboard_layout type4_layout[] =
+{
+ { 0, "US4" },
+ { 1, "US4" },
+ { 2, "FranceBelg4" },
+ { 3, "Canada4" },
+ { 4, "Denmark4" },
+ { 5, "Germany4" },
+ { 6, "Italy4" },
+ { 7, "Netherland4" },
+ { 8, "Norway4" },
+ { 9, "Portugal4" },
+ { 10, "SpainLatAm4" },
+ { 11, "SwedenFin4" },
+ { 12, "Switzer_Fr4" },
+ { 13, "Switzer_Ge4" },
+ { 14, "UK4" },
+ { 16, "Korea4" },
+ { 17, "Taiwan4" },
+ { 19, "US101A_PC" },
+ { 19, "US101A_Sun" },
+ { 32, "Japan4" },
+ { 33, "US5" },
+ { 34, "US_UNIX5" },
+ { 35, "France5" },
+ { 36, "Denmark5" },
+ { 37, "Germany5" },
+ { 38, "Italy5" },
+ { 39, "Netherland5" },
+ { 40, "Norway5" },
+ { 41, "Portugal5" },
+ { 42, "Spain5" },
+ { 43, "Sweden5" },
+ { 44, "Switzer_Fr5" },
+ { 45, "Switzer_Ge5" },
+ { 46, "UK5" },
+ { 47, "Korea5" },
+ { 48, "Taiwan5" },
+ { 49, "Japan5" },
+ { 50, "Canada_Fr5" },
+ { 51, "Hungary5" },
+ { 52, "Poland5" },
+ { 53, "Czech5" },
+ { 54, "Russia5" },
+ { 55, "Latvia5" },
+ { 56, "Turkey5" },
+ { 57, "Greece5" },
+ { 58, "Estonia5" },
+ { 59, "Lithuania5" },
+ { 63, "Canada_Fr5_TBITS5" },
+ { 80, "US5_Hobo" },
+ { 81, "US_UNIX5_Hobo" },
+ { 82, "France5_Hobo" },
+ { 83, "Denmark5_Hobo" },
+ { 84, "Germany5_Hobo" },
+ { 85, "Italy5_Hobo" },
+ { 86, "Netherland5_Hobo" },
+ { 87, "Norway5_Hobo" },
+ { 88, "Portugal5_Hobo" },
+ { 89, "Spain5_Hobo" },
+ { 90, "Sweden5_Hobo" },
+ { 91, "Switzer_Fr5_Hobo" },
+ { 92, "Switzer_Ge5_Hobo" },
+ { 93, "UK5_Hobo" },
+ { 94, "Korea5_Hobo" },
+ { 95, "Taiwan5_Hobo" },
+ { 96, "Japan5_Hobo" },
+ { 97, "Canada_Fr5_Hobo" },
+ { -1, NULL }
+};
+
+static const keyboard_layout type101_layout[] =
+{
+ { 0, "US101A_x86" },
+ { 1, "US101A_x86" },
+ { 34, "J3100_x86" },
+ { 35, "France_x86" },
+ { 36, "Denmark_x86" },
+ { 37, "Germany_x86" },
+ { 38, "Italy_x86" },
+ { 39, "Netherland_x86" },
+ { 40, "Norway_x86" },
+ { 41, "Portugal_x86" },
+ { 42, "Spain_x86" },
+ { 43, "Sweden_x86" },
+ { 44, "Switzer_Fr_x86" },
+ { 45, "Switzer_Ge_x86" },
+ { 46, "UK_x86" },
+ { 47, "Korea_x86" },
+ { 48, "Taiwan_x86" },
+ { 49, "Japan_x86" },
+ { 50, "Canada_Fr2_x86" },
+ { 51, "Hungary_x86" },
+ { 52, "Poland_x86" },
+ { 53, "Czech_x86" },
+ { 54, "Russia_x86" },
+ { 55, "Latvia_x86" },
+ { 56, "Turkey_x86" },
+ { 57, "Greece_x86" },
+ { 59, "Lithuania_x86" },
+ { 1001, "MS_US101A_x86" },
+ { -1, NULL }
+};
+
+static const keyboard_layout type6_layout[] =
+{
+ { 0, "US6" },
+ { 6, "Denmark6" },
+ { 7, "Finnish6" },
+ { 8, "France6" },
+ { 9, "Germany6" },
+ { 14, "Italy6" },
+ { 15, "Japan6" },
+ { 16, "Korea6" },
+ { 18, "Netherland6" },
+ { 19, "Norway6" },
+ { 22, "Portugal6" },
+ { 25, "Spain6" },
+ { 26, "Sweden6" },
+ { 27, "Switzer_Fr6" },
+ { 28, "Switzer_Ge6" },
+ { 30, "Taiwan6" },
+ { 32, "UK6" },
+ { 33, "US6" },
+ { -1, NULL }
+};
+#endif
+
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+const char* SalDisplay::GetKeyboardName( BOOL bRefresh )
+{
+ if( bRefresh || ! m_aKeyboardName.Len() )
+ {
+#ifdef SOLARIS
+ if( IsLocal() )
+ {
+ int kbd = open( "/dev/kbd", O_RDONLY );
+ if( kbd >= 0 )
+ {
+ int kbd_type = 0;
+ if( ! ioctl( kbd, KIOCTYPE, &kbd_type ) )
+ {
+ int kbd_layout = 0;
+ if( ! ioctl( kbd, KIOCLAYOUT, &kbd_layout ) )
+ {
+ const keyboard_layout *p_layout = NULL;
+ switch( kbd_type )
+ {
+ case KB_KLUNK: p_layout = type0_layout; break;
+ case KB_SUN3: p_layout = type3_layout; break;
+ case KB_SUN4: p_layout = type4_layout; break;
+ case KB_USB: p_layout = type6_layout; break;
+ case KB_PC: p_layout = type101_layout; break;
+ }
+
+ if( p_layout )
+ {
+ while( p_layout->n_layout != -1 )
+ {
+ if ( p_layout->n_layout == kbd_layout )
+ {
+ m_aKeyboardName = p_layout->p_description;
+ break;
+ }
+ p_layout++;
+ }
+ }
+ }
+ }
+ close(kbd);
+ }
+ }
+#else
+ int opcode, event, error;
+ int major = XkbMajorVersion, minor = XkbMinorVersion;
+ if( XkbQueryExtension( GetDisplay(), &opcode, &event,&error, &major, &minor ) )
+ {
+ XkbDescPtr pXkbDesc = NULL;
+ // try X keyboard extension
+ if( (pXkbDesc = XkbGetKeyboard( GetDisplay(), XkbAllComponentsMask, XkbUseCoreKbd )) )
+ {
+ const char* pAtom = NULL;
+ if( pXkbDesc->names->groups[0] )
+ {
+ pAtom = XGetAtomName( GetDisplay(), pXkbDesc->names->groups[0] );
+ m_aKeyboardName = pAtom;
+ XFree( (void*)pAtom );
+ }
+ else
+ m_aKeyboardName = "<unknown keyboard>";
+#if OSL_DEBUG_LEVEL > 1
+#define PRINT_ATOM( x ) { if( pXkbDesc->names->x ) { pAtom = XGetAtomName( GetDisplay(), pXkbDesc->names->x ); fprintf( stderr, "%s: %s\n", #x, pAtom ); XFree( (void*)pAtom ); } else fprintf( stderr, "%s: <nil>\n", #x ); }
+
+ PRINT_ATOM( keycodes );
+ PRINT_ATOM( geometry );
+ PRINT_ATOM( symbols );
+ PRINT_ATOM( types );
+ PRINT_ATOM( compat );
+ PRINT_ATOM( phys_symbols );
+
+#define PRINT_ATOM_2( x ) { if( pXkbDesc->names->x[i] ) { pAtom = XGetAtomName( GetDisplay(), pXkbDesc->names->x[i] ); fprintf( stderr, "%s[%d]: %s\n", #x, i, pAtom ); XFree( (void*)pAtom ); } else fprintf( stderr, "%s[%d]: <nil>\n", #x, i ); }
+ int i;
+ for( i = 0; i < XkbNumVirtualMods; i++ )
+ PRINT_ATOM_2( vmods );
+ for( i = 0; i < XkbNumIndicators; i++ )
+ PRINT_ATOM_2( indicators );
+ for( i = 0; i < XkbNumKbdGroups; i++ )
+ PRINT_ATOM_2( groups );
+#endif
+ XkbFreeKeyboard( pXkbDesc, XkbAllComponentsMask, True );
+ }
+ }
+#endif
+ if( ! m_aKeyboardName.Len() )
+ m_aKeyboardName = "<unknown keyboard>";
+ }
+ return m_aKeyboardName.GetBuffer();
+}
diff --git a/vcl/unx/generic/app/makefile.mk b/vcl/unx/generic/app/makefile.mk
new file mode 100644
index 000000000000..bd7549945c7c
--- /dev/null
+++ b/vcl/unx/generic/app/makefile.mk
@@ -0,0 +1,110 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=salapp
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+SLOFILES=\
+ $(SLO)$/i18n_cb.obj \
+ $(SLO)$/i18n_ic.obj \
+ $(SLO)$/i18n_im.obj \
+ $(SLO)$/i18n_xkb.obj \
+ $(SLO)$/i18n_wrp.obj \
+ $(SLO)$/i18n_status.obj \
+ $(SLO)$/i18n_keysym.obj \
+ $(SLO)$/saldata.obj \
+ $(SLO)$/saltimer.obj \
+ $(SLO)$/saldisp.obj \
+ $(SLO)$/randrwrapper.obj \
+ $(SLO)$/salinst.obj \
+ $(SLO)$/salsys.obj \
+ $(SLO)$/soicon.obj \
+ $(SLO)$/sm.obj \
+ $(SLO)$/keysymnames.obj \
+ $(SLO)$/wmadaptor.obj
+
+EXCEPTIONSFILES=\
+ $(SLO)$/wmadaptor.obj \
+ $(SLO)$/saldata.obj \
+ $(SLO)$/salinst.obj \
+ $(SLO)$/saldisp.obj \
+ $(SLO)$/i18n_status.obj \
+ $(SLO)$/i18n_cb.obj \
+ $(SLO)$/i18n_ic.obj \
+ $(SLO)$/salsys.obj
+
+
+.IF "$(ENABLE_RANDR)" != ""
+CDEFS+=-DUSE_RANDR
+.IF "$(XRANDR_DLOPEN)" == "FALSE"
+CDEFS+=$(XRANDR_CFLAGS)
+.ELSE
+CDEFS+=-DXRANDR_DLOPEN
+.ENDIF
+.ENDIF
+
+.IF "$(USE_XINERAMA)" != "NO"
+CDEFS+=-DUSE_XINERAMA
+.IF "$(USE_XINERAMA_VERSION)" == "Xorg"
+CDEFS+=-DUSE_XINERAMA_XORG
+.ELIF "$(USE_XINERAMA_VERSION)" == "Xsun"
+CDEFS+=-DUSE_XINERAMA_XSUN
+.ELSE
+# provide sensible default
+.IF "$(OS)" != "SOLARIS"
+CDEFS+=-DUSE_XINERAMA_XORG
+.ELSE
+CDEFS+=-DUSE_XINERAMA_XSUN
+.ENDIF
+.ENDIF
+.ENDIF
+
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
diff --git a/vcl/unx/generic/app/randrwrapper.cxx b/vcl/unx/generic/app/randrwrapper.cxx
new file mode 100644
index 000000000000..e7f37c00e2ca
--- /dev/null
+++ b/vcl/unx/generic/app/randrwrapper.cxx
@@ -0,0 +1,360 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifdef USE_RANDR
+
+#include <tools/prex.h>
+#include <X11/extensions/Xrandr.h>
+#include <tools/postx.h>
+
+#include "osl/module.h"
+#include "rtl/ustring.hxx"
+
+namespace
+{
+
+# ifdef XRANDR_DLOPEN
+
+class RandRWrapper
+{
+ oslModule m_pRandRLib;
+
+ // function pointers
+ Bool(*m_pXRRQueryExtension)(Display*,int*,int*);
+ Status(*m_pXRRQueryVersion)(Display*,int*,int*);
+ XRRScreenConfiguration*(*m_pXRRGetScreenInfo)(Display*,Drawable);
+ void(*m_pXRRFreeScreenConfigInfo)(XRRScreenConfiguration*);
+ void(*m_pXRRSelectInput)(Display*,XLIB_Window,int);
+ int(*m_pXRRUpdateConfiguration)(XEvent*);
+ XRRScreenSize*(*m_pXRRSizes)(Display*,int,int*);
+ XRRScreenSize*(*m_pXRRConfigSizes)(XRRScreenConfiguration*,int*);
+ SizeID(*m_pXRRConfigCurrentConfiguration)(XRRScreenConfiguration*,Rotation*);
+ int(*m_pXRRRootToScreen)(Display*, XLIB_Window);
+
+ bool m_bValid;
+
+ void initFromModule();
+
+ RandRWrapper(Display*);
+ ~RandRWrapper();
+public:
+ static RandRWrapper& get(Display*);
+ static void releaseWrapper();
+
+ Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base )
+ {
+ Bool bRet = False;
+ if( m_bValid )
+ bRet = m_pXRRQueryExtension( i_pDisp, o_event_base, o_error_base );
+ return bRet;
+ }
+ Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor )
+ {
+ return m_bValid ? m_pXRRQueryVersion( i_pDisp, o_major, o_minor ) : 0;
+ }
+ XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable )
+ {
+ return m_bValid ? m_pXRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL;
+ }
+ void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig )
+ {
+ if( m_bValid )
+ m_pXRRFreeScreenConfigInfo( i_pConfig );
+ }
+ void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask )
+ {
+ if( m_bValid )
+ m_pXRRSelectInput( i_pDisp, i_window, i_nMask );
+ }
+ int XRRUpdateConfiguration( XEvent* i_pEvent )
+ {
+ return m_bValid ? m_pXRRUpdateConfiguration( i_pEvent ) : 0;
+ }
+ XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens )
+ {
+ return m_bValid ? m_pXRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL;
+ }
+ XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes )
+ {
+ return m_bValid ? m_pXRRConfigSizes( i_pConfig, o_nSizes ) : NULL;
+ }
+ SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot )
+ {
+ return m_bValid ? m_pXRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0;
+ }
+ int XRRRootToScreen( Display *dpy, XLIB_Window root )
+ {
+ return m_bValid ? m_pXRRRootToScreen( dpy, root ) : -1;
+ }
+};
+
+void RandRWrapper::initFromModule()
+{
+ m_pXRRQueryExtension = (Bool(*)(Display*,int*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRQueryExtension" );
+ m_pXRRQueryVersion = (Status(*)(Display*,int*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRQueryVersion" );
+ m_pXRRGetScreenInfo = (XRRScreenConfiguration*(*)(Display*,Drawable))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRGetScreenInfo" );
+ m_pXRRFreeScreenConfigInfo = (void(*)(XRRScreenConfiguration*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRFreeScreenConfigInfo" );
+ m_pXRRSelectInput = (void(*)(Display*,XLIB_Window,int))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRSelectInput" );
+ m_pXRRUpdateConfiguration = (int(*)(XEvent*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRUpdateConfiguration" );
+ m_pXRRSizes = (XRRScreenSize*(*)(Display*,int,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRSizes" );
+ m_pXRRConfigSizes = (XRRScreenSize*(*)(XRRScreenConfiguration*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRConfigSizes" );
+ m_pXRRConfigCurrentConfiguration = (SizeID(*)(XRRScreenConfiguration*,Rotation*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRConfigCurrentConfiguration" );
+ m_pXRRRootToScreen = (int(*)(Display*,XLIB_Window))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRRootToScreen" );
+
+ m_bValid = m_pXRRQueryExtension &&
+ m_pXRRQueryVersion &&
+ m_pXRRGetScreenInfo &&
+ m_pXRRFreeScreenConfigInfo &&
+ m_pXRRSelectInput &&
+ m_pXRRUpdateConfiguration &&
+ m_pXRRSizes &&
+ m_pXRRConfigSizes &&
+ m_pXRRConfigCurrentConfiguration &&
+ m_pXRRRootToScreen
+ ;
+}
+
+RandRWrapper::RandRWrapper( Display* pDisplay ) :
+ m_pRandRLib( NULL ),
+ m_pXRRQueryExtension( NULL ),
+ m_pXRRQueryVersion( NULL ),
+ m_pXRRGetScreenInfo( NULL ),
+ m_pXRRFreeScreenConfigInfo( NULL ),
+ m_pXRRSelectInput( NULL ),
+ m_pXRRUpdateConfiguration( NULL ),
+ m_pXRRSizes( NULL ),
+ m_pXRRConfigSizes( NULL ),
+ m_pXRRConfigCurrentConfiguration( NULL ),
+ m_pXRRRootToScreen( NULL ),
+ m_bValid( false )
+{
+ // first try in process space (e.g. gtk links that ?)
+ initFromModule();
+ if( ! m_bValid )
+ {
+ rtl::OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrandr.so.2" ) );
+ // load and resolve dependencies immediately
+ // rationale: there are older distributions where libXrandr.so.2 is not linked
+ // with libXext.so, resulting in a missing symbol and terminating the office
+ // obviously they expected libXext to be linked in global symbolspace (that is
+ // linked by the application), which is not the case with us (because we want
+ // to be able to run in headless mode even without an installed X11 library)
+ m_pRandRLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT | SAL_LOADMODULE_NOW );
+ initFromModule();
+ }
+ if( m_bValid )
+ {
+ int nEventBase = 0, nErrorBase = 0;
+ if( ! m_pXRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) )
+ m_bValid = false;
+ }
+}
+
+RandRWrapper::~RandRWrapper()
+{
+ if( m_pRandRLib )
+ osl_unloadModule( m_pRandRLib );
+}
+
+static RandRWrapper* pWrapper = NULL;
+
+RandRWrapper& RandRWrapper::get( Display* i_pDisplay )
+{
+ if( ! pWrapper )
+ pWrapper = new RandRWrapper( i_pDisplay );
+ return *pWrapper;
+}
+
+void RandRWrapper::releaseWrapper()
+{
+ delete pWrapper;
+ pWrapper = NULL;
+}
+
+# else
+
+class RandRWrapper
+{
+ bool m_bValid;
+
+ RandRWrapper(Display*);
+public:
+ static RandRWrapper& get(Display*);
+ static void releaseWrapper();
+
+ Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base )
+ {
+ Bool bRet = False;
+ if( m_bValid )
+ bRet = ::XRRQueryExtension( i_pDisp, o_event_base, o_error_base );
+ return bRet;
+ }
+ Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor )
+ {
+ return m_bValid ? ::XRRQueryVersion( i_pDisp, o_major, o_minor ) : 0;
+ }
+ XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable )
+ {
+ return m_bValid ? ::XRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL;
+ }
+ void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig )
+ {
+ if( m_bValid )
+ ::XRRFreeScreenConfigInfo( i_pConfig );
+ }
+ void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask )
+ {
+ if( m_bValid )
+ ::XRRSelectInput( i_pDisp, i_window, i_nMask );
+ }
+ int XRRUpdateConfiguration( XEvent* i_pEvent )
+ {
+ return m_bValid ? ::XRRUpdateConfiguration( i_pEvent ) : 0;
+ }
+ XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens )
+ {
+ return m_bValid ? ::XRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL;
+ }
+ XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes )
+ {
+ return m_bValid ? ::XRRConfigSizes( i_pConfig, o_nSizes ) : NULL;
+ }
+ SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot )
+ {
+ return m_bValid ? ::XRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0;
+ }
+ int XRRRootToScreen( Display *dpy, XLIB_Window root )
+ {
+ return m_bValid ? ::XRRRootToScreen( dpy, root ) : -1;
+ }
+};
+
+RandRWrapper::RandRWrapper( Display* pDisplay ) :
+ m_bValid( true )
+{
+ int nEventBase = 0, nErrorBase = 0;
+ if( !XRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) )
+ m_bValid = false;
+}
+
+static RandRWrapper* pWrapper = NULL;
+
+RandRWrapper& RandRWrapper::get( Display* i_pDisplay )
+{
+ if( ! pWrapper )
+ pWrapper = new RandRWrapper( i_pDisplay );
+ return *pWrapper;
+}
+
+void RandRWrapper::releaseWrapper()
+{
+ delete pWrapper;
+ pWrapper = NULL;
+}
+
+#endif
+
+} // namespace
+
+#endif
+
+#include "unx/saldisp.hxx"
+#include "unx/salframe.h"
+#if OSL_DEBUG_LEVEL > 1
+#include <cstdio>
+#endif
+
+void SalDisplay::InitRandR( XLIB_Window aRoot ) const
+{
+ #ifdef USE_RANDR
+ if( m_bUseRandRWrapper )
+ RandRWrapper::get( GetDisplay() ).XRRSelectInput( GetDisplay(), aRoot, RRScreenChangeNotifyMask );
+ #else
+ (void)aRoot;
+ #endif
+}
+
+void SalDisplay::DeInitRandR()
+{
+ #ifdef USE_RANDR
+ if( m_bUseRandRWrapper )
+ RandRWrapper::releaseWrapper();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SalDisplay::DeInitRandR()\n" );
+#endif
+ #endif
+}
+
+int SalDisplay::processRandREvent( XEvent* pEvent )
+{
+ int nRet = 0;
+ #ifdef USE_RANDR
+ XConfigureEvent* pCnfEvent=(XConfigureEvent*)pEvent;
+ if( m_bUseRandRWrapper && pWrapper && pWrapper->XRRRootToScreen(GetDisplay(),pCnfEvent->window) != -1 )
+ {
+ nRet = pWrapper->XRRUpdateConfiguration( pEvent );
+ if( nRet == 1 && pEvent->type != ConfigureNotify) // this should then be a XRRScreenChangeNotifyEvent
+ {
+ // update screens
+ bool bNotify = false;
+ for( size_t i = 0; i < m_aScreens.size(); i++ )
+ {
+ if( m_aScreens[i].m_bInit )
+ {
+ XRRScreenConfiguration *pConfig = NULL;
+ XRRScreenSize *pSizes = NULL;
+ int nSizes = 0;
+ Rotation nRot = 0;
+ SizeID nId = 0;
+
+ pConfig = pWrapper->XRRGetScreenInfo( GetDisplay(), m_aScreens[i].m_aRoot );
+ nId = pWrapper->XRRConfigCurrentConfiguration( pConfig, &nRot );
+ pSizes = pWrapper->XRRConfigSizes( pConfig, &nSizes );
+ XRRScreenSize *pTargetSize = pSizes + nId;
+
+ bNotify = bNotify ||
+ m_aScreens[i].m_aSize.Width() != pTargetSize->width ||
+ m_aScreens[i].m_aSize.Height() != pTargetSize->height;
+
+ m_aScreens[i].m_aSize = Size( pTargetSize->width, pTargetSize->height );
+
+ pWrapper->XRRFreeScreenConfigInfo( pConfig );
+
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "screen %d changed to size %dx%d\n", (int)i, (int)pTargetSize->width, (int)pTargetSize->height );
+ #endif
+ }
+ }
+ if( bNotify && ! m_aFrames.empty() )
+ m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ }
+ #else
+ (void)pEvent;
+ #endif
+ return nRet;
+}
diff --git a/vcl/unx/generic/app/saldata.cxx b/vcl/unx/generic/app/saldata.cxx
new file mode 100644
index 000000000000..1b72d55e21c5
--- /dev/null
+++ b/vcl/unx/generic/app/saldata.cxx
@@ -0,0 +1,867 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#ifdef USE_XTOOLKIT
+# define SAL_XT
+#endif
+
+// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <stdio.h> // snprintf, seems not to be in namespace std on every platform
+#include <limits.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/resource.h>
+#ifdef SUN
+#include <sys/systeminfo.h>
+#endif
+#ifdef AIX
+#include <strings.h>
+#endif
+#ifdef FREEBSD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#include <vos/process.hxx>
+#include <vos/mutex.hxx>
+
+#include "unx/Xproto.h"
+#include "unx/saldisp.hxx"
+#include "unx/saldata.hxx"
+#include "unx/salframe.h"
+#include "unx/sm.hxx"
+#include "unx/i18n_im.hxx"
+#include "unx/i18n_xkb.hxx"
+#include "salinst.hxx"
+
+#include <osl/signal.h>
+#include <osl/thread.h>
+#include <osl/process.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/bootstrap.hxx>
+
+#include <tools/debug.hxx>
+#include <vcl/svapp.hxx>
+
+// -=-= <signal.h> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef UNX
+#ifndef SIGBUS
+#define SIGBUS 10
+#endif
+#ifndef SIGSEGV
+#define SIGSEGV 11
+#endif
+#ifndef SIGIOT
+#define SIGIOT SIGABRT
+#endif
+#endif
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static const struct timeval noyield__ = { 0, 0 };
+static const struct timeval yield__ = { 0, 10000 };
+
+static const char* XRequest[] = {
+ // see /usr/lib/X11/XErrorDB, /usr/openwin/lib/XErrorDB ...
+ NULL,
+ "X_CreateWindow",
+ "X_ChangeWindowAttributes",
+ "X_GetWindowAttributes",
+ "X_DestroyWindow",
+ "X_DestroySubwindows",
+ "X_ChangeSaveSet",
+ "X_ReparentWindow",
+ "X_MapWindow",
+ "X_MapSubwindows",
+ "X_UnmapWindow",
+ "X_UnmapSubwindows",
+ "X_ConfigureWindow",
+ "X_CirculateWindow",
+ "X_GetGeometry",
+ "X_QueryTree",
+ "X_InternAtom",
+ "X_GetAtomName",
+ "X_ChangeProperty",
+ "X_DeleteProperty",
+ "X_GetProperty",
+ "X_ListProperties",
+ "X_SetSelectionOwner",
+ "X_GetSelectionOwner",
+ "X_ConvertSelection",
+ "X_SendEvent",
+ "X_GrabPointer",
+ "X_UngrabPointer",
+ "X_GrabButton",
+ "X_UngrabButton",
+ "X_ChangeActivePointerGrab",
+ "X_GrabKeyboard",
+ "X_UngrabKeyboard",
+ "X_GrabKey",
+ "X_UngrabKey",
+ "X_AllowEvents",
+ "X_GrabServer",
+ "X_UngrabServer",
+ "X_QueryPointer",
+ "X_GetMotionEvents",
+ "X_TranslateCoords",
+ "X_WarpPointer",
+ "X_SetInputFocus",
+ "X_GetInputFocus",
+ "X_QueryKeymap",
+ "X_OpenFont",
+ "X_CloseFont",
+ "X_QueryFont",
+ "X_QueryTextExtents",
+ "X_ListFonts",
+ "X_ListFontsWithInfo",
+ "X_SetFontPath",
+ "X_GetFontPath",
+ "X_CreatePixmap",
+ "X_FreePixmap",
+ "X_CreateGC",
+ "X_ChangeGC",
+ "X_CopyGC",
+ "X_SetDashes",
+ "X_SetClipRectangles",
+ "X_FreeGC",
+ "X_ClearArea",
+ "X_CopyArea",
+ "X_CopyPlane",
+ "X_PolyPoint",
+ "X_PolyLine",
+ "X_PolySegment",
+ "X_PolyRectangle",
+ "X_PolyArc",
+ "X_FillPoly",
+ "X_PolyFillRectangle",
+ "X_PolyFillArc",
+ "X_PutImage",
+ "X_GetImage",
+ "X_PolyText8",
+ "X_PolyText16",
+ "X_ImageText8",
+ "X_ImageText16",
+ "X_CreateColormap",
+ "X_FreeColormap",
+ "X_CopyColormapAndFree",
+ "X_InstallColormap",
+ "X_UninstallColormap",
+ "X_ListInstalledColormaps",
+ "X_AllocColor",
+ "X_AllocNamedColor",
+ "X_AllocColorCells",
+ "X_AllocColorPlanes",
+ "X_FreeColors",
+ "X_StoreColors",
+ "X_StoreNamedColor",
+ "X_QueryColors",
+ "X_LookupColor",
+ "X_CreateCursor",
+ "X_CreateGlyphCursor",
+ "X_FreeCursor",
+ "X_RecolorCursor",
+ "X_QueryBestSize",
+ "X_QueryExtension",
+ "X_ListExtensions",
+ "X_ChangeKeyboardMapping",
+ "X_GetKeyboardMapping",
+ "X_ChangeKeyboardControl",
+ "X_GetKeyboardControl",
+ "X_Bell",
+ "X_ChangePointerControl",
+ "X_GetPointerControl",
+ "X_SetScreenSaver",
+ "X_GetScreenSaver",
+ "X_ChangeHosts",
+ "X_ListHosts",
+ "X_SetAccessControl",
+ "X_SetCloseDownMode",
+ "X_KillClient",
+ "X_RotateProperties",
+ "X_ForceScreenSaver",
+ "X_SetPointerMapping",
+ "X_GetPointerMapping",
+ "X_SetModifierMapping",
+ "X_GetModifierMapping",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "X_NoOperation"
+};
+
+// -=-= C statics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+int X11SalData::XErrorHdl( Display *pDisplay, XErrorEvent *pEvent )
+{
+ GetX11SalData()->XError( pDisplay, pEvent );
+ return 0;
+}
+
+int X11SalData::XIOErrorHdl( Display * )
+{
+ /* #106197# hack: until a real shutdown procedure exists
+ * _exit ASAP
+ */
+ if( ImplGetSVData()->maAppData.mbAppQuit )
+ _exit(1);
+
+ // really bad hack
+ if( ! SessionManagerClient::checkDocumentsSaved() )
+ /* oslSignalAction eToDo = */ osl_raiseSignal (OSL_SIGNAL_USER_X11SUBSYSTEMERROR, NULL);
+
+ std::fprintf( stderr, "X IO Error\n" );
+ std::fflush( stdout );
+ std::fflush( stderr );
+
+ /* #106197# the same reasons to use _exit instead of exit in salmain
+ * do apply here. Since there is nothing to be done after an XIO
+ * error we have to _exit immediately.
+ */
+ _exit(0);
+ return 0;
+}
+
+// -=-= SalData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <pthread.h>
+
+X11SalData::X11SalData()
+{
+ bNoExceptions_ = !!getenv( "SAL_NOSEGV" );
+
+ pXLib_ = NULL;
+ m_pSalDisplay = NULL;
+ m_pInstance = NULL;
+ m_pPlugin = NULL;
+
+ hMainThread_ = pthread_self();
+ osl_getLocalHostname( &maLocalHostName.pData );
+}
+
+X11SalData::~X11SalData()
+{
+ DeleteDisplay();
+}
+
+void X11SalData::DeleteDisplay()
+{
+ delete m_pSalDisplay;
+ m_pSalDisplay = NULL;
+ delete pXLib_;
+ pXLib_ = NULL;
+}
+
+void X11SalData::Init()
+{
+ pXLib_ = new SalXLib();
+ pXLib_->Init();
+}
+
+void X11SalData::initNWF( void )
+{
+}
+
+void X11SalData::deInitNWF( void )
+{
+}
+
+// -=-= SalXLib =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalXLib::SalXLib()
+{
+ m_aTimeout.tv_sec = 0;
+ m_aTimeout.tv_usec = 0;
+ m_nTimeoutMS = 0;
+
+ nFDs_ = 0;
+ FD_ZERO( &aReadFDS_ );
+ FD_ZERO( &aExceptionFDS_ );
+
+ m_pTimeoutFDS[0] = m_pTimeoutFDS[1] = -1;
+ if (pipe (m_pTimeoutFDS) != -1)
+ {
+ // initialize 'wakeup' pipe.
+ int flags;
+
+ // set close-on-exec descriptor flag.
+ if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (m_pTimeoutFDS[0], F_SETFD, flags);
+ }
+ if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (m_pTimeoutFDS[1], F_SETFD, flags);
+ }
+
+ // set non-blocking I/O flag.
+ if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (m_pTimeoutFDS[0], F_SETFL, flags);
+ }
+ if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (m_pTimeoutFDS[1], F_SETFL, flags);
+ }
+
+ // insert [0] into read descriptor set.
+ FD_SET( m_pTimeoutFDS[0], &aReadFDS_ );
+ nFDs_ = m_pTimeoutFDS[0] + 1;
+ }
+
+ m_bHaveSystemChildFrames = false;
+ m_aOrigXIOErrorHandler = XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl );
+ PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) );
+}
+
+SalXLib::~SalXLib()
+{
+ // close 'wakeup' pipe.
+ close (m_pTimeoutFDS[0]);
+ close (m_pTimeoutFDS[1]);
+
+ PopXErrorLevel();
+ XSetIOErrorHandler (m_aOrigXIOErrorHandler);
+}
+
+void SalXLib::PushXErrorLevel( bool bIgnore )
+{
+ m_aXErrorHandlerStack.push_back( XErrorStackEntry() );
+ XErrorStackEntry& rEnt = m_aXErrorHandlerStack.back();
+ rEnt.m_bWas = false;
+ rEnt.m_bIgnore = bIgnore;
+ rEnt.m_nLastErrorRequest = 0;
+ rEnt.m_aHandler = XSetErrorHandler( (XErrorHandler)X11SalData::XErrorHdl );
+}
+
+void SalXLib::PopXErrorLevel()
+{
+ if( m_aXErrorHandlerStack.size() )
+ {
+ XSetErrorHandler( m_aXErrorHandlerStack.back().m_aHandler );
+ m_aXErrorHandlerStack.pop_back();
+ }
+}
+
+void SalXLib::Init()
+{
+ SalI18N_InputMethod* pInputMethod = new SalI18N_InputMethod;
+ pInputMethod->SetLocale();
+ XrmInitialize();
+
+ /*
+ * open connection to X11 Display
+ * try in this order:
+ * o -display command line parameter,
+ * o $DISPLAY environment variable
+ * o default display
+ */
+
+ Display *pDisp = NULL;
+
+ // is there a -display command line parameter?
+ vos::OExtCommandLine aCommandLine;
+ sal_uInt32 nParams = aCommandLine.getCommandArgCount();
+ rtl::OUString aParam;
+ rtl::OString aDisplay;
+ for (USHORT i=0; i<nParams; i++)
+ {
+ aCommandLine.getCommandArg(i, aParam);
+ if (aParam.equalsAscii("-display"))
+ {
+ aCommandLine.getCommandArg(i+1, aParam);
+ aDisplay = rtl::OUStringToOString(
+ aParam, osl_getThreadTextEncoding());
+
+ if ((pDisp = XOpenDisplay(aDisplay.getStr()))!=NULL)
+ {
+ /*
+ * if a -display switch was used, we need
+ * to set the environment accoringly since
+ * the clipboard build another connection
+ * to the xserver using $DISPLAY
+ */
+ rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("DISPLAY"));
+ osl_setEnvironment(envVar.pData, aParam.pData);
+ }
+ break;
+ }
+ }
+
+ if (!pDisp && !aDisplay.getLength())
+ {
+ // Open $DISPLAY or default...
+ char *pDisplay = getenv("DISPLAY");
+ if (pDisplay != NULL)
+ aDisplay = rtl::OString(pDisplay);
+ pDisp = XOpenDisplay(pDisplay);
+ }
+
+ if ( !pDisp )
+ {
+ rtl::OUString aProgramFileURL;
+ osl_getExecutableFile( &aProgramFileURL.pData );
+ rtl::OUString aProgramSystemPath;
+ osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
+ rtl::OString aProgramName = rtl::OUStringToOString(
+ aProgramSystemPath,
+ osl_getThreadTextEncoding() );
+ std::fprintf( stderr, "%s X11 error: Can't open display: %s\n",
+ aProgramName.getStr(), aDisplay.getStr());
+ std::fprintf( stderr, " Set DISPLAY environment variable, use -display option\n");
+ std::fprintf( stderr, " or check permissions of your X-Server\n");
+ std::fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n");
+ std::fflush( stderr );
+ exit(0);
+ }
+
+ SalDisplay *pSalDisplay = new SalX11Display( pDisp );
+
+ pInputMethod->CreateMethod( pDisp );
+ pInputMethod->AddConnectionWatch( pDisp, (void*)this );
+ pSalDisplay->SetInputMethod( pInputMethod );
+
+ PushXErrorLevel( true );
+ SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
+ XSync( pDisp, False );
+
+ pKbdExtension->UseExtension( ! HasXErrorOccured() );
+ PopXErrorLevel();
+
+ pSalDisplay->SetKbdExtension( pKbdExtension );
+}
+
+extern "C" {
+void EmitFontpathWarning( void )
+{
+ static Bool bOnce = False;
+ if ( !bOnce )
+ {
+ bOnce = True;
+ std::fprintf( stderr, "Please verify your fontpath settings\n"
+ "\t(See \"man xset\" for details"
+ " or ask your system administrator)\n" );
+ }
+}
+
+} /* extern "C" */
+
+static void PrintXError( Display *pDisplay, XErrorEvent *pEvent )
+{
+ char msg[ 120 ] = "";
+#if ! ( defined LINUX && defined PPC )
+ XGetErrorText( pDisplay, pEvent->error_code, msg, sizeof( msg ) );
+#endif
+ std::fprintf( stderr, "X-Error: %s\n", msg );
+ if( pEvent->request_code < capacityof( XRequest ) )
+ {
+ const char* pName = XRequest[pEvent->request_code];
+ if( !pName )
+ pName = "BadRequest?";
+ std::fprintf( stderr, "\tMajor opcode: %d (%s)\n", pEvent->request_code, pName );
+ }
+ else
+ {
+ std::fprintf( stderr, "\tMajor opcode: %d\n", pEvent->request_code );
+ // TODO: also display extension name?
+ std::fprintf( stderr, "\tMinor opcode: %d\n", pEvent->minor_code );
+ }
+
+ std::fprintf( stderr, "\tResource ID: 0x%lx\n",
+ pEvent->resourceid );
+ std::fprintf( stderr, "\tSerial No: %ld (%ld)\n",
+ pEvent->serial, LastKnownRequestProcessed(pDisplay) );
+
+ if( !getenv( "SAL_SYNCHRONIZE" ) )
+ {
+ std::fprintf( stderr, "These errors are reported asynchronously,\n");
+ std::fprintf( stderr, "set environment variable SAL_SYNCHRONIZE to 1 to help debugging\n");
+ }
+
+ std::fflush( stdout );
+ std::fflush( stderr );
+}
+
+void SalXLib::XError( Display *pDisplay, XErrorEvent *pEvent )
+{
+ if( m_bHaveSystemChildFrames )
+ return;
+
+ if( ! m_aXErrorHandlerStack.back().m_bIgnore )
+ {
+ if ( (pEvent->error_code == BadAlloc)
+ && (pEvent->request_code == X_OpenFont) )
+ {
+ static Bool bOnce = False;
+ if ( !bOnce )
+ {
+ std::fprintf(stderr, "X-Error occured in a request for X_OpenFont\n");
+ EmitFontpathWarning();
+
+ bOnce = True ;
+ }
+ return;
+ }
+ /* ignore
+ * X_SetInputFocus: it's a hint only anyway
+ * X_GetProperty: this is part of the XGetWindowProperty call and will
+ * be handled by the return value of that function
+ */
+ else if( pEvent->request_code == X_SetInputFocus ||
+ pEvent->request_code == X_GetProperty
+ )
+ return;
+
+
+ if( pDisplay != GetX11SalData()->GetDisplay()->GetDisplay() )
+ return;
+
+ PrintXError( pDisplay, pEvent );
+
+ oslSignalAction eToDo = osl_raiseSignal (OSL_SIGNAL_USER_X11SUBSYSTEMERROR, NULL);
+ switch (eToDo)
+ {
+ case osl_Signal_ActIgnore :
+ return;
+ case osl_Signal_ActAbortApp :
+ abort();
+ case osl_Signal_ActKillApp :
+ exit(0);
+ case osl_Signal_ActCallNextHdl :
+ break;
+ default :
+ break;
+ }
+
+ }
+
+ m_aXErrorHandlerStack.back().m_bWas = true;
+}
+
+struct YieldEntry
+{
+ YieldEntry* next; // pointer to next entry
+ int fd; // file descriptor for reading
+ void* data; // data for predicate and callback
+ YieldFunc pending; // predicate (determins pending events)
+ YieldFunc queued; // read and queue up events
+ YieldFunc handle; // handle pending events
+
+ inline int HasPendingEvent() const { return pending( fd, data ); }
+ inline int IsEventQueued() const { return queued( fd, data ); }
+ inline void HandleNextEvent() const { handle( fd, data ); }
+};
+
+#define MAX_NUM_DESCRIPTORS 128
+
+static YieldEntry yieldTable[ MAX_NUM_DESCRIPTORS ];
+
+void SalXLib::Insert( int nFD, void* data,
+ YieldFunc pending,
+ YieldFunc queued,
+ YieldFunc handle )
+{
+ DBG_ASSERT( nFD, "can not insert stdin descriptor" );
+ DBG_ASSERT( !yieldTable[nFD].fd, "SalXLib::Insert fd twice" );
+
+ yieldTable[nFD].fd = nFD;
+ yieldTable[nFD].data = data;
+ yieldTable[nFD].pending = pending;
+ yieldTable[nFD].queued = queued;
+ yieldTable[nFD].handle = handle;
+
+ FD_SET( nFD, &aReadFDS_ );
+ FD_SET( nFD, &aExceptionFDS_ );
+
+ if( nFD >= nFDs_ )
+ nFDs_ = nFD + 1;
+}
+
+void SalXLib::Remove( int nFD )
+{
+ FD_CLR( nFD, &aReadFDS_ );
+ FD_CLR( nFD, &aExceptionFDS_ );
+
+ yieldTable[nFD].fd = 0;
+
+ if ( nFD == nFDs_ )
+ {
+ for ( nFD = nFDs_ - 1;
+ nFD >= 0 && !yieldTable[nFD].fd;
+ nFD-- ) ;
+
+ nFDs_ = nFD + 1;
+ }
+}
+
+bool SalXLib::CheckTimeout( bool bExecuteTimers )
+{
+ bool bRet = false;
+ if( m_aTimeout.tv_sec ) // timer is started
+ {
+ timeval aTimeOfDay;
+ gettimeofday( &aTimeOfDay, 0 );
+ if( aTimeOfDay >= m_aTimeout )
+ {
+ bRet = true;
+ if( bExecuteTimers )
+ {
+ // timed out, update timeout
+ m_aTimeout = aTimeOfDay;
+ /*
+ * #107827# autorestart immediately, will be stopped (or set
+ * to different value in notify hdl if necessary;
+ * CheckTimeout should return false while
+ * timers are being dispatched.
+ */
+ m_aTimeout += m_nTimeoutMS;
+ // notify
+ GetX11SalData()->Timeout();
+ }
+ }
+ }
+ return bRet;
+}
+
+void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ // check for timeouts here if you want to make screenshots
+ static char* p_prioritize_timer = getenv ("SAL_HIGHPRIORITY_REPAINT");
+ if (p_prioritize_timer != NULL)
+ CheckTimeout();
+
+ // first, check for already queued events.
+ for ( int nFD = 0; nFD < nFDs_; nFD++ )
+ {
+ YieldEntry* pEntry = &(yieldTable[nFD]);
+ if ( pEntry->fd )
+ {
+ DBG_ASSERT( nFD == pEntry->fd, "wrong fd in Yield()" );
+ if ( pEntry->HasPendingEvent() )
+ {
+ pEntry->HandleNextEvent();
+ // #63862# da jetzt alle user-events ueber die interne
+ // queue kommen, wird die Kontrolle analog zum select
+ // gesteuerten Zweig einmal bei bWait abgegeben
+
+ /* #i9277# do not reschedule since performance gets down the
+ the drain under heavy load
+ YieldMutexReleaser aReleaser;
+ if ( bWait ) osl_yieldThread();
+ */
+
+ return;
+ }
+ }
+ }
+
+ // next, select with or without timeout according to bWait.
+ int nFDs = nFDs_;
+ fd_set ReadFDS = aReadFDS_;
+ fd_set ExceptionFDS = aExceptionFDS_;
+ int nFound = 0;
+
+ timeval Timeout = noyield__;
+ timeval *pTimeout = &Timeout;
+
+ if (bWait)
+ {
+ pTimeout = 0;
+ if (m_aTimeout.tv_sec) // Timer is started.
+ {
+ // determine remaining timeout.
+ gettimeofday (&Timeout, 0);
+ Timeout = m_aTimeout - Timeout;
+ if (yield__ >= Timeout)
+ {
+ // guard against micro timeout.
+ Timeout = yield__;
+ }
+ pTimeout = &Timeout;
+ }
+ }
+
+ {
+ // release YieldMutex (and re-acquire at block end)
+ YieldMutexReleaser aReleaser;
+ nFound = select( nFDs, &ReadFDS, NULL, &ExceptionFDS, pTimeout );
+ }
+ if( nFound < 0 ) // error
+ {
+#ifdef DBG_UTIL
+ std::fprintf( stderr, "SalXLib::Yield e=%d f=%d\n", errno, nFound );
+#endif
+ if( EINTR == errno )
+ {
+ errno = 0;
+ }
+ }
+
+ // usually handle timeouts here (as in 5.2)
+ if (p_prioritize_timer == NULL)
+ CheckTimeout();
+
+ // handle wakeup events.
+ if ((nFound > 0) && (FD_ISSET(m_pTimeoutFDS[0], &ReadFDS)))
+ {
+ int buffer;
+ while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0)
+ continue;
+ nFound -= 1;
+ }
+
+ // handle other events.
+ if( nFound > 0 )
+ {
+ // now we are in the protected section !
+ // recall select if we have acquired fd's, ready for reading,
+
+ struct timeval noTimeout = { 0, 0 };
+ nFound = select( nFDs_, &ReadFDS, NULL,
+ &ExceptionFDS, &noTimeout );
+
+ // someone-else has done the job for us
+ if (nFound == 0)
+ return;
+
+ for ( int nFD = 0; nFD < nFDs_; nFD++ )
+ {
+ YieldEntry* pEntry = &(yieldTable[nFD]);
+ if ( pEntry->fd )
+ {
+ if ( FD_ISSET( nFD, &ExceptionFDS ) ) {
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "SalXLib::Yield exception\n" );
+#endif
+ nFound--;
+ }
+ if ( FD_ISSET( nFD, &ReadFDS ) )
+ {
+ int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
+ for( int i = 0; pEntry->IsEventQueued() && i < nMaxEvents; i++ )
+ {
+ pEntry->HandleNextEvent();
+ // if a recursive call has done the job
+ // so abort here
+ }
+ nFound--;
+ }
+ }
+ }
+ }
+}
+
+void SalXLib::Wakeup()
+{
+ write (m_pTimeoutFDS[1], "", 1);
+}
+
+void SalXLib::PostUserEvent()
+{
+ Wakeup();
+}
+
+const char* X11SalData::getFrameResName()
+{
+ /* according to ICCCM:
+ * first search command line for -name parameter
+ * then try RESOURCE_NAME environment variable
+ * then use argv[0] stripped by directories
+ */
+ static rtl::OStringBuffer aResName;
+ if( !aResName.getLength() )
+ {
+ int nArgs = osl_getCommandArgCount();
+ for( int n = 0; n < nArgs-1; n++ )
+ {
+ rtl::OUString aArg;
+ if( ! osl_getCommandArg( n, &aArg.pData ) &&
+ aArg.equalsIgnoreAsciiCaseAscii( "-name" ) &&
+ ! osl_getCommandArg( n+1, &aArg.pData ) )
+ {
+ aResName.append( rtl::OUStringToOString( aArg, osl_getThreadTextEncoding() ) );
+ break;
+ }
+ }
+ if( !aResName.getLength() )
+ {
+ const char* pEnv = getenv( "RESOURCE_NAME" );
+ if( pEnv && *pEnv )
+ aResName.append( pEnv );
+ }
+ if( !aResName.getLength() )
+ aResName.append( "VCLSalFrame" );
+ }
+ return aResName.getStr();
+}
+
+const char* X11SalData::getFrameClassName()
+{
+ static rtl::OStringBuffer aClassName;
+ if( !aClassName.getLength() )
+ {
+ rtl::OUString aIni, aProduct;
+ rtl::Bootstrap::get( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aIni );
+ aIni += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
+ rtl::Bootstrap aBootstrap( aIni );
+ aBootstrap.getFrom( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ProductKey" ) ), aProduct );
+
+ if( aProduct.getLength() )
+ aClassName.append( rtl::OUStringToOString( aProduct, osl_getThreadTextEncoding() ) );
+ else
+ aClassName.append( "VCLSalFrame" );
+ }
+ return aClassName.getStr();
+}
+
+rtl::OString X11SalData::getFrameResName( SalExtStyle nStyle )
+{
+ rtl::OStringBuffer aBuf( 64 );
+ aBuf.append( getFrameResName() );
+ if( (nStyle & SAL_FRAME_EXT_STYLE_DOCUMENT) )
+ aBuf.append( ".DocumentWindow" );
+
+ return aBuf.makeStringAndClear();
+}
diff --git a/vcl/unx/generic/app/saldisp.cxx b/vcl/unx/generic/app/saldisp.cxx
new file mode 100644
index 000000000000..923d3d3e9ac4
--- /dev/null
+++ b/vcl/unx/generic/app/saldisp.cxx
@@ -0,0 +1,3435 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define SAL_XT
+
+// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+
+#if defined(SOLARIS)
+#include <sal/alloca.h>
+#include <osl/module.h>
+#endif
+
+#include <tools/prex.h>
+#include <X11/cursorfont.h>
+#include "unx/x11_cursors/salcursors.h"
+#include "unx/x11_cursors/invert50.h"
+#ifdef SOLARIS
+#define XK_KOREAN
+#endif
+#include <X11/keysym.h>
+
+#include <X11/Xatom.h>
+
+#ifdef USE_XINERAMA
+#ifdef USE_XINERAMA_XORG
+#include <X11/extensions/Xinerama.h>
+#elif defined USE_XINERAMA_XSUN
+#if defined(SOLARIS) && defined(INTEL) // missing extension header in standard installation
+#define MAXFRAMEBUFFERS 16
+Bool XineramaGetState(Display*, int);
+Status XineramaGetInfo(Display*, int, XRectangle*, unsigned char*, int*);
+#else
+#include <X11/extensions/xinerama.h>
+#endif
+#else
+#error USE_XINERAMA but no xinerama version
+#endif
+#endif
+
+#include <tools/postx.h>
+
+#include <unx/salunx.h>
+#include <sal/types.h>
+#include "unx/i18n_im.hxx"
+#include "unx/i18n_xkb.hxx"
+#include <unx/saldisp.hxx>
+#include <unx/saldata.hxx>
+#include <salinst.hxx>
+#include <unx/salgdi.h>
+#include <unx/salframe.h>
+#include <vcl/keycodes.hxx>
+#include <vcl/salbtype.hxx>
+#include <unx/salbmp.h>
+#ifndef _OSL_THREADMUTEX_H_
+#include <osl/mutex.h>
+#endif
+#include <unx/salobj.h>
+#include <unx/sm.hxx>
+#include <unx/wmadaptor.hxx>
+#include <unx/dtint.hxx>
+
+#include <osl/socket.h>
+#include <poll.h>
+
+using namespace rtl;
+using namespace vcl_sal;
+
+// -=-= #defines -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define PSEUDOCOLOR12
+#define PSEUDOCOLOR8
+#define TRUECOLOR24
+#define TRUECOLOR16
+#define TRUECOLOR15
+#define TRUECOLOR12
+#define TRUECOLOR8
+
+#define SALCOLOR_WHITE MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF )
+#define SALCOLOR_BLACK MAKE_SALCOLOR( 0x00, 0x00, 0x00 )
+
+// -=-= Prototyps =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-= static variables -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static const char* const VisualClassName[] = {
+ "StaticGray",
+ "GrayScale",
+ "StaticColor",
+ "PseudoColor",
+ "TrueColor",
+ "DirectColor"
+};
+
+static const char* const EventNames[] =
+{
+ NULL,
+ NULL,
+ "KeyPress",
+ "KeyRelease",
+ "ButtonPress",
+ "ButtonRelease",
+ "MotionNotify",
+ "EnterNotify",
+ "LeaveNotify",
+ "FocusIn",
+ "FocusOut",
+ "KeymapNotify",
+ "Expose",
+ "GraphicsExpose",
+ "NoExpose",
+ "VisibilityNotify",
+ "CreateNotify",
+ "DestroyNotify",
+ "UnmapNotify",
+ "MapNotify",
+ "MapRequest",
+ "ReparentNotify",
+ "ConfigureNotify",
+ "ConfigureRequest",
+ "GravityNotify",
+ "ResizeRequest",
+ "CirculateNotify",
+ "CirculateRequest",
+ "PropertyNotify",
+ "SelectionClear",
+ "SelectionRequest",
+ "SelectionNotify",
+ "ColormapNotify",
+ "ClientMessage",
+ "MappingNotify"
+};
+
+// -=-= global inline =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline const char *Null( const char *p ) { return p ? p : ""; }
+inline const char *GetEnv( const char *p ) { return Null( getenv( p ) ); }
+inline const char *KeyStr( KeySym n ) { return Null( XKeysymToString( n ) ); }
+
+inline const char *GetAtomName( Display *d, Atom a )
+{ return Null( XGetAtomName( d, a ) ); }
+
+inline double Hypothenuse( long w, long h )
+{ return sqrt( (double)((w*w)+(h*h)) ); }
+
+inline int ColorDiff( int r, int g, int b )
+{ return (r*r)+(g*g)+(b*b); }
+
+inline int ColorDiff( SalColor c1, int r, int g, int b )
+{ return ColorDiff( (int)SALCOLOR_RED (c1)-r,
+ (int)SALCOLOR_GREEN(c1)-g,
+ (int)SALCOLOR_BLUE (c1)-b ); }
+
+// -=-= global functions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static int sal_Shift( Pixel nMask )
+{
+ int i = 24;
+ if( nMask < 0x00010000 ) { nMask <<= 16; i -= 16; }
+ if( nMask < 0x01000000 ) { nMask <<= 8; i -= 8; }
+ if( nMask < 0x10000000 ) { nMask <<= 4; i -= 4; }
+ if( nMask < 0x40000000 ) { nMask <<= 2; i -= 2; }
+ if( nMask < 0x80000000 ) { nMask <<= 1; i -= 1; }
+ return i;
+}
+
+static int sal_significantBits( Pixel nMask )
+{
+ int nRotate = sizeof(Pixel)*4;
+ int nBits = 0;
+ while( nRotate-- )
+ {
+ if( nMask & 1 )
+ nBits++;
+ nMask >>= 1;
+ }
+ return nBits;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static BOOL sal_GetVisualInfo( Display *pDisplay, XID nVID, XVisualInfo &rVI )
+{
+ int nInfos;
+ XVisualInfo aTemplate;
+ XVisualInfo*pInfos;
+
+ aTemplate.visualid = nVID;
+
+ pInfos = XGetVisualInfo( pDisplay, VisualIDMask, &aTemplate, &nInfos );
+ if( !pInfos )
+ return FALSE;
+
+ rVI = *pInfos;
+ XFree( pInfos );
+
+ DBG_ASSERT( rVI.visualid == nVID,
+ "sal_GetVisualInfo: could not get correct visual by visualId" );
+ return TRUE;
+}
+
+// ---------------------------------------------------------------------------
+
+// check wether displaystring is in format N.M or N. or just N
+// with N and M beeing natural numbers
+static BOOL
+sal_IsDisplayNumber( const char *pDisplayString )
+{
+ if ( ! isdigit(*pDisplayString) )
+ return FALSE;
+ while ( isdigit(*(++pDisplayString)) )
+ ; /* do nothing */
+
+ if ( *pDisplayString == '.' )
+ {
+ while ( isdigit(*(++pDisplayString)) )
+ ; /* do nothing */
+ }
+
+ return (*pDisplayString == '\0');
+}
+
+// check whether host1 and host2 point to the same ip address
+static BOOL
+sal_EqualHosts( const OUString& Host1, const OUString& Host2)
+{
+ oslSocketAddr pHostAddr1;
+ oslSocketAddr pHostAddr2;
+ BOOL bEqualAddress = FALSE;
+
+ if ( Host1.toChar() >= '0' && Host1.toChar() <= '9' )
+ pHostAddr1 = osl_createInetSocketAddr( Host1.pData, 0 );
+ else
+ pHostAddr1 = osl_resolveHostname( Host1.pData );
+
+ if ( Host2.toChar() >= '0' && Host2.toChar() <= '9' )
+ pHostAddr2 = osl_createInetSocketAddr( Host2.pData, 0 );
+ else
+ pHostAddr2 = osl_resolveHostname( Host2.pData );
+
+ if( pHostAddr1 && pHostAddr2 )
+ bEqualAddress = osl_isEqualSocketAddr( pHostAddr1, pHostAddr2 ) ? TRUE : FALSE;
+
+ if( pHostAddr1 )
+ osl_destroySocketAddr( pHostAddr1 );
+ if( pHostAddr2 )
+ osl_destroySocketAddr( pHostAddr2 );
+
+ return bEqualAddress;
+}
+
+static BOOL
+sal_IsLocalDisplay( Display *pDisplay )
+{
+ const char *pDisplayString = DisplayString( pDisplay );
+
+ // no string, no idea
+ if ( pDisplayString == NULL || pDisplayString[ 0 ] == '\0')
+ return FALSE;
+
+ // check for ":x.y"
+ if ( pDisplayString[ 0 ] == ':' )
+ return sal_IsDisplayNumber( pDisplayString + 1 );
+
+ // check for fixed token which all mean localhost:x.y
+ const char pLocal[] = "localhost:";
+ const int nLocalLen = sizeof(pLocal) - 1;
+ if ( strncmp(pDisplayString, pLocal, nLocalLen) == 0 )
+ return sal_IsDisplayNumber( pDisplayString + nLocalLen );
+
+ const char pUnix[] = "unix:";
+ const int nUnixLen = sizeof(pUnix) - 1;
+ if ( strncmp(pDisplayString, pUnix, nUnixLen) == 0 )
+ return sal_IsDisplayNumber( pDisplayString + nUnixLen );
+
+ const char pLoopback[] = "127.0.0.1:";
+ const int nLoopbackLen= sizeof(pLoopback) - 1;
+ if ( strncmp(pDisplayString, pLoopback, nLoopbackLen) == 0 )
+ return sal_IsDisplayNumber( pDisplayString + nLoopbackLen );
+
+ // compare local hostname to displaystring, both may be ip address or
+ // hostname
+ BOOL bEqual = FALSE;
+ char *pDisplayHost = strdup( pDisplayString );
+ char *pPtr = strrchr( pDisplayHost, ':' );
+
+ if( pPtr != NULL )
+ {
+ const OUString& rLocalHostname( GetX11SalData()->GetLocalHostName() );
+ if( rLocalHostname.getLength() )
+ {
+ *pPtr = '\0';
+ OUString aDisplayHostname( pDisplayHost, strlen( pDisplayHost ), osl_getThreadTextEncoding() );
+ bEqual = sal_EqualHosts( rLocalHostname, aDisplayHostname );
+ bEqual = bEqual && sal_IsDisplayNumber( pPtr + 1 );
+ }
+ }
+ free( pDisplayHost );
+
+ return bEqual;
+}
+
+// ---------------------------------------------------------------------------
+// IsLocal means soffice is running on the same host as the xserver
+// since it is not called very often and sal_IsLocalDisplay() is relative
+// expensive bLocal_ is initialized on first call
+
+BOOL SalDisplay::IsLocal()
+{
+ if ( ! mbLocalIsValid )
+ {
+ bLocal_ = sal_IsLocalDisplay( pDisp_ );
+ mbLocalIsValid = TRUE;
+ }
+ return (BOOL)bLocal_;
+}
+
+// ---------------------------------------------------------------------------
+extern "C" srv_vendor_t
+sal_GetServerVendor( Display *p_display )
+{
+ typedef struct {
+ srv_vendor_t e_vendor; // vendor as enum
+ const char *p_name; // vendor name as returned by VendorString()
+ unsigned int n_len; // number of chars to compare
+ } vendor_t;
+
+ const vendor_t p_vendorlist[] = {
+ { vendor_xfree, "The XFree86 Project, Inc", 13 },
+ { vendor_sun, "Sun Microsystems, Inc.", 10 },
+ { vendor_attachmate, "Attachmate Corporation", 10 },
+ { vendor_excursion,
+ "DECWINDOWS DigitalEquipmentCorporation, eXcursion", 42 },
+ { vendor_hp, "Hewlett-Packard Company", 17 },
+ { vendor_hummingbird, "Hummingbird Communications Ltd.", 11 },
+ { vendor_ibm, "International Business Machines", 24 },
+ { vendor_sgi, "Silicon Graphics", 9 },
+ { vendor_sco, "The Santa Cruz Operation", 16 },
+ { vendor_xinside, "X Inside Inc.", 10 },
+ // allways the last entry: vendor_none to indicate eol
+ { vendor_none, NULL, 0 },
+ };
+
+ // handle regular server vendors
+ char *p_name = ServerVendor( p_display );
+ vendor_t *p_vendor;
+ for (p_vendor = const_cast<vendor_t*>(p_vendorlist); p_vendor->e_vendor != vendor_none; p_vendor++)
+ {
+ if ( strncmp (p_name, p_vendor->p_name, p_vendor->n_len) == 0 )
+ return p_vendor->e_vendor;
+ }
+
+ // vendor not found in list
+ return vendor_unknown;
+}
+
+static sal_Bool sal_IsTrustedSolaris (Display *p_display)
+{
+ int n_numextensions = 0;
+ char **p_extensions = XListExtensions (p_display, &n_numextensions);
+ sal_Bool b_is = sal_False;
+
+ if (p_extensions != NULL)
+ {
+ for (int i = 0; !b_is && i < n_numextensions; i++)
+ b_is = (strcmp (p_extensions[i], "SUN_TSOL") == 0);
+ XFreeExtensionList (p_extensions);
+ }
+
+ return b_is;
+}
+
+// -=-= SalDisplay -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+BOOL SalDisplay::BestVisual( Display *pDisplay,
+ int nScreen,
+ XVisualInfo &rVI )
+{
+ VisualID nDefVID = XVisualIDFromVisual( DefaultVisual( pDisplay, nScreen ) );
+ VisualID nVID = 0;
+ char *pVID = getenv( "SAL_VISUAL" );
+ if( pVID )
+ sscanf( pVID, "%li", &nVID );
+
+ if( nVID && sal_GetVisualInfo( pDisplay, nVID, rVI ) )
+ return rVI.visualid == nDefVID;
+
+ XVisualInfo aVI;
+ aVI.screen = nScreen;
+ // get all visuals
+ int nVisuals;
+ XVisualInfo* pVInfos = XGetVisualInfo( pDisplay, VisualScreenMask,
+ &aVI, &nVisuals );
+ // pVInfos should contain at least one visual, otherwise
+ // we're in trouble
+ int* pWeight = (int*)alloca( sizeof(int)*nVisuals );
+ int i;
+ for( i = 0; i < nVisuals; i++ )
+ {
+ BOOL bUsable = FALSE;
+ int nTrueColor = 1;
+
+ if ( pVInfos[i].screen != nScreen )
+ {
+ bUsable = FALSE;
+ }
+ else
+ if( pVInfos[i].c_class == TrueColor )
+ {
+ nTrueColor = 2048;
+ if( pVInfos[i].depth == 24 )
+ bUsable = TRUE;
+#ifdef TRUECOLOR8
+ else if( pVInfos[i].depth == 8 )
+ {
+ nTrueColor = -1; // strongly discourage 8 bit true color
+ bUsable = TRUE;
+ }
+#endif
+#ifdef TRUECOLOR15
+ else if( pVInfos[i].depth == 15 )
+ bUsable = TRUE;
+#endif
+#ifdef TRUECOLOR16
+ else if( pVInfos[i].depth == 16 )
+ bUsable = TRUE;
+#endif
+#ifdef TRUECOLOR32
+ else if( pVInfos[i].depth == 32 )
+ {
+ nTrueColor = 256;
+ // we do not have use for an alpha channel
+ // better use a 24 or 16 bit truecolor visual if possible
+ bUsable = TRUE;
+ }
+#endif
+ }
+ else if( pVInfos[i].c_class == PseudoColor )
+ {
+ if( pVInfos[i].depth <= 8 )
+ bUsable = TRUE;
+#ifdef PSEUDOCOLOR12
+ else if( pVInfos[i].depth == 12 )
+ bUsable = TRUE;
+#endif
+ }
+ pWeight[ i ] = bUsable ? nTrueColor*pVInfos[i].depth : -1024;
+ pWeight[ i ] -= pVInfos[ i ].visualid;
+ }
+
+ int nBestVisual = 0;
+ int nBestWeight = -1024;
+ for( i = 0; i < nVisuals; i++ )
+ {
+ if( pWeight[ i ] > nBestWeight )
+ {
+ nBestWeight = pWeight[ i ];
+ nBestVisual = i;
+ }
+ }
+
+ rVI = pVInfos[ nBestVisual ];
+
+ XFree( pVInfos );
+ return rVI.visualid == nDefVID;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+SalDisplay::SalDisplay( Display *display ) :
+ mpInputMethod( NULL ),
+ pDisp_( display ),
+ m_pWMAdaptor( NULL ),
+ m_pDtIntegrator( NULL ),
+ m_bUseRandRWrapper( true ),
+ m_nLastUserEventTime( CurrentTime )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SalDisplay::SalDisplay()\n" );
+#endif
+ X11SalData *pSalData = GetX11SalData();
+
+ DBG_ASSERT( ! pSalData->GetDisplay(), "Second SalDisplay created !!!\n" );
+ pSalData->SetSalDisplay( this );
+
+ pXLib_ = pSalData->GetLib();
+ m_nDefaultScreen = DefaultScreen( pDisp_ );
+
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalDisplay::~SalDisplay( )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SalDisplay::~SalDisplay()\n" );
+#endif
+ if( pDisp_ )
+ {
+ doDestruct();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "display %p closed\n", pDisp_ );
+#endif
+ pDisp_ = NULL;
+ }
+ // don't do this in doDestruct since RandR extension adds hooks into Display
+ // that is XCloseDisplay still needs the RandR library if it was used
+ DeInitRandR();
+}
+
+void SalDisplay::doDestruct()
+{
+ X11SalData *pSalData = GetX11SalData();
+
+ delete m_pWMAdaptor;
+ m_pWMAdaptor = NULL;
+ delete m_pDtIntegrator;
+ m_pDtIntegrator = NULL;
+ X11SalBitmap::ImplDestroyCache();
+ X11SalGraphics::releaseGlyphPeer();
+
+ if( IsDisplay() )
+ {
+ delete mpInputMethod, mpInputMethod = (SalI18N_InputMethod*)ILLEGAL_POINTER;
+ delete mpKbdExtension, mpKbdExtension = (SalI18N_KeyboardExtension*)ILLEGAL_POINTER;
+
+ // do not call anything that could implicitly call back into
+ // this object after this point
+ osl_destroyMutex( hEventGuard_ );
+
+ for( unsigned int i = 0; i < m_aScreens.size(); i++ )
+ {
+ ScreenData& rData = m_aScreens[i];
+ if( rData.m_bInit )
+ {
+ if( rData.m_aMonoGC != rData.m_aCopyGC )
+ XFreeGC( pDisp_, rData.m_aMonoGC );
+ XFreeGC( pDisp_, rData.m_aCopyGC );
+ XFreeGC( pDisp_, rData.m_aAndInvertedGC );
+ XFreeGC( pDisp_, rData.m_aAndGC );
+ XFreeGC( pDisp_, rData.m_aOrGC );
+ XFreeGC( pDisp_, rData.m_aStippleGC );
+ XFreePixmap( pDisp_, rData.m_hInvert50 );
+ XDestroyWindow( pDisp_, rData.m_aRefWindow );
+ Colormap aColMap = rData.m_aColormap.GetXColormap();
+ if( aColMap != None && aColMap != DefaultColormap( pDisp_, i ) )
+ XFreeColormap( pDisp_, aColMap );
+ }
+ }
+
+ hEventGuard_ = (oslMutex)ILLEGAL_POINTER;
+
+ for( size_t i = 0; i < POINTER_COUNT; i++ )
+ {
+ if( aPointerCache_[i] )
+ XFreeCursor( pDisp_, aPointerCache_[i] );
+ }
+
+ pXLib_->Remove( ConnectionNumber( pDisp_ ) );
+ }
+
+ if( pSalData->GetDisplay() == this )
+ pSalData->SetSalDisplay( NULL );
+}
+
+static int DisplayHasEvent( int
+#ifdef DBG_UTIL
+fd
+#endif
+, SalX11Display *pDisplay )
+{
+ DBG_ASSERT( ConnectionNumber( pDisplay->GetDisplay() ) == fd,
+ "wrong fd in DisplayHasEvent" );
+ if( ! pDisplay->IsDisplay() )
+ return 0;
+
+ vos::IMutex* pSalInstYieldMutex =
+ GetSalData()->m_pInstance->GetYieldMutex();
+ ::vos::OGuard aGuard( *pSalInstYieldMutex );
+ return pDisplay->IsEvent();
+}
+static int DisplayQueue( int
+#ifdef DBG_UTIL
+fd
+#endif
+, SalX11Display *pDisplay )
+{
+ DBG_ASSERT( ConnectionNumber( pDisplay->GetDisplay() ) == fd,
+ "wrong fd in DisplayHasEvent" );
+ vos::IMutex* pSalInstYieldMutex =
+ GetSalData()->m_pInstance->GetYieldMutex();
+ ::vos::OGuard aGuard( *pSalInstYieldMutex );
+ return XEventsQueued( pDisplay->GetDisplay(),
+ QueuedAfterReading );
+}
+static int DisplayYield( int
+#ifdef DBG_UTIL
+fd
+#endif
+, SalX11Display *pDisplay )
+{
+ DBG_ASSERT( ConnectionNumber( pDisplay->GetDisplay() ) == fd,
+ "wrong fd in DisplayHasEvent" );
+ vos::IMutex* pSalInstYieldMutex =
+ GetSalData()->m_pInstance->GetYieldMutex();
+ ::vos::OGuard aGuard( *pSalInstYieldMutex );
+ pDisplay->Yield();
+ return TRUE;
+}
+
+SalX11Display::SalX11Display( Display *display )
+ : SalDisplay( display )
+{
+ Init();
+
+ pXLib_->Insert( ConnectionNumber( pDisp_ ),
+ this,
+ (YieldFunc) DisplayHasEvent,
+ (YieldFunc) DisplayQueue,
+ (YieldFunc) DisplayYield );
+}
+
+SalX11Display::~SalX11Display()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SalX11Display::~SalX11Display()\n" );
+#endif
+ if( pDisp_ )
+ {
+ doDestruct();
+ XCloseDisplay( pDisp_ );
+ pDisp_ = NULL;
+ }
+}
+
+void SalDisplay::initScreen( int nScreen ) const
+{
+ if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) )
+ nScreen = m_nDefaultScreen;
+ ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
+ if( rSD.m_bInit )
+ return;
+ rSD.m_bInit = true;
+
+ XVisualInfo aVI;
+ Colormap aColMap;
+
+ if( SalDisplay::BestVisual( pDisp_, nScreen, aVI ) ) // DefaultVisual
+ aColMap = DefaultColormap( pDisp_, nScreen );
+ else
+ aColMap = XCreateColormap( pDisp_,
+ RootWindow( pDisp_, nScreen ),
+ aVI.visual,
+ AllocNone );
+
+ Screen* pScreen = ScreenOfDisplay( pDisp_, nScreen );
+
+ rSD.m_aSize = Size( WidthOfScreen( pScreen ), HeightOfScreen( pScreen ) );
+ rSD.m_aRoot = RootWindow( pDisp_, nScreen );
+ rSD.m_aVisual = SalVisual( &aVI );
+ rSD.m_aColormap = SalColormap( this, aColMap, nScreen );
+
+ // we're interested in configure notification of root windows
+ InitRandR( rSD.m_aRoot );
+
+ // - - - - - - - - - - Reference Window/Default Drawable - -
+ XSetWindowAttributes aXWAttributes;
+ aXWAttributes.border_pixel = 0;
+ aXWAttributes.background_pixel = 0;
+ aXWAttributes.colormap = aColMap;
+ rSD.m_aRefWindow = XCreateWindow( pDisp_,
+ rSD.m_aRoot,
+ 0,0, 16,16, 0,
+ rSD.m_aVisual.GetDepth(),
+ InputOutput,
+ rSD.m_aVisual.GetVisual(),
+ CWBorderPixel|CWBackPixel|CWColormap,
+ &aXWAttributes );
+
+ // set client leader (session id gets set when session is started)
+ if( rSD.m_aRefWindow )
+ {
+ // client leader must have WM_CLIENT_LEADER pointing to itself
+ XChangeProperty( pDisp_,
+ rSD.m_aRefWindow,
+ XInternAtom( pDisp_, "WM_CLIENT_LEADER", False ),
+ XA_WINDOW,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&rSD.m_aRefWindow,
+ 1
+ );
+
+ ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
+ const char* argv[2];
+ argv[0] = "/bin/sh";
+ argv[1] = aExec.GetBuffer();
+ XSetCommand( pDisp_, rSD.m_aRefWindow, const_cast<char**>(argv), 2 );
+ XSelectInput( pDisp_, rSD.m_aRefWindow, PropertyChangeMask );
+
+ // - - - - - - - - - - GCs - - - - - - - - - - - - - - - - -
+ XGCValues values;
+ values.graphics_exposures = False;
+ values.fill_style = FillOpaqueStippled;
+ values.background = (1<<rSD.m_aVisual.GetDepth())-1;
+ values.foreground = 0;
+
+ rSD.m_aCopyGC = XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground,
+ &values );
+ rSD.m_aAndInvertedGC= XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground,
+ &values );
+ rSD.m_aAndGC = XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground,
+ &values );
+ rSD.m_aOrGC = XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground,
+ &values );
+ rSD.m_aStippleGC = XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCFillStyle
+ | GCForeground
+ | GCBackground,
+ &values );
+
+ XSetFunction( pDisp_, rSD.m_aAndInvertedGC, GXandInverted );
+ XSetFunction( pDisp_, rSD.m_aAndGC, GXand );
+ // #44556# PowerPC Solaris 2.5 (XSun 3500) Bug: GXor = GXnop
+ //XSetFunction( pDisp_, pOrGC_, GXor );
+ XSetFunction( pDisp_, rSD.m_aOrGC, GXxor );
+
+ if( 1 == rSD.m_aVisual.GetDepth() )
+ {
+ XSetFunction( pDisp_, rSD.m_aCopyGC, GXcopyInverted );
+ rSD.m_aMonoGC = rSD.m_aCopyGC;
+ }
+ else
+ {
+ Pixmap hPixmap = XCreatePixmap( pDisp_, rSD.m_aRefWindow, 1, 1, 1 );
+ rSD.m_aMonoGC = XCreateGC( pDisp_,
+ hPixmap,
+ GCGraphicsExposures,
+ &values );
+ XFreePixmap( pDisp_, hPixmap );
+ }
+ rSD.m_hInvert50 = XCreateBitmapFromData( pDisp_,
+ rSD.m_aRefWindow,
+ invert50_bits,
+ invert50_width,
+ invert50_height );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalDisplay::Init()
+{
+ for( size_t i = 0; i < POINTER_COUNT; i++ )
+ aPointerCache_[i] = None;
+
+ eWindowManager_ = otherwm;
+ nProperties_ = PROPERTY_DEFAULT;
+ hEventGuard_ = NULL;
+ mpFactory = (AttributeProvider*)NULL;
+ m_pCapture = NULL;
+ m_bXinerama = false;
+
+ int nDisplayScreens = ScreenCount( pDisp_ );
+ m_aScreens = std::vector<ScreenData>(nDisplayScreens);
+
+ mbExactResolution = false;
+ /* #i15507#
+ * Xft resolution should take precedence since
+ * it is what modern desktops use.
+ */
+ const char* pValStr = XGetDefault( pDisp_, "Xft", "dpi" );
+ if( pValStr != NULL )
+ {
+ const rtl::OString aValStr( pValStr );
+ const long nDPI = (long) aValStr.toDouble();
+ // guard against insane resolution
+ if( (nDPI >= 50) && (nDPI <= 500) )
+ {
+ aResolution_ = Pair( nDPI, nDPI );
+ mbExactResolution = true;
+ }
+ }
+ if( mbExactResolution == false )
+ {
+ aResolution_ =
+ Pair( DPI( WidthOfScreen( DefaultScreenOfDisplay( pDisp_ ) ), DisplayWidthMM ( pDisp_, m_nDefaultScreen ) ),
+ DPI( HeightOfScreen( DefaultScreenOfDisplay( pDisp_ ) ), DisplayHeightMM( pDisp_, m_nDefaultScreen ) ) );
+ }
+
+ nMaxRequestSize_ = XExtendedMaxRequestSize( pDisp_ ) * 4;
+ if( !nMaxRequestSize_ )
+ nMaxRequestSize_ = XMaxRequestSize( pDisp_ ) * 4;
+
+ SetServerVendor();
+ X11SalBitmap::ImplCreateCache();
+
+ hEventGuard_ = osl_createMutex();
+ bLocal_ = FALSE; /* dont care, initialize later by
+ calling SalDisplay::IsLocal() */
+ mbLocalIsValid = FALSE; /* bLocal_ is not yet initialized */
+
+ // - - - - - - - - - - Synchronize - - - - - - - - - - - - -
+ if( getenv( "SAL_SYNCHRONIZE" ) )
+ XSynchronize( pDisp_, True );
+
+ // - - - - - - - - - - Keyboardmapping - - - - - - - - - - -
+ ModifierMapping();
+
+ // - - - - - - - - - - Window Manager - - - - - - - - - - -
+ m_pWMAdaptor = ::vcl_sal::WMAdaptor::createWMAdaptor( this );
+ const char *pWM = getenv( "SAL_WM" );
+ if( pWM )
+ {
+ long int nWM = 0;
+ sscanf( pWM, "%li", &nWM );
+ eWindowManager_ = SalWM(nWM);
+ }
+ else if( XInternAtom( pDisp_, "_SGI_TELL_WM", True ) )
+ eWindowManager_ = FourDwm;
+ else if( XInternAtom( pDisp_, "KWM_RUNNING", True ) )
+ eWindowManager_ = mwm; // naja, eigentlich kwm ...
+ else if( XInternAtom( pDisp_, "_OL_WIN_ATTR", True ) )
+ eWindowManager_ = olwm;
+ else if( m_pWMAdaptor->getWindowManagerName().EqualsAscii( "Dtwm" ) )
+ eWindowManager_ = dtwm;
+
+ // - - - - - - - - - - Properties - - - - - - - - - - - - -
+ const char *pProperties = getenv( "SAL_PROPERTIES" );
+ if( pProperties )
+ sscanf( pProperties, "%li", &nProperties_ );
+ else
+ {
+#if defined DBG_UTIL || defined SUN || defined LINUX || defined FREEBSD
+ nProperties_ |= PROPERTY_FEATURE_Maximize;
+#endif
+ // Server Bugs & Properties
+ if( GetServerVendor() == vendor_excursion )
+ {
+ nProperties_ |= PROPERTY_BUG_Stipple;
+ nProperties_ |= PROPERTY_BUG_DrawLine;
+ nProperties_ &= ~PROPERTY_SUPPORT_XSetClipMask;
+ }
+ else
+ if( GetServerVendor() == vendor_attachmate )
+ {
+ nProperties_ |= PROPERTY_BUG_CopyPlane_RevertBWPixel;
+ }
+ else
+ if( GetServerVendor() == vendor_ibm )
+ {
+ nProperties_ |= PROPERTY_BUG_XA_FAMILY_NAME_nil;
+
+ if( otherwm == eWindowManager_ ) eWindowManager_ = mwm;
+ }
+ else
+ if( GetServerVendor() == vendor_xfree )
+ {
+ nProperties_ |= PROPERTY_BUG_XCopyArea_GXxor;
+#if defined LINUX || defined FREEBSD
+ // otherwm and olwm are a kind of default, which are not detected
+ // carefully. if we are running linux (i.e. not netbsd) on an xfree
+ // display, fvwm is most probable the wm to choose, confusing with mwm
+ // doesn't harm. #57791# start maximized if possible
+ if( (otherwm == eWindowManager_)
+ || (olwm == eWindowManager_ ))
+ {
+ eWindowManager_ = fvwm; // ???
+ nProperties_ |= PROPERTY_FEATURE_Maximize;
+ }
+#else
+ if( otherwm == eWindowManager_ ) eWindowManager_ = winmgr;
+#endif
+#if defined SOLARIS && defined SPARC
+ nProperties_ |= PROPERTY_BUG_Bitmap_Bit_Order;
+ // solaris xlib seems to have problems with putting images
+ // in correct bit order to xfree 8 bit displays
+#endif
+ }
+ else
+ if( GetServerVendor() == vendor_sun )
+ {
+ // nicht alle! (bekannt: nur Sparc II CG3, CG6?)
+ nProperties_ &= ~PROPERTY_SUPPORT_XSetClipMask;
+
+ // trusted solaris doesn't allow to change properties on the
+ // wm decoration window
+ if (sal_IsTrustedSolaris (pDisp_))
+ nProperties_ |= PROPERTY_FEATURE_TrustedSolaris;
+
+ // Fehler im Sun-Solaris X86 Server !
+ if (ImageByteOrder(GetDisplay()) == LSBFirst)
+ {
+ nProperties_ |= PROPERTY_BUG_Tile;
+ nProperties_ |= PROPERTY_SUPPORT_3ButtonMouse;
+ }
+ else // MSBFirst Sun-Solaris Sparc Server
+ {
+ // XCopyPlane reverts black and white for 1bit bitmaps
+ // only sun, only 8bit pseudocolor target
+ if ( (GetVisual(m_nDefaultScreen).GetDepth() == 8)
+ && (GetVisual(m_nDefaultScreen).GetClass() == PseudoColor))
+ nProperties_ |= PROPERTY_BUG_CopyPlane_RevertBWPixel;
+ // Fehler in Solaris 2.5.1
+ if (VendorRelease ( GetDisplay() ) < 3600)
+ nProperties_ |= PROPERTY_BUG_FillPolygon_Tile;
+ }
+
+ if( otherwm == eWindowManager_ )
+ eWindowManager_ = olwm;
+ }
+ else
+ if( GetServerVendor() == vendor_sco )
+ {
+ if( otherwm == eWindowManager_ ) eWindowManager_ = pmwm;
+ }
+ else
+ if( GetServerVendor() == vendor_sgi )
+ {
+ if( GetVisual( m_nDefaultScreen ).GetDepth() > 8 && GetVisual( m_nDefaultScreen ).GetDepth() <= 16 )
+ nProperties_ |= PROPERTY_BUG_XCopyArea_GXxor;
+ nProperties_ |= PROPERTY_SUPPORT_XSetClipMask;
+
+ if( otherwm == eWindowManager_ )
+ eWindowManager_ = FourDwm;
+ }
+ else
+ if( GetServerVendor() == vendor_hp )
+ {
+ if( otherwm == eWindowManager_ ) eWindowManager_ = dtwm;
+ }
+ else
+ if( GetServerVendor() == vendor_hummingbird )
+ {
+ if (GetVisual(m_nDefaultScreen).GetDepth() == 24)
+ nProperties_ |= PROPERTY_BUG_CopyArea_OnlySmallSlices;
+ }
+
+ if( otherwm == eWindowManager_ )
+ {
+ if( !XInternAtom( pDisp_, "_MOTIF_WM_INFO", True ) )
+ eWindowManager_ = olwm;
+ // ???
+ }
+
+ if( winmgr == eWindowManager_ )
+ {
+ nProperties_ &= ~PROPERTY_SUPPORT_WM_SetPos;
+ nProperties_ &= ~PROPERTY_SUPPORT_WM_Screen;
+ nProperties_ |= PROPERTY_FEATURE_Maximize;
+ }
+ else if( dtwm == eWindowManager_ )
+ {
+ nProperties_ &= ~PROPERTY_SUPPORT_WM_ClientPos;
+ }
+ else if( pmwm == eWindowManager_ )
+ {
+ nProperties_ &= ~PROPERTY_SUPPORT_WM_ClientPos;
+ }
+ }
+
+ InitXinerama();
+
+ // initialize system settings update
+ m_pDtIntegrator = DtIntegrator::CreateDtIntegrator();
+
+#ifdef DBG_UTIL
+ PrintInfo();
+#endif
+}
+
+// Sound
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalDisplay::Beep() const
+{
+ XBell( pDisp_, 0 );
+}
+
+// Keyboard
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+String SalDisplay::GetKeyNameFromKeySym( KeySym nKeySym ) const
+{
+ String aRet;
+
+ // return an empty string for keysyms that are not bound to
+ // any key code
+ XLIB_KeyCode aKeyCode = XKeysymToKeycode( GetDisplay(), nKeySym );
+ if( aKeyCode != 0 && aKeyCode != NoSymbol )
+ {
+ if( !nKeySym )
+ aRet = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "???" ) );
+ else
+ {
+ aRet = ::vcl_sal::getKeysymReplacementName( const_cast<SalDisplay*>(this)->GetKeyboardName(), nKeySym );
+ if( ! aRet.Len() )
+ {
+ const char *pString = XKeysymToString( nKeySym );
+ int n = strlen( pString );
+ if( n > 2 && pString[n-2] == '_' )
+ aRet = String( pString, n-2, RTL_TEXTENCODING_ISO_8859_1 );
+ else
+ aRet = String( pString, n, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+ }
+ return aRet;
+}
+
+inline KeySym sal_XModifier2Keysym( Display *pDisplay,
+ XModifierKeymap *pXModMap,
+ int n )
+{
+ return XKeycodeToKeysym( pDisplay,
+ pXModMap->modifiermap[n*pXModMap->max_keypermod],
+ 0 );
+}
+
+void SalDisplay::ModifierMapping()
+{
+ XModifierKeymap *pXModMap = XGetModifierMapping( pDisp_ );
+
+ bNumLockFromXS_ = True;
+ nShiftKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ShiftMapIndex );
+ nCtrlKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ControlMapIndex );
+ nMod1KeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, Mod1MapIndex );
+ // Auf Sun-Servern und SCO-Severn beruecksichtigt XLookupString
+ // nicht den NumLock Modifier.
+ if( (GetServerVendor() == vendor_sun)
+ || (GetServerVendor() == vendor_sco) )
+ {
+ XLIB_KeyCode aNumLock = XKeysymToKeycode( pDisp_, XK_Num_Lock );
+
+ if( aNumLock ) for( int i = ShiftMapIndex; i <= Mod5MapIndex; i++ )
+ {
+ if( pXModMap->modifiermap[i*pXModMap->max_keypermod] == aNumLock )
+ {
+ bNumLockFromXS_ = False;
+ nNumLockIndex_ = i;
+ nNumLockMask_ = 1<<i;
+ break;
+ }
+ }
+ }
+
+ XFreeModifiermap( pXModMap );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+XubString SalDisplay::GetKeyName( USHORT nKeyCode ) const
+{
+ String aStrMap;
+
+ if( nKeyCode & KEY_MOD1 )
+ aStrMap += GetKeyNameFromKeySym( nCtrlKeySym_ );
+
+ if( nKeyCode & KEY_MOD2 )
+ {
+ if( aStrMap.Len() )
+ aStrMap += '+';
+ aStrMap += GetKeyNameFromKeySym( nMod1KeySym_ );
+ }
+
+ if( nKeyCode & KEY_SHIFT )
+ {
+ if( aStrMap.Len() )
+ aStrMap += '+';
+ aStrMap += GetKeyNameFromKeySym( nShiftKeySym_ );
+ }
+ nKeyCode &= 0x0FFF;
+
+ KeySym nKeySym = 0;
+
+ if( KEY_0 <= nKeyCode && nKeyCode <= KEY_9 )
+ nKeySym = XK_0 + (nKeyCode - KEY_0);
+ else if( KEY_A <= nKeyCode && nKeyCode <= KEY_Z )
+ nKeySym = XK_A + (nKeyCode - KEY_A);
+ else if( KEY_F1 <= nKeyCode && nKeyCode <= KEY_F26 ) // Existiert die Taste
+ nKeySym = XK_F1 + (nKeyCode - KEY_F1);
+ else switch( nKeyCode )
+ {
+ case KEY_DOWN:
+ nKeySym = XK_Down;
+ break;
+ case KEY_UP:
+ nKeySym = XK_Up;
+ break;
+ case KEY_LEFT:
+ nKeySym = XK_Left;
+ break;
+ case KEY_RIGHT:
+ nKeySym = XK_Right;
+ break;
+ case KEY_HOME:
+ nKeySym = XK_Home;
+ break;
+ case KEY_END:
+ nKeySym = XK_End;
+ break;
+ case KEY_PAGEUP:
+ nKeySym = XK_Prior;
+ break;
+ case KEY_PAGEDOWN:
+ nKeySym = XK_Next;
+ break;
+ case KEY_RETURN:
+ nKeySym = XK_Return;
+ break;
+ case KEY_ESCAPE:
+ nKeySym = XK_Escape;
+ break;
+ case KEY_TAB:
+ nKeySym = XK_Tab;
+ break;
+ case KEY_BACKSPACE:
+ nKeySym = XK_BackSpace;
+ break;
+ case KEY_SPACE:
+ nKeySym = XK_space;
+ break;
+ case KEY_INSERT:
+ nKeySym = XK_Insert;
+ break;
+ case KEY_DELETE:
+ nKeySym = XK_Delete;
+ break;
+
+ #if !defined (SunXK_Undo)
+ #define SunXK_Stop 0x0000FF69 // XK_Cancel
+ #define SunXK_Props 0x1005FF70
+ #define SunXK_Front 0x1005FF71
+ #define SunXK_Copy 0x1005FF72
+ #define SunXK_Open 0x1005FF73
+ #define SunXK_Paste 0x1005FF74
+ #define SunXK_Cut 0x1005FF75
+ #endif
+
+ case KEY_REPEAT:
+ nKeySym = XK_Redo;
+ break;
+ case KEY_PROPERTIES:
+ nKeySym = SunXK_Props;
+ break;
+ case KEY_UNDO:
+ nKeySym = XK_Undo;
+ break;
+ case KEY_FRONT:
+ nKeySym = SunXK_Front;
+ break;
+ case KEY_COPY:
+ nKeySym = SunXK_Copy;
+ break;
+ case KEY_OPEN:
+ nKeySym = SunXK_Open;
+ break;
+ case KEY_PASTE:
+ nKeySym = SunXK_Paste;
+ break;
+ case KEY_FIND:
+ nKeySym = XK_Find;
+ break;
+ case KEY_CUT:
+ nKeySym = GetServerVendor() == vendor_sun ? SunXK_Cut : XK_L10;
+ break;
+ case KEY_ADD:
+ nKeySym = XK_plus;
+ break;
+ case KEY_SUBTRACT:
+ nKeySym = XK_minus;
+ break;
+ case KEY_MULTIPLY:
+ nKeySym = XK_asterisk;
+ break;
+ case KEY_DIVIDE:
+ nKeySym = XK_slash;
+ break;
+ case KEY_POINT:
+ nKeySym = XK_period;
+ break;
+ case KEY_COMMA:
+ nKeySym = XK_comma;
+ break;
+ case KEY_LESS:
+ nKeySym = XK_less;
+ break;
+ case KEY_GREATER:
+ nKeySym = XK_greater;
+ break;
+ case KEY_EQUAL:
+ nKeySym = XK_equal;
+ break;
+ case KEY_HELP:
+ nKeySym = XK_Help;
+ break;
+ case KEY_HANGUL_HANJA:
+ nKeySym = XK_Hangul_Hanja;
+ break;
+ case KEY_TILDE:
+ nKeySym = XK_asciitilde;
+ break;
+ case KEY_QUOTELEFT:
+ nKeySym = XK_grave;
+ break;
+
+ default:
+ nKeySym = 0;
+ break;
+ }
+
+ if( nKeySym )
+ {
+ String aKeyName = GetKeyNameFromKeySym( nKeySym );
+ if( aKeyName.Len() )
+ {
+ if( aStrMap.Len() )
+ aStrMap += '+';
+ aStrMap += aKeyName;
+ }
+ else
+ aStrMap.Erase();
+ }
+ else
+ aStrMap.Erase();
+
+ return aStrMap;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef IsISOKey
+#define IsISOKey( n ) (0x0000FE00==((n)&0xFFFFFF00))
+#endif
+
+USHORT SalDisplay::GetKeyCode( KeySym keysym, char*pcPrintable ) const
+{
+ USHORT nKey = 0;
+
+ if( XK_a <= keysym && XK_z >= keysym )
+ nKey = (USHORT)(KEY_A + (keysym - XK_a));
+ else if( XK_A <= keysym && XK_Z >= keysym )
+ nKey = (USHORT)(KEY_A + (keysym - XK_A));
+ else if( XK_0 <= keysym && XK_9 >= keysym )
+ nKey = (USHORT)(KEY_0 + (keysym - XK_0));
+ else if( IsModifierKey( keysym ) )
+ ;
+ else if( IsKeypadKey( keysym ) )
+ {
+ if( (keysym >= XK_KP_0) && (keysym <= XK_KP_9) )
+ {
+ nKey = (USHORT)(KEY_0 + (keysym - XK_KP_0));
+ *pcPrintable = '0' + nKey - KEY_0;
+ }
+ else if( IsPFKey( keysym ) )
+ nKey = (USHORT)(KEY_F1 + (keysym - XK_KP_F1));
+ else switch( keysym )
+ {
+ case XK_KP_Space:
+ nKey = KEY_SPACE;
+ *pcPrintable = ' ';
+ break;
+ case XK_KP_Tab:
+ nKey = KEY_TAB;
+ break;
+ case XK_KP_Enter:
+ nKey = KEY_RETURN;
+ break;
+ case XK_KP_Begin:
+ case XK_KP_Home:
+ nKey = KEY_HOME;
+ break;
+ case XK_KP_Left:
+ nKey = KEY_LEFT;
+ break;
+ case XK_KP_Up:
+ nKey = KEY_UP;
+ break;
+ case XK_KP_Right:
+ nKey = KEY_RIGHT;
+ break;
+ case XK_KP_Down:
+ nKey = KEY_DOWN;
+ break;
+ case XK_KP_Prior: // XK_KP_Page_Up
+ nKey = KEY_PAGEUP;
+ break;
+ case XK_KP_Next: // XK_KP_Page_Down
+ nKey = KEY_PAGEDOWN;
+ break;
+ case XK_KP_End:
+ nKey = KEY_END;
+ break;
+ case XK_KP_Insert:
+ nKey = KEY_INSERT;
+ break;
+ case XK_KP_Delete:
+ nKey = KEY_DELETE;
+ break;
+ case XK_KP_Equal:
+ nKey = KEY_EQUAL;
+ *pcPrintable = '=';
+ break;
+ case XK_KP_Multiply:
+ nKey = KEY_MULTIPLY;
+ *pcPrintable = '*';
+ break;
+ case XK_KP_Add:
+ nKey = KEY_ADD;
+ *pcPrintable = '+';
+ break;
+ case XK_KP_Separator:
+ nKey = KEY_DECIMAL;
+ *pcPrintable = ',';
+ break;
+ case XK_KP_Subtract:
+ nKey = KEY_SUBTRACT;
+ *pcPrintable = '-';
+ break;
+ case XK_KP_Decimal:
+ nKey = KEY_DECIMAL;
+ *pcPrintable = '.';
+ break;
+ case XK_KP_Divide:
+ nKey = KEY_DIVIDE;
+ *pcPrintable = '/';
+ break;
+ }
+ }
+ else if( IsFunctionKey( keysym ) )
+ {
+ if( bNumLockFromXS_ )
+ {
+ if( keysym >= XK_F1 && keysym <= XK_F26 )
+ nKey = (USHORT)(KEY_F1 + keysym - XK_F1);
+ }
+ else switch( keysym )
+ {
+ // - - - - - Sun X-Server Tastatur ohne Cursorblock ??? - - -
+ case XK_R7: // XK_F27:
+ nKey = KEY_HOME;
+ break;
+ case XK_R8: // XK_F28:
+ nKey = KEY_UP;
+ break;
+ case XK_R9: // XK_F29:
+ nKey = KEY_PAGEUP;
+ break;
+ case XK_R10: // XK_F30:
+ nKey = KEY_LEFT;
+ break;
+ case XK_R11: // XK_F31:
+ nKey = 0; // KEY_F31
+ break;
+ case XK_R12: // XK_F32:
+ nKey = KEY_RIGHT;
+ break;
+ case XK_R13: // XK_F33:
+ nKey = KEY_END;
+ break;
+ case XK_R14: // XK_F34:
+ nKey = KEY_DOWN;
+ break;
+ case XK_R15: // XK_F35:
+ nKey = KEY_PAGEDOWN;
+ break;
+ // - - - - - Sun X-Server Tastatur ??? - - - - - - - - - - - -
+ case XK_L1: // XK_F11:
+ nKey = KEY_F11; // on a sun keyboard this actually is usally SunXK_Stop,
+ // but VCL doesn't have a key defintion for that
+ break;
+ case XK_L2: // XK_F12:
+ if ( GetServerVendor() == vendor_sun )
+ nKey = KEY_REPEAT;
+ else
+ nKey = KEY_F12;
+ break;
+ case XK_L3: // XK_F13:
+ nKey = KEY_PROPERTIES; // KEY_F13
+ break;
+ case XK_L4: // XK_F14:
+ nKey = KEY_UNDO; // KEY_F14
+ break;
+ case XK_L5: // XK_F15:
+ nKey = KEY_F15; // KEY_FRONT
+ break;
+ case XK_L6: // XK_F16:
+ nKey = KEY_COPY; // KEY_F16
+ break;
+ case XK_L7: // XK_F17:
+ nKey = KEY_F17; // KEY_OPEN
+ break;
+ case XK_L8: // XK_F18:
+ nKey = KEY_PASTE; // KEY_F18
+ break;
+ case XK_L9: // XK_F19:
+ nKey = KEY_F19; // KEY_FIND
+ break;
+ case XK_L10: // XK_F20:
+ nKey = KEY_CUT; // KEY_F20
+ break;
+ default:
+ if( keysym >= XK_F1 && keysym <= XK_F26 )
+ nKey = (USHORT)(KEY_F1 + keysym - XK_F1);
+ break;
+ }
+ }
+ else if( IsCursorKey( keysym ) )
+ {
+ switch( keysym )
+ {
+ case XK_Begin:
+ case XK_Home:
+ nKey = KEY_HOME;
+ break;
+ case XK_Left:
+ nKey = KEY_LEFT;
+ break;
+ case XK_Up:
+ nKey = KEY_UP;
+ break;
+ case XK_Right:
+ nKey = KEY_RIGHT;
+ break;
+ case XK_Down:
+ nKey = KEY_DOWN;
+ break;
+ case XK_Prior: // XK_Page_Up
+ nKey = KEY_PAGEUP;
+ break;
+ case XK_Next: // XK_Page_Down
+ nKey = KEY_PAGEDOWN;
+ break;
+ case XK_End:
+ nKey = KEY_END;
+ break;
+ }
+ }
+ else if( IsMiscFunctionKey( keysym ) )
+ {
+ switch( keysym )
+ {
+ case XK_Insert:
+ nKey = KEY_INSERT;
+ break;
+ case XK_Redo:
+ nKey = KEY_REPEAT;
+ break;
+ case XK_Undo:
+ nKey = KEY_UNDO;
+ break;
+ case XK_Find:
+ nKey = KEY_FIND;
+ break;
+ case XK_Help:
+ nKey = KEY_HELP;
+ break;
+ case XK_Menu:
+ nKey = KEY_CONTEXTMENU;
+ break;
+/*
+ case XK_Break:
+ case XK_Select:
+ case XK_Execute:
+ case XK_Print:
+ case XK_Cancel:
+*/
+ }
+ }
+ else if( IsISOKey( keysym ) ) // XK_ISO_
+ {
+ switch( keysym )
+ {
+ case 0xFE20: // XK_ISO_Left_Tab:
+ nKey = KEY_TAB;
+ break;
+ }
+ }
+ else switch( keysym )
+ {
+ case XK_Return:
+ nKey = KEY_RETURN;
+ break;
+ case XK_BackSpace:
+ nKey = KEY_BACKSPACE;
+ break;
+ case XK_Delete:
+ nKey = KEY_DELETE;
+ break;
+ case XK_space:
+ nKey = KEY_SPACE;
+ break;
+ case XK_Tab:
+ nKey = KEY_TAB;
+ break;
+ case XK_Escape:
+ nKey = KEY_ESCAPE;
+ break;
+ case XK_plus:
+ nKey = KEY_ADD;
+ break;
+ case XK_minus:
+ nKey = KEY_SUBTRACT;
+ break;
+ case XK_asterisk:
+ nKey = KEY_MULTIPLY;
+ break;
+ case XK_slash:
+ nKey = KEY_DIVIDE;
+ break;
+ case XK_period:
+ nKey = KEY_POINT;
+ break;
+ case XK_comma:
+ nKey = KEY_COMMA;
+ break;
+ case XK_less:
+ nKey = KEY_LESS;
+ break;
+ case XK_greater:
+ nKey = KEY_GREATER;
+ break;
+ case XK_equal:
+ nKey = KEY_EQUAL;
+ break;
+ case XK_Hangul_Hanja:
+ nKey = KEY_HANGUL_HANJA;
+ break;
+ case XK_asciitilde:
+ nKey = KEY_TILDE;
+ *pcPrintable = '~';
+ break;
+ case XK_grave:
+ nKey = KEY_QUOTELEFT;
+ *pcPrintable = '`';
+ break;
+// case XK_Linefeed:
+// *pcPrintable = '\n';
+// break;
+ // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
+ case 0x1000FF02: // apXK_Copy
+ nKey = KEY_COPY;
+ break;
+ case 0x1000FF03: // apXK_Cut
+ nKey = KEY_CUT;
+ break;
+ case 0x1000FF04: // apXK_Paste
+ nKey = KEY_PASTE;
+ break;
+ case 0x1000FF14: // apXK_Repeat
+ nKey = KEY_REPEAT;
+ break;
+ // Exit, Save
+ // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
+ case 0x1000FF00:
+ nKey = KEY_DELETE;
+ break;
+ // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
+ case 0x1000FF73: // hpXK_DeleteChar
+ nKey = KEY_DELETE;
+ break;
+ case 0x1000FF74: // hpXK_BackTab
+ case 0x1000FF75: // hpXK_KP_BackTab
+ nKey = KEY_TAB;
+ break;
+ // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
+ case 0x1004FF02: // osfXK_Copy
+ nKey = KEY_COPY;
+ break;
+ case 0x1004FF03: // osfXK_Cut
+ nKey = KEY_CUT;
+ break;
+ case 0x1004FF04: // osfXK_Paste
+ nKey = KEY_PASTE;
+ break;
+ case 0x1004FF07: // osfXK_BackTab
+ nKey = KEY_TAB;
+ break;
+ case 0x1004FF08: // osfXK_BackSpace
+ nKey = KEY_BACKSPACE;
+ break;
+ case 0x1004FF1B: // osfXK_Escape
+ nKey = KEY_ESCAPE;
+ break;
+ // Up, Down, Left, Right, PageUp, PageDown
+ // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
+ // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
+ case 0x1005FF10: // SunXK_F36
+ nKey = KEY_F11;
+ break;
+ case 0x1005FF11: // SunXK_F37
+ nKey = KEY_F12;
+ break;
+ case 0x1005FF70: // SunXK_Props
+ nKey = KEY_PROPERTIES;
+ break;
+ case 0x1005FF71: // SunXK_Front
+ nKey = KEY_FRONT;
+ break;
+ case 0x1005FF72: // SunXK_Copy
+ nKey = KEY_COPY;
+ break;
+ case 0x1005FF73: // SunXK_Open
+ nKey = KEY_OPEN;
+ break;
+ case 0x1005FF74: // SunXK_Paste
+ nKey = KEY_PASTE;
+ break;
+ case 0x1005FF75: // SunXK_Cut
+ nKey = KEY_CUT;
+ break;
+ }
+ return nKey;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+KeySym SalDisplay::GetKeySym( XKeyEvent *pEvent,
+ unsigned char *pPrintable,
+ int *pLen,
+ KeySym *pUnmodifiedKeySym,
+ Status *pStatusReturn,
+ XIC aInputContext ) const
+{
+ KeySym nKeySym = 0;
+ memset( pPrintable, 0, *pLen );
+ *pStatusReturn = 0;
+
+ // first get the printable of the possibly modified KeySym
+ if ( (aInputContext == 0)
+ || (pEvent->type == KeyRelease)
+ || (mpInputMethod != NULL && mpInputMethod->PosixLocale()) )
+ {
+ // XmbLookupString must not be called for KeyRelease events
+ // Cannot enter space in c locale problem #89616# #88978# btraq #4478197
+ *pLen = XLookupString( pEvent, (char*)pPrintable, 1, &nKeySym, NULL );
+ }
+ else
+ {
+ *pLen = XmbLookupString( aInputContext,
+ pEvent, (char*)pPrintable, *pLen - 1, &nKeySym, pStatusReturn );
+
+ // Lookup the string again, now with appropriate size
+ if ( *pStatusReturn == XBufferOverflow )
+ {
+ pPrintable[ 0 ] = (char)0;
+ return 0;
+ }
+
+ switch ( *pStatusReturn )
+ {
+ case XBufferOverflow:
+ /* unhandled error */
+ break;
+ case XLookupNone:
+ /* unhandled error */
+ break;
+ case XLookupKeySym:
+ /* #72223# this is a strange one: on exceed sometimes
+ * no printable is returned for the first char entered,
+ * just to retry lookup solves the problem. The problem
+ * is not yet fully understood, so restrict 2nd lookup
+ * to 7bit ascii chars */
+ if ( (XK_space <= nKeySym) && (XK_asciitilde >= nKeySym) )
+ {
+ *pLen = 1;
+ pPrintable[ 0 ] = (char)nKeySym;
+ }
+ break;
+ case XLookupBoth:
+ case XLookupChars:
+
+ /* nothing to, char allready in pPrintable */
+ break;
+ }
+ }
+
+ if( !bNumLockFromXS_
+ && (IsCursorKey(nKeySym)
+ || IsFunctionKey(nKeySym)
+ || IsKeypadKey(nKeySym)
+ || XK_Delete == nKeySym ) )
+ {
+ // Bei einigen X-Servern muss man bei den Keypadtasten
+ // schon sehr genau hinschauen. ZB. Solaris XServer:
+ // 2, 4, 6, 8 werden als Cursorkeys klassifiziert (Up, Down, Left, Right
+ // 1, 3, 5, 9 werden als Functionkeys klassifiziert (F27,F29,F33,F35)
+ // 0 als Keypadkey und der Dezimalpunkt gar nicht (KP_Insert)
+ KeySym nNewKeySym = XLookupKeysym( pEvent, nNumLockIndex_ );
+ if( nNewKeySym != NoSymbol )
+ nKeySym = nNewKeySym;
+ }
+
+ // Now get the unmodified KeySym for KeyCode retrieval
+ // try to strip off modifiers, e.g. Ctrl-$ becomes Ctrl-Shift-4
+ *pUnmodifiedKeySym = XKeycodeToKeysym( GetDisplay(), pEvent->keycode, 0);
+
+ return nKeySym;
+}
+
+// Pointer
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define MAKE_BITMAP( name ) \
+ XCreateBitmapFromData( pDisp_, \
+ DefaultRootWindow( pDisp_ ), \
+ name##_bits, \
+ name##_width, \
+ name##_height )
+
+#define MAKE_CURSOR( name ) \
+ aCursBitmap = MAKE_BITMAP( name##curs ); \
+ aMaskBitmap = MAKE_BITMAP( name##mask ); \
+ nXHot = name##curs_x_hot; \
+ nYHot = name##curs_y_hot
+
+XLIB_Cursor SalDisplay::GetPointer( int ePointerStyle )
+{
+ if( ePointerStyle >= POINTER_COUNT )
+ return 0;
+
+ XLIB_Cursor &aCur = aPointerCache_[ePointerStyle];
+
+ if( aCur != None )
+ return aCur;
+
+ Pixmap aCursBitmap = None, aMaskBitmap = None;
+ unsigned int nXHot = 0, nYHot = 0;
+
+ switch( ePointerStyle )
+ {
+ case POINTER_NULL:
+ MAKE_CURSOR( null );
+ break;
+ case POINTER_ARROW:
+ aCur = XCreateFontCursor( pDisp_, XC_left_ptr );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WAIT:
+ aCur = XCreateFontCursor( pDisp_, XC_watch );
+ break;
+ case POINTER_TEXT: // Mouse Pointer ist ein "I" Beam
+ aCur = XCreateFontCursor( pDisp_, XC_xterm );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_HELP:
+ aCur = XCreateFontCursor( pDisp_, XC_question_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_CROSS: // Mouse Pointer ist ein Kreuz
+ aCur = XCreateFontCursor( pDisp_, XC_crosshair );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_NSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_SSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_ESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_NSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_side );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_SSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_side );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_WSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_left_side );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_ESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_right_side );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_NWSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_left_corner );
+ break;
+ case POINTER_NESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_right_corner );
+ break;
+ case POINTER_SWSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_left_corner );
+ break;
+ case POINTER_SESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_right_corner );
+ break;
+ case POINTER_WINDOW_NWSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_left_corner );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_NESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_right_corner );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_SWSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_left_corner );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_SESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_right_corner );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_HSPLIT:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
+ break;
+ case POINTER_VSPLIT:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
+ break;
+ case POINTER_HSIZEBAR:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow ); // ???
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_VSIZEBAR:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow ); // ???
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_REFHAND:
+ aCur = XCreateFontCursor( pDisp_, XC_hand1 );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_HAND:
+ aCur = XCreateFontCursor( pDisp_, XC_hand2 );
+ break;
+ case POINTER_MAGNIFY:
+ MAKE_CURSOR( magnify_ );
+ break;
+ case POINTER_FILL:
+ MAKE_CURSOR( fill_ );
+ break;
+ case POINTER_MOVE:
+ aCur = XCreateFontCursor( pDisp_, XC_fleur );
+ break;
+ case POINTER_MOVEDATA:
+ MAKE_CURSOR( movedata_ );
+ break;
+ case POINTER_COPYDATA:
+ MAKE_CURSOR( copydata_ );
+ break;
+ case POINTER_MOVEFILE:
+ MAKE_CURSOR( movefile_ );
+ break;
+ case POINTER_COPYFILE:
+ MAKE_CURSOR( copyfile_ );
+ break;
+ case POINTER_MOVEFILES:
+ MAKE_CURSOR( movefiles_ );
+ break;
+ case POINTER_COPYFILES:
+ MAKE_CURSOR( copyfiles_ );
+ break;
+ case POINTER_NOTALLOWED:
+ MAKE_CURSOR( nodrop_ );
+ break;
+ case POINTER_ROTATE:
+ MAKE_CURSOR( rotate_ );
+ break;
+ case POINTER_HSHEAR:
+ MAKE_CURSOR( hshear_ );
+ break;
+ case POINTER_VSHEAR:
+ MAKE_CURSOR( vshear_ );
+ break;
+ case POINTER_DRAW_LINE:
+ MAKE_CURSOR( drawline_ );
+ break;
+ case POINTER_DRAW_RECT:
+ MAKE_CURSOR( drawrect_ );
+ break;
+ case POINTER_DRAW_POLYGON:
+ MAKE_CURSOR( drawpolygon_ );
+ break;
+ case POINTER_DRAW_BEZIER:
+ MAKE_CURSOR( drawbezier_ );
+ break;
+ case POINTER_DRAW_ARC:
+ MAKE_CURSOR( drawarc_ );
+ break;
+ case POINTER_DRAW_PIE:
+ MAKE_CURSOR( drawpie_ );
+ break;
+ case POINTER_DRAW_CIRCLECUT:
+ MAKE_CURSOR( drawcirclecut_ );
+ break;
+ case POINTER_DRAW_ELLIPSE:
+ MAKE_CURSOR( drawellipse_ );
+ break;
+ case POINTER_DRAW_CONNECT:
+ MAKE_CURSOR( drawconnect_ );
+ break;
+ case POINTER_DRAW_TEXT:
+ MAKE_CURSOR( drawtext_ );
+ break;
+ case POINTER_MIRROR:
+ MAKE_CURSOR( mirror_ );
+ break;
+ case POINTER_CROOK:
+ MAKE_CURSOR( crook_ );
+ break;
+ case POINTER_CROP:
+ MAKE_CURSOR( crop_ );
+ break;
+ case POINTER_MOVEPOINT:
+ MAKE_CURSOR( movepoint_ );
+ break;
+ case POINTER_MOVEBEZIERWEIGHT:
+ MAKE_CURSOR( movebezierweight_ );
+ break;
+ case POINTER_DRAW_FREEHAND:
+ MAKE_CURSOR( drawfreehand_ );
+ break;
+ case POINTER_DRAW_CAPTION:
+ MAKE_CURSOR( drawcaption_ );
+ break;
+ case POINTER_PEN: // Mouse Pointer ist ein Stift
+ aCur = XCreateFontCursor( pDisp_, XC_pencil );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_LINKDATA:
+ MAKE_CURSOR( linkdata_ );
+ break;
+ case POINTER_MOVEDATALINK:
+ MAKE_CURSOR( movedlnk_ );
+ break;
+ case POINTER_COPYDATALINK:
+ MAKE_CURSOR( copydlnk_ );
+ break;
+ case POINTER_LINKFILE:
+ MAKE_CURSOR( linkfile_ );
+ break;
+ case POINTER_MOVEFILELINK:
+ MAKE_CURSOR( moveflnk_ );
+ break;
+ case POINTER_COPYFILELINK:
+ MAKE_CURSOR( copyflnk_ );
+ break;
+ case POINTER_CHART:
+ MAKE_CURSOR( chart_ );
+ break;
+ case POINTER_DETECTIVE:
+ MAKE_CURSOR( detective_ );
+ break;
+ case POINTER_PIVOT_COL:
+ MAKE_CURSOR( pivotcol_ );
+ break;
+ case POINTER_PIVOT_ROW:
+ MAKE_CURSOR( pivotrow_ );
+ break;
+ case POINTER_PIVOT_FIELD:
+ MAKE_CURSOR( pivotfld_ );
+ break;
+ case POINTER_PIVOT_DELETE:
+ MAKE_CURSOR( pivotdel_ );
+ break;
+ case POINTER_CHAIN:
+ MAKE_CURSOR( chain_ );
+ break;
+ case POINTER_CHAIN_NOTALLOWED:
+ MAKE_CURSOR( chainnot_ );
+ break;
+ case POINTER_TIMEEVENT_MOVE:
+ MAKE_CURSOR( timemove_ );
+ break;
+ case POINTER_TIMEEVENT_SIZE:
+ MAKE_CURSOR( timesize_ );
+ break;
+ case POINTER_AUTOSCROLL_N:
+ MAKE_CURSOR(asn_ );
+ break;
+ case POINTER_AUTOSCROLL_S:
+ MAKE_CURSOR( ass_ );
+ break;
+ case POINTER_AUTOSCROLL_W:
+ MAKE_CURSOR( asw_ );
+ break;
+ case POINTER_AUTOSCROLL_E:
+ MAKE_CURSOR( ase_ );
+ break;
+ case POINTER_AUTOSCROLL_NW:
+ MAKE_CURSOR( asnw_ );
+ break;
+ case POINTER_AUTOSCROLL_NE:
+ MAKE_CURSOR( asne_ );
+ break;
+ case POINTER_AUTOSCROLL_SW:
+ MAKE_CURSOR( assw_ );
+ break;
+ case POINTER_AUTOSCROLL_SE:
+ MAKE_CURSOR( asse_ );
+ break;
+ case POINTER_AUTOSCROLL_NS:
+ MAKE_CURSOR( asns_ );
+ break;
+ case POINTER_AUTOSCROLL_WE:
+ MAKE_CURSOR( aswe_ );
+ break;
+ case POINTER_AUTOSCROLL_NSWE:
+ MAKE_CURSOR( asnswe_ );
+ break;
+ case POINTER_AIRBRUSH:
+ MAKE_CURSOR( airbrush_ );
+ break;
+ case POINTER_TEXT_VERTICAL:
+ MAKE_CURSOR( vertcurs_ );
+ break;
+
+ // --> FME 2004-07-30 #i32329# Enhanced table selection
+ case POINTER_TAB_SELECT_S:
+ MAKE_CURSOR( tblsels_ );
+ break;
+ case POINTER_TAB_SELECT_E:
+ MAKE_CURSOR( tblsele_ );
+ break;
+ case POINTER_TAB_SELECT_SE:
+ MAKE_CURSOR( tblselse_ );
+ break;
+ case POINTER_TAB_SELECT_W:
+ MAKE_CURSOR( tblselw_ );
+ break;
+ case POINTER_TAB_SELECT_SW:
+ MAKE_CURSOR( tblselsw_ );
+ break;
+ // <--
+
+ // --> FME 2004-08-16 #i20119# Paintbrush tool
+ case POINTER_PAINTBRUSH :
+ MAKE_CURSOR( paintbrush_ );
+ break;
+ // <--
+
+ default:
+ DBG_ERROR("pointer not implemented");
+ aCur = XCreateFontCursor( pDisp_, XC_arrow );
+ break;
+ }
+
+ if( None == aCur )
+ {
+ XColor aBlack, aWhite, aDummy;
+ Colormap hColormap = GetColormap(m_nDefaultScreen).GetXColormap();
+
+ XAllocNamedColor( pDisp_, hColormap, "black", &aBlack, &aDummy );
+ XAllocNamedColor( pDisp_, hColormap, "white", &aWhite, &aDummy );
+
+ aCur = XCreatePixmapCursor( pDisp_,
+ aCursBitmap, aMaskBitmap,
+ &aBlack, &aWhite,
+ nXHot, nYHot );
+
+ XFreePixmap( pDisp_, aCursBitmap );
+ XFreePixmap( pDisp_, aMaskBitmap );
+ }
+
+ return aCur;
+}
+
+int SalDisplay::CaptureMouse( SalFrame *pCapture )
+{
+ if( !pCapture )
+ {
+ m_pCapture = NULL;
+ XUngrabPointer( GetDisplay(), CurrentTime );
+ XFlush( GetDisplay() );
+ return 0;
+ }
+
+ m_pCapture = NULL;
+
+ // FIXME: get rid of X11SalFrame
+ const SystemEnvData* pEnvData = pCapture->GetSystemData();
+ int ret = XGrabPointer( GetDisplay(),
+ (XLIB_Window)pEnvData->aWindow,
+ False,
+ PointerMotionMask| ButtonPressMask|ButtonReleaseMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ static_cast<X11SalFrame*>(pCapture)->GetCursor(),
+ CurrentTime );
+
+ if( ret != GrabSuccess )
+ {
+ DBG_ASSERT( 1, "SalDisplay::CaptureMouse could not grab pointer\n");
+ return -1;
+ }
+
+ m_pCapture = pCapture;
+ return 1;
+}
+
+// Events
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void SalDisplay::SendInternalEvent( SalFrame* pFrame, void* pData, USHORT nEvent )
+{
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) );
+
+ // Notify SalXLib::Yield() of a pending event.
+ pXLib_->PostUserEvent();
+
+ osl_releaseMutex( hEventGuard_ );
+ }
+ else {
+ DBG_ASSERT( 1, "SalDisplay::SendInternalEvent !acquireMutex\n" );
+ }
+}
+
+void SalDisplay::CancelInternalEvent( SalFrame* pFrame, void* pData, USHORT nEvent )
+{
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ if( ! m_aUserEvents.empty() )
+ {
+ std::list< SalUserEvent >::iterator it, next;
+ next = m_aUserEvents.begin();
+ do
+ {
+ it = next++;
+ if( it->m_pFrame == pFrame &&
+ it->m_pData == pData &&
+ it->m_nEvent == nEvent )
+ {
+ m_aUserEvents.erase( it );
+ }
+ } while( next != m_aUserEvents.end() );
+ }
+
+ osl_releaseMutex( hEventGuard_ );
+ }
+ else {
+ DBG_ASSERT( 1, "SalDisplay::CancelInternalEvent !acquireMutex\n" );
+ }
+}
+
+BOOL SalX11Display::IsEvent()
+{
+ BOOL bRet = FALSE;
+
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ if( m_aUserEvents.begin() != m_aUserEvents.end() )
+ bRet = TRUE;
+ osl_releaseMutex( hEventGuard_ );
+ }
+
+ if( bRet || XEventsQueued( pDisp_, QueuedAlready ) )
+ return TRUE;
+
+ XFlush( pDisp_ );
+ return FALSE;
+}
+
+bool SalDisplay::DispatchInternalEvent()
+{
+ SalFrame* pFrame = NULL;
+ void* pData = NULL;
+ USHORT nEvent = 0;
+
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ if( m_aUserEvents.begin() != m_aUserEvents.end() )
+ {
+ pFrame = m_aUserEvents.front().m_pFrame;
+ pData = m_aUserEvents.front().m_pData;
+ nEvent = m_aUserEvents.front().m_nEvent;
+
+ m_aUserEvents.pop_front();
+ }
+ osl_releaseMutex( hEventGuard_ );
+ }
+ else {
+ DBG_ASSERT( 1, "SalDisplay::Yield !acquireMutex\n" );
+ }
+
+ if( pFrame )
+ pFrame->CallCallback( nEvent, pData );
+
+ return pFrame != NULL;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void SalX11Display::Yield()
+{
+ if( DispatchInternalEvent() )
+ return;
+
+ XEvent aEvent;
+ DBG_ASSERT( static_cast<SalYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())->GetThreadId() ==
+ vos::OThread::getCurrentIdentifier(),
+ "will crash soon since solar mutex not locked in SalDisplay::Yield" );
+
+ XNextEvent( pDisp_, &aEvent );
+
+ Dispatch( &aEvent );
+
+#ifdef DBG_UTIL
+ if( pXLib_->HasXErrorOccured() )
+ {
+ XFlush( pDisp_ );
+ PrintEvent( "SalDisplay::Yield (WasXError)", &aEvent );
+ }
+#endif
+ pXLib_->ResetXErrorOccured();
+}
+
+long SalX11Display::Dispatch( XEvent *pEvent )
+{
+ if( pEvent->type == XLIB_KeyPress || pEvent->type == KeyRelease )
+ {
+ XLIB_Window aWindow = pEvent->xkey.window;
+
+ std::list< SalFrame* >::const_iterator it;
+ for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it )
+ {
+ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
+ if( pFrame->GetWindow() == aWindow || pFrame->GetShellWindow() == aWindow )
+ {
+ aWindow = pFrame->GetWindow();
+ break;
+ }
+ }
+ if( it != m_aFrames.end() )
+ {
+ if ( mpInputMethod->FilterEvent( pEvent , aWindow ) )
+ return 0;
+ }
+ }
+ else
+ if ( mpInputMethod->FilterEvent( pEvent, None ) )
+ return 0;
+
+ SalInstance* pInstance = GetSalData()->m_pInstance;
+ pInstance->CallEventCallback( pEvent, sizeof( XEvent ) );
+
+ switch( pEvent->type )
+ {
+ case MotionNotify:
+ while( XCheckWindowEvent( pEvent->xany.display,
+ pEvent->xany.window,
+ ButtonMotionMask,
+ pEvent ) )
+ ;
+ m_nLastUserEventTime = pEvent->xmotion.time;
+ break;
+ case PropertyNotify:
+ if( pEvent->xproperty.atom == getWMAdaptor()->getAtom( WMAdaptor::VCL_SYSTEM_SETTINGS ) )
+ {
+ for( unsigned int i = 0; i < m_aScreens.size(); i++ )
+ {
+ if( pEvent->xproperty.window == m_aScreens[i].m_aRefWindow )
+ {
+ std::list< SalFrame* >::const_iterator it;
+ for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it )
+ (*it)->CallCallback( SALEVENT_SETTINGSCHANGED, NULL );
+ return 0;
+ }
+ }
+ }
+ break;
+ case MappingNotify:
+ if( MappingKeyboard == pEvent->xmapping.request ||
+ MappingModifier == pEvent->xmapping.request )
+ {
+ XRefreshKeyboardMapping( &pEvent->xmapping );
+ if( MappingModifier == pEvent->xmapping.request )
+ ModifierMapping();
+ if( MappingKeyboard == pEvent->xmapping.request ) // refresh mapping
+ GetKeyboardName( TRUE );
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ m_nLastUserEventTime = pEvent->xbutton.time;
+ break;
+ case XLIB_KeyPress:
+ case KeyRelease:
+ m_nLastUserEventTime = pEvent->xkey.time;
+ break;
+ default:
+
+ if ( GetKbdExtension()->UseExtension()
+ && GetKbdExtension()->GetEventBase() == pEvent->type )
+ {
+ GetKbdExtension()->Dispatch( pEvent );
+ return 1;
+ }
+ break;
+ }
+
+ std::list< SalFrame* >::iterator it;
+ for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it )
+ {
+ X11SalFrame* pFrame = static_cast< X11SalFrame* >(*it);
+ XLIB_Window aDispatchWindow = pEvent->xany.window;
+ if( pFrame->GetWindow() == aDispatchWindow
+ || pFrame->GetShellWindow() == aDispatchWindow
+ || pFrame->GetForeignParent() == aDispatchWindow
+ )
+ {
+ return pFrame->Dispatch( pEvent );
+ }
+ if( pEvent->type == ConfigureNotify && pEvent->xconfigure.window == pFrame->GetStackingWindow() )
+ {
+ return pFrame->Dispatch( pEvent );
+ }
+ }
+
+ // dispatch to salobjects
+ X11SalObject::Dispatch( pEvent );
+
+ // is this perhaps a root window that changed size ?
+ processRandREvent( pEvent );
+
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalDisplay::PrintEvent( const ByteString &rComment,
+ XEvent *pEvent ) const
+{
+ if( pEvent->type <= MappingNotify )
+ {
+ fprintf( stderr, "[%s] %s s=%d w=%ld\n",
+ rComment.GetBuffer(),
+ EventNames[pEvent->type],
+ pEvent->xany.send_event,
+ pEvent->xany.window );
+
+ switch( pEvent->type )
+ {
+ case XLIB_KeyPress:
+ case KeyRelease:
+ fprintf( stderr, "\t\ts=%d c=%d\n",
+ pEvent->xkey.state,
+ pEvent->xkey.keycode );
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ fprintf( stderr, "\t\ts=%d b=%d x=%d y=%d rx=%d ry=%d\n",
+ pEvent->xbutton.state,
+ pEvent->xbutton.button,
+ pEvent->xbutton.x,
+ pEvent->xbutton.y,
+ pEvent->xbutton.x_root,
+ pEvent->xbutton.y_root );
+ break;
+
+ case MotionNotify:
+ fprintf( stderr, "\t\ts=%d x=%d y=%d\n",
+ pEvent->xmotion.state,
+ pEvent->xmotion.x,
+ pEvent->xmotion.y );
+ break;
+
+ case EnterNotify:
+ case LeaveNotify:
+ fprintf( stderr, "\t\tm=%d f=%d x=%d y=%d\n",
+ pEvent->xcrossing.mode,
+ pEvent->xcrossing.focus,
+ pEvent->xcrossing.x,
+ pEvent->xcrossing.y );
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ fprintf( stderr, "\t\tm=%d d=%d\n",
+ pEvent->xfocus.mode,
+ pEvent->xfocus.detail );
+ break;
+
+ case Expose:
+ case GraphicsExpose:
+ fprintf( stderr, "\t\tc=%d %d*%d %d+%d\n",
+ pEvent->xexpose.count,
+ pEvent->xexpose.width,
+ pEvent->xexpose.height,
+ pEvent->xexpose.x,
+ pEvent->xexpose.y );
+ break;
+
+ case VisibilityNotify:
+ fprintf( stderr, "\t\ts=%d\n",
+ pEvent->xvisibility.state );
+ break;
+
+ case CreateNotify:
+ case DestroyNotify:
+ break;
+
+ case MapNotify:
+ case UnmapNotify:
+ break;
+
+ case ReparentNotify:
+ fprintf( stderr, "\t\tp=%d x=%d y=%d\n",
+ sal::static_int_cast< int >(pEvent->xreparent.parent),
+ pEvent->xreparent.x,
+ pEvent->xreparent.y );
+ break;
+
+ case ConfigureNotify:
+ fprintf( stderr, "\t\tb=%d %d*%d %d+%d\n",
+ pEvent->xconfigure.border_width,
+ pEvent->xconfigure.width,
+ pEvent->xconfigure.height,
+ pEvent->xconfigure.x,
+ pEvent->xconfigure.y );
+ break;
+
+ case PropertyNotify:
+ fprintf( stderr, "\t\ta=%s (0x%X)\n",
+ GetAtomName( pDisp_, pEvent->xproperty.atom ),
+ sal::static_int_cast< unsigned int >(
+ pEvent->xproperty.atom) );
+ break;
+
+ case ColormapNotify:
+ fprintf( stderr, "\t\tc=%ld n=%d s=%d\n",
+ pEvent->xcolormap.colormap,
+ pEvent->xcolormap.c_new,
+ pEvent->xcolormap.state );
+ break;
+
+ case ClientMessage:
+ fprintf( stderr, "\t\ta=%s (0x%X) f=%i [0x%lX,0x%lX,0x%lX,0x%lX,0x%lX])\n",
+ GetAtomName( pDisp_, pEvent->xclient.message_type ),
+ sal::static_int_cast< unsigned int >(
+ pEvent->xclient.message_type),
+ pEvent->xclient.format,
+ pEvent->xclient.data.l[0],
+ pEvent->xclient.data.l[1],
+ pEvent->xclient.data.l[2],
+ pEvent->xclient.data.l[3],
+ pEvent->xclient.data.l[4] );
+ break;
+
+ case MappingNotify:
+ fprintf( stderr, "\t\tr=%sd\n",
+ MappingModifier == pEvent->xmapping.request
+ ? "MappingModifier"
+ : MappingKeyboard == pEvent->xmapping.request
+ ? "MappingKeyboard"
+ : "MappingPointer" );
+
+ break;
+ }
+ }
+ else
+ fprintf( stderr, "[%s] %d s=%d w=%ld\n",
+ rComment.GetBuffer(),
+ pEvent->type,
+ pEvent->xany.send_event,
+ pEvent->xany.window );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalDisplay::PrintInfo() const
+{
+ if( IsDisplay() )
+ {
+ fprintf( stderr, "\n" );
+ fprintf( stderr, "Environment\n" );
+ fprintf( stderr, "\t$XENVIRONMENT \t\"%s\"\n",
+ GetEnv( "XENVIRONMENT" ) );
+ fprintf( stderr, "\t$DISPLAY \t\"%s\"\n",
+ GetEnv( "DISPLAY" ) );
+ fprintf( stderr, "\t$SAL_VISUAL \t\"%s\"\n",
+ GetEnv( "SAL_VISUAL" ) );
+ fprintf( stderr, "\t$SAL_FONTPATH \t\"%s\"\n",
+ GetEnv( "SAL_FONTPATH" ) );
+ fprintf( stderr, "\t$SAL_NOSEGV \t\"%s\"\n",
+ GetEnv( "SAL_NOSEGV" ) );
+ fprintf( stderr, "\t$SAL_IGNOREXERRORS\t\"%s\"\n",
+ GetEnv( "SAL_IGNOREXERRORS" ) );
+ fprintf( stderr, "\t$SAL_PROPERTIES \t\"%s\"\n",
+ GetEnv( "SAL_PROPERTIES" ) );
+ fprintf( stderr, "\t$SAL_WM \t\"%s\"\n",
+ GetEnv( "SAL_WM" ) );
+ fprintf( stderr, "\t$SAL_SYNCHRONIZE \t\"%s\"\n",
+ GetEnv( "SAL_SYNCHRONIZE" ) );
+
+ char sHostname[ 120 ];
+ gethostname (sHostname, 120 );
+ fprintf( stderr, "Client\n" );
+ fprintf( stderr, "\tHost \t\"%s\"\n",
+ sHostname );
+
+ fprintf( stderr, "Display\n" );
+ fprintf( stderr, "\tHost \t\"%s\"\n",
+ DisplayString(pDisp_) );
+ fprintf( stderr, "\tVendor (Release) \t\"%s (%d)\"\n",
+ ServerVendor(pDisp_), VendorRelease(pDisp_) );
+ fprintf( stderr, "\tProtocol \t%d.%d\n",
+ ProtocolVersion(pDisp_), ProtocolRevision(pDisp_) );
+ fprintf( stderr, "\tScreen (count,def)\t%d (%d,%d)\n",
+ m_nDefaultScreen, ScreenCount(pDisp_), DefaultScreen(pDisp_) );
+ fprintf( stderr, "\tshift ctrl alt \t%s (0x%X) %s (0x%X) %s (0x%X)\n",
+ KeyStr( nShiftKeySym_ ), sal::static_int_cast< unsigned int >(nShiftKeySym_),
+ KeyStr( nCtrlKeySym_ ), sal::static_int_cast< unsigned int >(nCtrlKeySym_),
+ KeyStr( nMod1KeySym_ ), sal::static_int_cast< unsigned int >(nMod1KeySym_) );
+ if( XExtendedMaxRequestSize(pDisp_) * 4 )
+ fprintf( stderr, "\tXMaxRequestSize \t%ld %ld [bytes]\n",
+ XMaxRequestSize(pDisp_) * 4, XExtendedMaxRequestSize(pDisp_) * 4 );
+ if( GetProperties() != PROPERTY_DEFAULT )
+ fprintf( stderr, "\tProperties \t0x%lX\n", GetProperties() );
+ if( eWindowManager_ != otherwm )
+ fprintf( stderr, "\tWindowmanager \t%d\n", eWindowManager_ );
+ fprintf( stderr, "\tWMName \t%s\n", rtl::OUStringToOString( getWMAdaptor()->getWindowManagerName(), osl_getThreadTextEncoding() ).getStr() );
+ }
+ fprintf( stderr, "Screen\n" );
+ fprintf( stderr, "\tResolution/Size \t%ld*%ld %ld*%ld %.1lf\"\n",
+ aResolution_.A(), aResolution_.B(),
+ m_aScreens[m_nDefaultScreen].m_aSize.Width(), m_aScreens[m_nDefaultScreen].m_aSize.Height(),
+ Hypothenuse( DisplayWidthMM ( pDisp_, m_nDefaultScreen ),
+ DisplayHeightMM( pDisp_, m_nDefaultScreen ) ) / 25.4 );
+ fprintf( stderr, "\tBlack&White \t%lu %lu\n",
+ GetColormap(m_nDefaultScreen).GetBlackPixel(), GetColormap(m_nDefaultScreen).GetWhitePixel() );
+ fprintf( stderr, "\tRGB \t0x%lx 0x%lx 0x%lx\n",
+ GetVisual(m_nDefaultScreen).red_mask, GetVisual(m_nDefaultScreen).green_mask, GetVisual(m_nDefaultScreen).blue_mask );
+ fprintf( stderr, "\tVisual \t%d-bit %s ID=0x%x\n",
+ GetVisual(m_nDefaultScreen).GetDepth(),
+ VisualClassName[ GetVisual(m_nDefaultScreen).GetClass() ],
+ sal::static_int_cast< unsigned int >(GetVisual(m_nDefaultScreen).GetVisualId()) );
+}
+
+int SalDisplay::addXineramaScreenUnique( long i_nX, long i_nY, long i_nWidth, long i_nHeight )
+{
+ // see if any frame buffers are at the same coordinates
+ // this can happen with weird configuration e.g. on
+ // XFree86 and Clone displays
+ const size_t nScreens = m_aXineramaScreens.size();
+ for( size_t n = 0; n < nScreens; n++ )
+ {
+ if( m_aXineramaScreens[n].Left() == i_nX &&
+ m_aXineramaScreens[n].Top() == i_nY )
+ {
+ if( m_aXineramaScreens[n].GetWidth() < i_nWidth ||
+ m_aXineramaScreens[n].GetHeight() < i_nHeight )
+ {
+ m_aXineramaScreens[n].SetSize( Size( i_nWidth, i_nHeight ) );
+ }
+ return (int)n;
+ }
+ }
+ m_aXineramaScreens.push_back( Rectangle( Point( i_nX, i_nY ), Size( i_nWidth, i_nHeight ) ) );
+ return (int)m_aXineramaScreens.size()-1;
+}
+
+void SalDisplay::InitXinerama()
+{
+ if( m_aScreens.size() > 1 )
+ {
+ m_bXinerama = false;
+ return; // multiple screens mean no xinerama
+ }
+#ifdef USE_XINERAMA
+#if defined(USE_XINERAMA_XSUN)
+ int nFramebuffers = 1;
+ if( XineramaGetState( pDisp_, m_nDefaultScreen ) )
+ {
+ XRectangle pFramebuffers[MAXFRAMEBUFFERS];
+ unsigned char hints[MAXFRAMEBUFFERS];
+ int result = XineramaGetInfo( pDisp_,
+ m_nDefaultScreen,
+ pFramebuffers,
+ hints,
+ &nFramebuffers );
+ if( result > 0 && nFramebuffers > 1 )
+ {
+ m_bXinerama = true;
+ m_aXineramaScreens = std::vector<Rectangle>();
+ for( int i = 0; i < nFramebuffers; i++ )
+ addXineramaScreenUnique( pFramebuffers[i].x,
+ pFramebuffers[i].y,
+ pFramebuffers[i].width,
+ pFramebuffers[i].height );
+ }
+ }
+#elif defined(USE_XINERAMA_XORG)
+if( XineramaIsActive( pDisp_ ) )
+{
+ int nFramebuffers = 1;
+ XineramaScreenInfo* pScreens = XineramaQueryScreens( pDisp_, &nFramebuffers );
+ if( pScreens )
+ {
+ if( nFramebuffers > 1 )
+ {
+ m_aXineramaScreens = std::vector<Rectangle>();
+ for( int i = 0; i < nFramebuffers; i++ )
+ {
+ addXineramaScreenUnique( pScreens[i].x_org,
+ pScreens[i].y_org,
+ pScreens[i].width,
+ pScreens[i].height );
+ }
+ m_bXinerama = m_aXineramaScreens.size() > 1;
+ }
+ XFree( pScreens );
+ }
+}
+#endif
+#if OSL_DEBUG_LEVEL > 1
+ if( m_bXinerama )
+ {
+ for( std::vector< Rectangle >::const_iterator it = m_aXineramaScreens.begin(); it != m_aXineramaScreens.end(); ++it )
+ fprintf( stderr, "Xinerama screen: %ldx%ld+%ld+%ld\n", it->GetWidth(), it->GetHeight(), it->Left(), it->Top() );
+ }
+#endif
+#endif // USE_XINERAMA
+}
+
+void SalDisplay::registerFrame( SalFrame* pFrame )
+{
+ m_aFrames.push_front( pFrame );
+}
+
+void SalDisplay::deregisterFrame( SalFrame* pFrame )
+{
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ std::list< SalUserEvent >::iterator it = m_aUserEvents.begin();
+ while ( it != m_aUserEvents.end() )
+ {
+ if( it->m_pFrame == pFrame )
+ it = m_aUserEvents.erase( it );
+ else
+ ++it;
+ }
+ osl_releaseMutex( hEventGuard_ );
+ }
+ else {
+ DBG_ERROR( "SalDisplay::deregisterFrame !acquireMutex\n" );
+ }
+
+ m_aFrames.remove( pFrame );
+}
+
+
+extern "C"
+{
+ static Bool timestamp_predicate( Display*, XEvent* i_pEvent, XPointer i_pArg )
+ {
+ SalDisplay* pSalDisplay = reinterpret_cast<SalDisplay*>(i_pArg);
+ if( i_pEvent->type == PropertyNotify &&
+ i_pEvent->xproperty.window == pSalDisplay->GetDrawable( pSalDisplay->GetDefaultScreenNumber() ) &&
+ i_pEvent->xproperty.atom == pSalDisplay->getWMAdaptor()->getAtom( WMAdaptor::SAL_GETTIMEEVENT )
+ )
+ return True;
+
+ return False;
+ }
+}
+
+XLIB_Time SalDisplay::GetLastUserEventTime( bool i_bAlwaysReget ) const
+{
+ if( m_nLastUserEventTime == CurrentTime || i_bAlwaysReget )
+ {
+ // get current server time
+ unsigned char c = 0;
+ XEvent aEvent;
+ Atom nAtom = getWMAdaptor()->getAtom( WMAdaptor::SAL_GETTIMEEVENT );
+ XChangeProperty( GetDisplay(), GetDrawable( GetDefaultScreenNumber() ),
+ nAtom, nAtom, 8, PropModeReplace, &c, 1 );
+ XFlush( GetDisplay() );
+
+ if( ! XIfEventWithTimeout( &aEvent, (XPointer)this, timestamp_predicate ) )
+ {
+ // this should not happen at all; still sometimes it happens
+ aEvent.xproperty.time = CurrentTime;
+ }
+
+ m_nLastUserEventTime = aEvent.xproperty.time;
+ }
+ return m_nLastUserEventTime;
+}
+
+bool SalDisplay::XIfEventWithTimeout( XEvent* o_pEvent, XPointer i_pPredicateData,
+ X_if_predicate i_pPredicate, long i_nTimeout ) const
+{
+ /* #i99360# ugly workaround an X11 library bug
+ this replaces the following call:
+ XIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData );
+ */
+ bool bRet = true;
+
+ if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
+ {
+ // wait for some event to arrive
+ struct pollfd aFD;
+ aFD.fd = ConnectionNumber(GetDisplay());
+ aFD.events = POLLIN;
+ aFD.revents = 0;
+ poll( &aFD, 1, i_nTimeout );
+ if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
+ {
+ poll( &aFD, 1, i_nTimeout ); // try once more for a packet of events from the Xserver
+ if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
+ {
+ bRet = false;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -=-= SalVisual -=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalVisual::SalVisual()
+{
+ rtl_zeroMemory( this, sizeof( SalVisual ) );
+}
+
+SalVisual::SalVisual( const XVisualInfo* pXVI )
+{
+ *(XVisualInfo*)this = *pXVI;
+ if( GetClass() == TrueColor )
+ {
+ nRedShift_ = sal_Shift( red_mask );
+ nGreenShift_ = sal_Shift( green_mask );
+ nBlueShift_ = sal_Shift( blue_mask );
+
+ nRedBits_ = sal_significantBits( red_mask );
+ nGreenBits_ = sal_significantBits( green_mask );
+ nBlueBits_ = sal_significantBits( blue_mask );
+
+ if( GetDepth() == 24 )
+ if( red_mask == 0xFF0000 )
+ if( green_mask == 0xFF00 )
+ if( blue_mask == 0xFF )
+ eRGBMode_ = RGB;
+ else
+ eRGBMode_ = other;
+ else if( blue_mask == 0xFF00 )
+ if( green_mask == 0xFF )
+ eRGBMode_ = RBG;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ else if( green_mask == 0xFF0000 )
+ if( red_mask == 0xFF00 )
+ if( blue_mask == 0xFF )
+ eRGBMode_ = GRB;
+ else
+ eRGBMode_ = other;
+ else if( blue_mask == 0xFF00 )
+ if( red_mask == 0xFF )
+ eRGBMode_ = GBR;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ else if( blue_mask == 0xFF0000 )
+ if( red_mask == 0xFF00 )
+ if( green_mask == 0xFF )
+ eRGBMode_ = BRG;
+ else
+ eRGBMode_ = other;
+ else if( green_mask == 0xFF00 )
+ if( red_mask == 0xFF )
+ eRGBMode_ = BGR;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalVisual::~SalVisual()
+{
+ if( -1 == screen && VisualID(-1) == visualid ) delete visual;
+}
+
+// Konvertiert die Reihenfolge der Bytes eines Pixel in Bytes eines SalColors
+// fuer die 6 XXXA ist das nicht reversibel
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// SalColor is RGB (ABGR) a=0xFF000000, r=0xFF0000, g=0xFF00, b=0xFF
+
+#define SALCOLOR RGB
+#define SALCOLORREVERSE BGR
+
+BOOL SalVisual::Convert( int &n0, int &n1, int &n2, int &n3 )
+{
+ int n;
+
+ switch( GetMode() )
+ {
+ case other:
+ return FALSE;
+ case SALCOLOR:
+ break;
+ case SALCOLORREVERSE:
+ case RBG:
+ case BRG:
+ case GBR:
+ case GRB:
+ return Convert( n0, n1, n2 );
+ case RGBA:
+ n = n0;
+ n0 = n1;
+ n1 = n2;
+ n2 = n3;
+ n3 = n;
+ break;
+ case BGRA:
+ case RBGA:
+ case BRGA:
+ case GBRA:
+ case GRBA:
+ default:
+ fprintf( stderr, "SalVisual::Convert %d\n", GetMode() );
+ abort();
+ }
+ return TRUE;
+}
+
+BOOL SalVisual::Convert( int &n0, int &n1, int &n2 )
+{
+ int n;
+
+ switch( GetMode() )
+ {
+ case other:
+ return FALSE;
+ case SALCOLOR:
+ break;
+ case RBG:
+ n = n0;
+ n0 = n1;
+ n1 = n;
+ break;
+ case GRB:
+ n = n1;
+ n1 = n2;
+ n2 = n;
+ break;
+ case SALCOLORREVERSE:
+ n = n0;
+ n0 = n2;
+ n2 = n;
+ break;
+ case BRG:
+ n = n0;
+ n0 = n1;
+ n1 = n2;
+ n2 = n;
+ break;
+ case GBR:
+ n = n2;
+ n2 = n1;
+ n1 = n0;
+ n0 = n;
+ break;
+ default:
+ fprintf( stderr, "SalVisual::Convert %d\n", GetMode() );
+ abort();
+ }
+ return TRUE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColor SalVisual::GetTCColor( Pixel nPixel ) const
+{
+ if( SALCOLOR == eRGBMode_ )
+ return (SalColor)nPixel;
+
+ if( SALCOLORREVERSE == eRGBMode_ )
+ return MAKE_SALCOLOR( (nPixel & 0x0000FF),
+ (nPixel & 0x00FF00) >> 8,
+ (nPixel & 0xFF0000) >> 16);
+
+ Pixel r = nPixel & red_mask;
+ Pixel g = nPixel & green_mask;
+ Pixel b = nPixel & blue_mask;
+
+ if( other != eRGBMode_ ) // 8+8+8=24
+ return MAKE_SALCOLOR( r >> nRedShift_,
+ g >> nGreenShift_,
+ b >> nBlueShift_ );
+
+ if( nRedShift_ > 0 ) r >>= nRedShift_; else r <<= -nRedShift_;
+ if( nGreenShift_ > 0 ) g >>= nGreenShift_; else g <<= -nGreenShift_;
+ if( nBlueShift_ > 0 ) b >>= nBlueShift_; else b <<= -nBlueShift_;
+
+ if( nRedBits_ != 8 )
+ r |= (r & 0xff) >> (8-nRedBits_);
+ if( nGreenBits_ != 8 )
+ g |= (g & 0xff) >> (8-nGreenBits_);
+ if( nBlueBits_ != 8 )
+ b |= (b & 0xff) >> (8-nBlueBits_);
+
+ return MAKE_SALCOLOR( r, g, b );
+}
+
+Pixel SalVisual::GetTCPixel( SalColor nSalColor ) const
+{
+ if( SALCOLOR == eRGBMode_ )
+ return (Pixel)nSalColor;
+
+ Pixel r = (Pixel)SALCOLOR_RED( nSalColor );
+ Pixel g = (Pixel)SALCOLOR_GREEN( nSalColor );
+ Pixel b = (Pixel)SALCOLOR_BLUE( nSalColor );
+
+ if( SALCOLORREVERSE == eRGBMode_ )
+ return (b << 16) | (g << 8) | (r);
+
+ if( other != eRGBMode_ ) // 8+8+8=24
+ return (r << nRedShift_) | (g << nGreenShift_) | (b << nBlueShift_);
+
+ if( nRedShift_ > 0 ) r <<= nRedShift_; else r >>= -nRedShift_;
+ if( nGreenShift_ > 0 ) g <<= nGreenShift_; else g >>= -nGreenShift_;
+ if( nBlueShift_ > 0 ) b <<= nBlueShift_; else b >>= -nBlueShift_;
+
+ return (r&red_mask) | (g&green_mask) | (b&blue_mask);
+}
+
+// -=-= SalColormap -=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColormap::SalColormap( const SalDisplay *pDisplay, Colormap hColormap, int nScreen )
+ : m_pDisplay( pDisplay ),
+ m_hColormap( hColormap ),
+ m_nScreen( nScreen )
+{
+ m_aVisual = m_pDisplay->GetVisual( m_nScreen );
+
+ XColor aColor;
+
+ GetXPixel( aColor, 0x00, 0x00, 0x00 );
+ m_nBlackPixel = aColor.pixel;
+
+ GetXPixel( aColor, 0xFF, 0xFF, 0xFF );
+ m_nWhitePixel = aColor.pixel;
+
+ m_nUsed = 1 << m_aVisual.GetDepth();
+
+ if( m_aVisual.GetClass() == PseudoColor )
+ {
+ int r, g, b;
+
+ // black, white, gray, ~gray = 4
+ GetXPixels( aColor, 0xC0, 0xC0, 0xC0 );
+
+ // light colors: 3 * 2 = 6
+// GetXPixels( aColor, 0x00, 0x00, 0x00 );
+ GetXPixels( aColor, 0x00, 0x00, 0xFF );
+ GetXPixels( aColor, 0x00, 0xFF, 0x00 );
+ GetXPixels( aColor, 0x00, 0xFF, 0xFF );
+// GetXPixels( aColor, 0xFF, 0x00, 0x00 );
+// GetXPixels( aColor, 0xFF, 0x00, 0xFF );
+// GetXPixels( aColor, 0xFF, 0xFF, 0x00 );
+// GetXPixels( aColor, 0xFF, 0xFF, 0xFF );
+
+ // standard colors: 7 * 2 = 14
+// GetXPixels( aColor, 0x00, 0x00, 0x00 );
+ GetXPixels( aColor, 0x00, 0x00, 0x80 );
+ GetXPixels( aColor, 0x00, 0x80, 0x00 );
+ GetXPixels( aColor, 0x00, 0x80, 0x80 );
+ GetXPixels( aColor, 0x80, 0x00, 0x00 );
+ GetXPixels( aColor, 0x80, 0x00, 0x80 );
+ GetXPixels( aColor, 0x80, 0x80, 0x00 );
+ GetXPixels( aColor, 0x80, 0x80, 0x80 );
+ GetXPixels( aColor, 0x00, 0xB8, 0xFF ); // Blau 7
+
+ // cube: 6*6*6 - 8 = 208
+ for( r = 0; r < 0x100; r += 0x33 ) // 0x33, 0x66, 0x99, 0xCC, 0xFF
+ for( g = 0; g < 0x100; g += 0x33 )
+ for( b = 0; b < 0x100; b += 0x33 )
+ GetXPixels( aColor, r, g, b );
+
+ // gray: 16 - 6 = 10
+ for( g = 0x11; g < 0xFF; g += 0x11 )
+ GetXPixels( aColor, g, g, g );
+
+ // green: 16 - 6 = 10
+ for( g = 0x11; g < 0xFF; g += 0x11 )
+ GetXPixels( aColor, 0, g, 0 );
+
+ // red: 16 - 6 = 10
+ for( r = 0x11; r < 0xFF; r += 0x11 )
+ GetXPixels( aColor, r, 0, 0 );
+
+ // blue: 16 - 6 = 10
+ for( b = 0x11; b < 0xFF; b += 0x11 )
+ GetXPixels( aColor, 0, 0, b );
+ }
+}
+
+// PseudoColor
+SalColormap::SalColormap( const BitmapPalette &rPalette )
+ : m_pDisplay( GetX11SalData()->GetDisplay() ),
+ m_hColormap( None ),
+ m_nWhitePixel( SALCOLOR_NONE ),
+ m_nBlackPixel( SALCOLOR_NONE ),
+ m_nUsed( rPalette.GetEntryCount() ),
+ m_nScreen( GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() )
+{
+ m_aPalette = std::vector<SalColor>(m_nUsed);
+
+ for( unsigned int i = 0; i < m_nUsed; i++ )
+ {
+ const BitmapColor &rColor = rPalette[i];
+ m_aPalette[i] = MAKE_SALCOLOR( rColor.GetRed(),
+ rColor.GetGreen(),
+ rColor.GetBlue() );
+ if( (m_nBlackPixel == SALCOLOR_NONE) && (SALCOLOR_BLACK == m_aPalette[i]) )
+ m_nBlackPixel = i;
+ else if( (m_nWhitePixel == SALCOLOR_NONE) && (SALCOLOR_WHITE == m_aPalette[i]) )
+ m_nWhitePixel = i;
+ }
+}
+
+// MonoChrome
+SalColormap::SalColormap()
+ : m_pDisplay( GetX11SalData()->GetDisplay() ),
+ m_hColormap( None ),
+ m_nWhitePixel( 1 ),
+ m_nBlackPixel( 0 ),
+ m_nUsed( 2 ),
+ m_nScreen( 0 )
+{
+ if( m_pDisplay )
+ m_nScreen = m_pDisplay->GetDefaultScreenNumber();
+ m_aPalette = std::vector<SalColor>(m_nUsed);
+
+ m_aPalette[m_nBlackPixel] = SALCOLOR_BLACK;
+ m_aPalette[m_nWhitePixel] = SALCOLOR_WHITE;
+}
+
+// TrueColor
+SalColormap::SalColormap( USHORT nDepth )
+ : m_pDisplay( GetX11SalData()->GetDisplay() ),
+ m_hColormap( None ),
+ m_nWhitePixel( (1 << nDepth) - 1 ),
+ m_nBlackPixel( 0x00000000 ),
+ m_nUsed( 1 << nDepth ),
+ m_nScreen( GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() )
+{
+ const SalVisual *pVisual = &m_pDisplay->GetVisual( m_nScreen );
+
+ if( pVisual->GetClass() == TrueColor && pVisual->GetDepth() == nDepth )
+ m_aVisual = *pVisual;
+ else
+ {
+ XVisualInfo aVI;
+
+ if( !XMatchVisualInfo( m_pDisplay->GetDisplay(),
+ m_pDisplay->GetDefaultScreenNumber(),
+ nDepth,
+ TrueColor,
+ &aVI ) )
+ {
+ aVI.visual = new Visual();
+ aVI.visualid = (VisualID)0; // beware of temporary destructor below
+ aVI.screen = 0;
+ aVI.depth = nDepth;
+ aVI.c_class = TrueColor;
+ if( 24 == nDepth ) // 888
+ {
+ aVI.red_mask = 0xFF0000;
+ aVI.green_mask = 0x00FF00;
+ aVI.blue_mask = 0x0000FF;
+ }
+ else if( 16 == nDepth ) // 565
+ {
+ aVI.red_mask = 0x00F800;
+ aVI.green_mask = 0x0007E0;
+ aVI.blue_mask = 0x00001F;
+ }
+ else if( 15 == nDepth ) // 555
+ {
+ aVI.red_mask = 0x007C00;
+ aVI.green_mask = 0x0003E0;
+ aVI.blue_mask = 0x00001F;
+ }
+ else if( 12 == nDepth ) // 444
+ {
+ aVI.red_mask = 0x000F00;
+ aVI.green_mask = 0x0000F0;
+ aVI.blue_mask = 0x00000F;
+ }
+ else if( 8 == nDepth ) // 332
+ {
+ aVI.red_mask = 0x0000E0;
+ aVI.green_mask = 0x00001C;
+ aVI.blue_mask = 0x000003;
+ }
+ else
+ {
+ aVI.red_mask = 0x000000;
+ aVI.green_mask = 0x000000;
+ aVI.blue_mask = 0x000000;
+ }
+ aVI.colormap_size = 0;
+ aVI.bits_per_rgb = 8;
+
+ aVI.visual->ext_data = NULL;
+ aVI.visual->visualid = aVI.visualid;
+ aVI.visual->c_class = aVI.c_class;
+ aVI.visual->red_mask = aVI.red_mask;
+ aVI.visual->green_mask = aVI.green_mask;
+ aVI.visual->blue_mask = aVI.blue_mask;
+ aVI.visual->bits_per_rgb = aVI.bits_per_rgb;
+ aVI.visual->map_entries = aVI.colormap_size;
+
+ m_aVisual = SalVisual( &aVI );
+ // give ownership of constructed Visual() to m_aVisual
+ // see SalVisual destructor
+ m_aVisual.visualid = (VisualID)-1;
+ m_aVisual.screen = -1;
+ }
+ else
+ m_aVisual = SalVisual( &aVI );
+ }
+}
+
+SalColormap::~SalColormap()
+{
+#ifdef DBG_UTIL
+ m_hColormap = (Colormap)ILLEGAL_POINTER;
+ m_pDisplay = (SalDisplay*)ILLEGAL_POINTER;
+#endif
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalColormap::SetPalette( const BitmapPalette &rPalette )
+{
+ if( this != &GetX11SalData()->GetDisplay()->GetColormap(m_nScreen) )
+ {
+ m_nBlackPixel = SALCOLOR_NONE;
+ m_nWhitePixel = SALCOLOR_NONE;
+ }
+
+ if( rPalette.GetEntryCount() > m_nUsed )
+ {
+ m_nBlackPixel = SALCOLOR_NONE;
+ m_nWhitePixel = SALCOLOR_NONE;
+ m_nUsed = rPalette.GetEntryCount();
+ m_aPalette = std::vector<SalColor>(m_nUsed);
+ }
+
+ for( int i = 0; i < rPalette.GetEntryCount(); i++ )
+ {
+ const BitmapColor &rColor = rPalette[i];
+ m_aPalette[i] = MAKE_SALCOLOR( rColor.GetRed(),
+ rColor.GetGreen(),
+ rColor.GetBlue() );
+ if( (m_nBlackPixel == SALCOLOR_NONE) && (SALCOLOR_BLACK == m_aPalette[i]) )
+ m_nBlackPixel = i;
+ else if( (m_nWhitePixel == SALCOLOR_NONE) && (SALCOLOR_WHITE == m_aPalette[i]) )
+ m_nWhitePixel = i;
+ }
+}
+
+void SalColormap::GetPalette()
+{
+ Pixel i;
+ m_aPalette = std::vector<SalColor>(m_nUsed);
+
+ XColor *aColor = new XColor[m_nUsed];
+
+ for( i = 0; i < m_nUsed; i++ )
+ {
+ aColor[i].red = aColor[i].green = aColor[i].blue = 0;
+ aColor[i].pixel = i;
+ }
+
+ XQueryColors( m_pDisplay->GetDisplay(), m_hColormap, aColor, m_nUsed );
+
+ for( i = 0; i < m_nUsed; i++ )
+ {
+ m_aPalette[i] = MAKE_SALCOLOR( aColor[i].red >> 8,
+ aColor[i].green >> 8,
+ aColor[i].blue >> 8 );
+ }
+
+ delete [] aColor;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static USHORT sal_Lookup( const std::vector<SalColor>& rPalette,
+ int r, int g, int b,
+ Pixel nUsed )
+{
+ USHORT nPixel = 0;
+ int nBest = ColorDiff( rPalette[0], r, g, b );
+
+ for( USHORT i = 1; i < nUsed; i++ )
+ {
+ int n = ColorDiff( rPalette[i], r, g, b );
+
+ if( n < nBest )
+ {
+ if( !n )
+ return i;
+
+ nPixel = i;
+ nBest = n;
+ }
+ }
+ return nPixel;
+}
+
+void SalColormap::GetLookupTable()
+{
+ m_aLookupTable = std::vector<USHORT>(16*16*16);
+
+ int i = 0;
+ for( int r = 0; r < 256; r += 17 )
+ for( int g = 0; g < 256; g += 17 )
+ for( int b = 0; b < 256; b += 17 )
+ m_aLookupTable[i++] = sal_Lookup( m_aPalette, r, g, b, m_nUsed );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColor SalColormap::GetColor( Pixel nPixel ) const
+{
+ if( m_nBlackPixel == nPixel ) return SALCOLOR_BLACK;
+ if( m_nWhitePixel == nPixel ) return SALCOLOR_WHITE;
+
+ if( m_aVisual.GetVisual() )
+ {
+ if( m_aVisual.GetClass() == TrueColor )
+ return m_aVisual.GetTCColor( nPixel );
+
+ if( m_aPalette.empty()
+ && m_hColormap
+#ifdef PSEUDOCOLOR12
+ && m_aVisual.GetDepth() <= 12
+#else
+ && m_aVisual.GetDepth() <= 8
+#endif
+ && m_aVisual.GetClass() == PseudoColor )
+ ((SalColormap*)this)->GetPalette();
+ }
+
+ if( !m_aPalette.empty() && nPixel < m_nUsed )
+ return m_aPalette[nPixel];
+
+ if( m_hColormap )
+ {
+ DBG_ASSERT( 1, "SalColormap::GetColor() !hColormap_\n" );
+ return nPixel;
+ }
+
+ // DirectColor, StaticColor, StaticGray, GrayScale
+ XColor aColor;
+
+ aColor.pixel = nPixel;
+
+ XQueryColor( m_pDisplay->GetDisplay(), m_hColormap, &aColor );
+
+ return MAKE_SALCOLOR( aColor.red>>8, aColor.green>>8, aColor.blue>>8 );
+}
+
+inline BOOL SalColormap::GetXPixel( XColor &rColor,
+ int r,
+ int g,
+ int b ) const
+{
+ rColor.red = r * 257;
+ rColor.green = g * 257;
+ rColor.blue = b * 257;
+ return XAllocColor( GetXDisplay(), m_hColormap, &rColor );
+}
+
+BOOL SalColormap::GetXPixels( XColor &rColor,
+ int r,
+ int g,
+ int b ) const
+{
+ if( !GetXPixel( rColor, r, g, b ) )
+ return FALSE;
+ if( rColor.pixel & 1 )
+ return TRUE;
+ return GetXPixel( rColor, r^0xFF, g^0xFF, b^0xFF );
+}
+
+Pixel SalColormap::GetPixel( SalColor nSalColor ) const
+{
+ if( SALCOLOR_NONE == nSalColor ) return 0;
+ if( SALCOLOR_BLACK == nSalColor ) return m_nBlackPixel;
+ if( SALCOLOR_WHITE == nSalColor ) return m_nWhitePixel;
+
+ if( m_aVisual.GetClass() == TrueColor )
+ return m_aVisual.GetTCPixel( nSalColor );
+
+ if( m_aLookupTable.empty() )
+ {
+ if( m_aPalette.empty()
+ && m_hColormap
+#ifdef PSEUDOCOLOR12
+ && m_aVisual.GetDepth() <= 12
+#else
+ && m_aVisual.GetDepth() <= 8
+#endif
+ && m_aVisual.GetClass() == PseudoColor ) // what else ???
+ ((SalColormap*)this)->GetPalette();
+
+ if( !m_aPalette.empty() )
+ for( Pixel i = 0; i < m_nUsed; i++ )
+ if( m_aPalette[i] == nSalColor )
+ return i;
+
+ if( m_hColormap )
+ {
+ // DirectColor, StaticColor, StaticGray, GrayScale (PseudoColor)
+ XColor aColor;
+
+ if( GetXPixel( aColor,
+ SALCOLOR_RED ( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE ( nSalColor ) ) )
+ {
+ if( !m_aPalette.empty() && !m_aPalette[aColor.pixel] )
+ {
+ const_cast<SalColormap*>(this)->m_aPalette[aColor.pixel] = nSalColor;
+
+ if( !(aColor.pixel & 1) && !m_aPalette[aColor.pixel+1] )
+ {
+ XColor aInversColor;
+
+ SalColor nInversColor = nSalColor ^ 0xFFFFFF;
+
+ GetXPixel( aInversColor,
+ SALCOLOR_RED ( nInversColor ),
+ SALCOLOR_GREEN( nInversColor ),
+ SALCOLOR_BLUE ( nInversColor ) );
+
+ if( !m_aPalette[aInversColor.pixel] )
+ const_cast<SalColormap*>(this)->m_aPalette[aInversColor.pixel] = nInversColor;
+#ifdef DBG_UTIL
+ else
+ fprintf( stderr, "SalColormap::GetPixel() 0x%06lx=%lu 0x%06lx=%lu\n",
+ static_cast< unsigned long >(nSalColor), aColor.pixel,
+ static_cast< unsigned long >(nInversColor), aInversColor.pixel);
+#endif
+ }
+ }
+
+ return aColor.pixel;
+ }
+
+#ifdef DBG_UTIL
+ fprintf( stderr, "SalColormap::GetPixel() !XAllocColor %lx\n",
+ static_cast< unsigned long >(nSalColor) );
+#endif
+ }
+
+ if( m_aPalette.empty() )
+ {
+#ifdef DBG_UTIL
+ fprintf( stderr, "SalColormap::GetPixel() Palette empty %lx\n",
+ static_cast< unsigned long >(nSalColor));
+#endif
+ return nSalColor;
+ }
+
+ ((SalColormap*)this)->GetLookupTable();
+ }
+
+ // Colormatching ueber Palette
+ USHORT r = SALCOLOR_RED ( nSalColor );
+ USHORT g = SALCOLOR_GREEN( nSalColor );
+ USHORT b = SALCOLOR_BLUE ( nSalColor );
+ return m_aLookupTable[ (((r+8)/17) << 8)
+ + (((g+8)/17) << 4)
+ + ((b+8)/17) ];
+}
+
diff --git a/vcl/unx/generic/app/salinst.cxx b/vcl/unx/generic/app/salinst.cxx
new file mode 100644
index 000000000000..98bce72d6bce
--- /dev/null
+++ b/vcl/unx/generic/app/salinst.cxx
@@ -0,0 +1,452 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "osl/module.hxx"
+#include "tools/solarmutex.hxx"
+#include "vos/mutex.hxx"
+
+
+#include "unx/salunx.h"
+#include "unx/saldata.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/salinst.h"
+#include "unx/salframe.h"
+#include "unx/dtint.hxx"
+#include "unx/salprn.h"
+#include "unx/sm.hxx"
+
+#include "vcl/apptypes.hxx"
+#include "vcl/helper.hxx"
+
+#include "salwtype.hxx"
+
+// -------------------------------------------------------------------------
+//
+// SalYieldMutex
+//
+// -------------------------------------------------------------------------
+
+SalYieldMutex::SalYieldMutex()
+{
+ mnCount = 0;
+ mnThreadId = 0;
+ ::tools::SolarMutex::SetSolarMutex( this );
+}
+
+void SalYieldMutex::acquire()
+{
+ OMutex::acquire();
+ mnThreadId = vos::OThread::getCurrentIdentifier();
+ mnCount++;
+}
+
+void SalYieldMutex::release()
+{
+ if ( mnThreadId == vos::OThread::getCurrentIdentifier() )
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ }
+ OMutex::release();
+}
+
+sal_Bool SalYieldMutex::tryToAcquire()
+{
+ if ( OMutex::tryToAcquire() )
+ {
+ mnThreadId = vos::OThread::getCurrentIdentifier();
+ mnCount++;
+ return True;
+ }
+ else
+ return False;
+}
+
+//----------------------------------------------------------------------------
+
+// -=-= SalInstance =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// plugin factory function
+extern "C"
+{
+ VCL_DLLPUBLIC SalInstance* create_SalInstance()
+ {
+ /* #i92121# workaround deadlocks in the X11 implementation
+ */
+ static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
+ /* #i90094#
+ from now on we know that an X connection will be
+ established, so protect X against itself
+ */
+ if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
+ XInitThreads();
+
+ X11SalInstance* pInstance = new X11SalInstance( new SalYieldMutex() );
+
+ // initialize SalData
+ X11SalData *pSalData = new X11SalData;
+ SetSalData( pSalData );
+ pSalData->m_pInstance = pInstance;
+ pSalData->Init();
+
+ return pInstance;
+ }
+}
+
+X11SalInstance::~X11SalInstance()
+{
+ // close session management
+ SessionManagerClient::close();
+
+ // dispose SalDisplay list from SalData
+ // would be done in a static destructor else which is
+ // a little late
+
+ X11SalData *pSalData = GetX11SalData();
+ pSalData->deInitNWF();
+ delete pSalData;
+ SetSalData( NULL );
+
+ ::tools::SolarMutex::SetSolarMutex( 0 );
+ delete mpSalYieldMutex;
+}
+
+
+// --------------------------------------------------------
+// AnyInput from sv/mow/source/app/svapp.cxx
+
+struct PredicateReturn
+{
+ USHORT nType;
+ BOOL bRet;
+};
+
+extern "C" {
+Bool ImplPredicateEvent( Display *, XEvent *pEvent, char *pData )
+{
+ PredicateReturn *pPre = (PredicateReturn *)pData;
+
+ if ( pPre->bRet )
+ return False;
+
+ USHORT nType;
+
+ switch( pEvent->type )
+ {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ nType = INPUT_MOUSE;
+ break;
+
+ case XLIB_KeyPress:
+ //case KeyRelease:
+ nType = INPUT_KEYBOARD;
+ break;
+ case Expose:
+ case GraphicsExpose:
+ case NoExpose:
+ nType = INPUT_PAINT;
+ break;
+ default:
+ nType = 0;
+ }
+
+ if ( (nType & pPre->nType) || ( ! nType && (pPre->nType & INPUT_OTHER) ) )
+ pPre->bRet = TRUE;
+
+ return False;
+}
+}
+
+bool X11SalInstance::AnyInput(USHORT nType)
+{
+ X11SalData *pSalData = GetX11SalData();
+ Display *pDisplay = pSalData->GetDisplay()->GetDisplay();
+ BOOL bRet = FALSE;
+
+ if( (nType & INPUT_TIMER) &&
+ pSalData->GetDisplay()->GetXLib()->CheckTimeout( false ) )
+ {
+ bRet = TRUE;
+ }
+ else if (XPending(pDisplay) )
+ {
+ PredicateReturn aInput;
+ XEvent aEvent;
+
+ aInput.bRet = FALSE;
+ aInput.nType = nType;
+
+ XCheckIfEvent(pDisplay, &aEvent, ImplPredicateEvent,
+ (char *)&aInput );
+
+ bRet = aInput.bRet;
+ }
+ return bRet;
+}
+
+vos::IMutex* X11SalInstance::GetYieldMutex()
+{
+ return mpSalYieldMutex;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG X11SalInstance::ReleaseYieldMutex()
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ if ( pYieldMutex->GetThreadId() ==
+ vos::OThread::getCurrentIdentifier() )
+ {
+ ULONG nCount = pYieldMutex->GetAcquireCount();
+ ULONG n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+
+ return nCount;
+ }
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::AcquireYieldMutex( ULONG nCount )
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ while ( nCount )
+ {
+ pYieldMutex->acquire();
+ nCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool X11SalInstance::CheckYieldMutex()
+{
+ bool bRet = true;
+
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ if ( pYieldMutex->GetThreadId() !=
+ vos::OThread::getCurrentIdentifier() )
+ {
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{ GetX11SalData()->GetLib()->Yield( bWait, bHandleAllCurrentEvents ); }
+
+void* X11SalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
+{
+ static const char* pDisplay = getenv( "DISPLAY" );
+ rReturnedType = AsciiCString;
+ rReturnedBytes = pDisplay ? strlen( pDisplay )+1 : 1;
+ return pDisplay ? (void*)pDisplay : (void*)"";
+}
+
+SalFrame *X11SalInstance::CreateFrame( SalFrame *pParent, ULONG nSalFrameStyle )
+{
+ SalFrame *pFrame = new X11SalFrame( pParent, nSalFrameStyle );
+
+ return pFrame;
+}
+
+SalFrame* X11SalInstance::CreateChildFrame( SystemParentData* pParentData, ULONG nStyle )
+{
+ SalFrame* pFrame = new X11SalFrame( NULL, nStyle, pParentData );
+
+ return pFrame;
+}
+
+void X11SalInstance::DestroyFrame( SalFrame* pFrame )
+{
+ delete pFrame;
+}
+
+static void getServerDirectories( std::list< rtl::OString >& o_rFontPaths )
+{
+#ifdef LINUX
+ /*
+ * chkfontpath exists on some (RH derived) Linux distributions
+ */
+ static const char* pCommands[] = {
+ "/usr/sbin/chkfontpath 2>/dev/null", "chkfontpath 2>/dev/null"
+ };
+ ::std::list< ByteString > aLines;
+
+ for( unsigned int i = 0; i < sizeof(pCommands)/sizeof(pCommands[0]); i++ )
+ {
+ FILE* pPipe = popen( pCommands[i], "r" );
+ aLines.clear();
+ if( pPipe )
+ {
+ char line[1024];
+ char* pSearch;
+ while( fgets( line, sizeof(line), pPipe ) )
+ {
+ int nLen = strlen( line );
+ if( line[nLen-1] == '\n' )
+ line[nLen-1] = 0;
+ pSearch = strstr( line, ": " );
+ if( pSearch )
+ aLines.push_back( pSearch+2 );
+ }
+ if( ! pclose( pPipe ) )
+ break;
+ }
+ }
+
+ for( ::std::list< ByteString >::iterator it = aLines.begin(); it != aLines.end(); ++it )
+ {
+ if( ! access( it->GetBuffer(), F_OK ) )
+ {
+ o_rFontPaths.push_back( *it );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding fs dir %s\n", it->GetBuffer() );
+#endif
+ }
+ }
+#else
+ (void)o_rFontPaths;
+#endif
+}
+
+
+
+void X11SalInstance::FillFontPathList( std::list< rtl::OString >& o_rFontPaths )
+{
+ Display *pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+
+ DBG_ASSERT( pDisplay, "No Display !" );
+ if( pDisplay )
+ {
+ // get font paths to look for fonts
+ int nPaths = 0, i;
+ char** pPaths = XGetFontPath( pDisplay, &nPaths );
+
+ bool bServerDirs = false;
+ for( i = 0; i < nPaths; i++ )
+ {
+ OString aPath( pPaths[i] );
+ sal_Int32 nPos = 0;
+ if( ! bServerDirs
+ && ( nPos = aPath.indexOf( ':' ) ) > 0
+ && ( !aPath.copy(nPos).equals( ":unscaled" ) ) )
+ {
+ bServerDirs = true;
+ getServerDirectories( o_rFontPaths );
+ }
+ else
+ {
+ psp::normPath( aPath );
+ o_rFontPaths.push_back( aPath );
+ }
+ }
+
+ if( nPaths )
+ XFreeFontPath( pPaths );
+ }
+
+ // insert some standard directories
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/TrueType" );
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/Type1" );
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/Type1/sun" );
+ o_rFontPaths.push_back( "/usr/X11R6/lib/X11/fonts/truetype" );
+ o_rFontPaths.push_back( "/usr/X11R6/lib/X11/fonts/Type1" );
+
+ #ifdef SOLARIS
+ /* cde specials, from /usr/dt/bin/Xsession: here are the good fonts,
+ the OWfontpath file may contain as well multiple lines as a comma
+ separated list of fonts in each line. to make it even more weird
+ environment variables are allowed as well */
+
+ const char* lang = getenv("LANG");
+ if ( lang != NULL )
+ {
+ String aOpenWinDir( String::CreateFromAscii( "/usr/openwin/lib/locale/" ) );
+ aOpenWinDir.AppendAscii( lang );
+ aOpenWinDir.AppendAscii( "/OWfontpath" );
+
+ SvFileStream aStream( aOpenWinDir, STREAM_READ );
+
+ // TODO: replace environment variables
+ while( aStream.IsOpen() && ! aStream.IsEof() )
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ // need an OString for normpath
+ OString aNLine( aLine );
+ psp::normPath( aNLine );
+ aLine = aNLine;
+ // try to avoid bad fonts in some cases
+ static bool bAvoid = (strncasecmp( lang, "ar", 2 ) == 0) || (strncasecmp( lang, "he", 2 ) == 0) || strncasecmp( lang, "iw", 2 ) == 0 || (strncasecmp( lang, "hi", 2 ) == 0);
+ if( bAvoid && aLine.Search( "iso_8859" ) != STRING_NOTFOUND )
+ continue;
+ o_rFontPaths.push_back( aLine );
+ }
+ }
+ #endif /* SOLARIS */
+}
+
+extern "C" { static void SAL_CALL thisModule() {} }
+
+void X11SalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType)
+{
+ const rtl::OUString SYM_ADD_TO_RECENTLY_USED_FILE_LIST(RTL_CONSTASCII_USTRINGPARAM("add_to_recently_used_file_list"));
+ const rtl::OUString LIB_RECENT_FILE(RTL_CONSTASCII_USTRINGPARAM("librecentfile.so"));
+ typedef void (*PFUNC_ADD_TO_RECENTLY_USED_LIST)(const rtl::OUString&, const rtl::OUString&);
+
+ PFUNC_ADD_TO_RECENTLY_USED_LIST add_to_recently_used_file_list = 0;
+
+ osl::Module module;
+ module.loadRelative( &thisModule, LIB_RECENT_FILE );
+ if (module.is())
+ add_to_recently_used_file_list = (PFUNC_ADD_TO_RECENTLY_USED_LIST)module.getFunctionSymbol(SYM_ADD_TO_RECENTLY_USED_FILE_LIST);
+ if (add_to_recently_used_file_list)
+ add_to_recently_used_file_list(rFileUrl, rMimeType);
+}
diff --git a/vcl/unx/generic/app/salsys.cxx b/vcl/unx/generic/app/salsys.cxx
new file mode 100644
index 000000000000..92f0748b6460
--- /dev/null
+++ b/vcl/unx/generic/app/salsys.cxx
@@ -0,0 +1,226 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <unx/salunx.h>
+#include <unx/dtint.hxx>
+#include <unx/saldata.hxx>
+#include <unx/salinst.h>
+#include <unx/saldisp.hxx>
+#include <unx/salsys.h>
+
+#include <vcl/msgbox.hxx>
+#include <vcl/button.hxx>
+
+#include <svdata.hxx>
+
+#include <rtl/ustrbuf.hxx>
+#include <osl/thread.h>
+
+
+SalSystem* X11SalInstance::CreateSalSystem()
+{
+ return new X11SalSystem();
+}
+
+// -----------------------------------------------------------------------
+
+X11SalSystem::~X11SalSystem()
+{
+}
+
+// for the moment only handle xinerama case
+unsigned int X11SalSystem::GetDisplayScreenCount()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ return pSalDisp->IsXinerama() ? pSalDisp->GetXineramaScreens().size() : pSalDisp->GetScreenCount();
+}
+
+bool X11SalSystem::IsMultiDisplay()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ unsigned int nScreenCount = pSalDisp->GetScreenCount();
+ return pSalDisp->IsXinerama() ? false : (nScreenCount > 1);
+}
+
+unsigned int X11SalSystem::GetDefaultDisplayNumber()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ return pSalDisp->IsXinerama() ? pSalDisp->GetDefaultMonitorNumber() : pSalDisp->GetDefaultScreenNumber();
+}
+
+Rectangle X11SalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen )
+{
+ Rectangle aRet;
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ if( pSalDisp->IsXinerama() )
+ {
+ const std::vector< Rectangle >& rScreens = pSalDisp->GetXineramaScreens();
+ if( nScreen < rScreens.size() )
+ aRet = rScreens[nScreen];
+ }
+ else
+ {
+ const SalDisplay::ScreenData& rScreen = pSalDisp->getDataForScreen( nScreen );
+ aRet = Rectangle( Point( 0, 0 ), rScreen.m_aSize );
+ }
+
+ return aRet;
+}
+
+Rectangle X11SalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ // FIXME: workareas
+ return GetDisplayScreenPosSizePixel( nScreen );
+}
+
+rtl::OUString X11SalSystem::GetScreenName( unsigned int nScreen )
+{
+ rtl::OUString aScreenName;
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ if( pSalDisp->IsXinerama() )
+ {
+ const std::vector< Rectangle >& rScreens = pSalDisp->GetXineramaScreens();
+ if( nScreen >= rScreens.size() )
+ nScreen = 0;
+ rtl::OUStringBuffer aBuf( 256 );
+ aBuf.append( rtl::OStringToOUString( rtl::OString( DisplayString( pSalDisp->GetDisplay() ) ), osl_getThreadTextEncoding() ) );
+ aBuf.appendAscii( " [" );
+ aBuf.append( static_cast<sal_Int32>(nScreen) );
+ aBuf.append( sal_Unicode(']') );
+ aScreenName = aBuf.makeStringAndClear();
+ }
+ else
+ {
+ if( nScreen >= static_cast<unsigned int>(pSalDisp->GetScreenCount()) )
+ nScreen = 0;
+ rtl::OUStringBuffer aBuf( 256 );
+ aBuf.append( rtl::OStringToOUString( rtl::OString( DisplayString( pSalDisp->GetDisplay() ) ), osl_getThreadTextEncoding() ) );
+ // search backwards for ':'
+ int nPos = aBuf.getLength();
+ if( nPos > 0 )
+ nPos--;
+ while( nPos > 0 && aBuf.charAt( nPos ) != ':' )
+ nPos--;
+ // search forward to '.'
+ while( nPos < aBuf.getLength() && aBuf.charAt( nPos ) != '.' )
+ nPos++;
+ if( nPos < aBuf.getLength() )
+ aBuf.setLength( nPos+1 );
+ else
+ aBuf.append( sal_Unicode('.') );
+ aBuf.append( static_cast<sal_Int32>(nScreen) );
+ aScreenName = aBuf.makeStringAndClear();
+ }
+ return aScreenName;
+}
+
+int X11SalSystem::ShowNativeDialog( const String& rTitle, const String& rMessage, const std::list< String >& rButtons, int nDefButton )
+{
+ int nRet = -1;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpIntroWindow )
+ pSVData->mpIntroWindow->Hide();
+
+ WarningBox aWarn( NULL, WB_STDWORK, rMessage );
+ aWarn.SetText( rTitle );
+ aWarn.Clear();
+
+ USHORT nButton = 0;
+ for( std::list< String >::const_iterator it = rButtons.begin(); it != rButtons.end(); ++it )
+ {
+ aWarn.AddButton( *it, nButton+1, nButton == (USHORT)nDefButton ? BUTTONDIALOG_DEFBUTTON : 0 );
+ nButton++;
+ }
+ aWarn.SetFocusButton( (USHORT)nDefButton+1 );
+
+ nRet = ((int)aWarn.Execute()) - 1;
+
+ // normalize behaviour, actually this should never happen
+ if( nRet < -1 || nRet >= int(rButtons.size()) )
+ nRet = -1;
+
+ return nRet;
+}
+
+int X11SalSystem::ShowNativeMessageBox(const String& rTitle, const String& rMessage, int nButtonCombination, int nDefaultButton)
+{
+ int nDefButton = 0;
+ std::list< String > aButtons;
+ int nButtonIds[5], nBut = 0;
+
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK ||
+ nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL )
+ {
+ aButtons.push_back( Button::GetStandardText( BUTTON_OK ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK;
+ }
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_YES_NO_CANCEL ||
+ nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_YES_NO )
+ {
+ aButtons.push_back( Button::GetStandardText( BUTTON_YES ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_YES;
+ aButtons.push_back( Button::GetStandardText( BUTTON_NO ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO;
+ if( nDefaultButton == SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO )
+ nDefButton = 1;
+ }
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL ||
+ nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_YES_NO_CANCEL ||
+ nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL )
+ {
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL )
+ {
+ aButtons.push_back( Button::GetStandardText( BUTTON_RETRY ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_RETRY;
+ }
+ aButtons.push_back( Button::GetStandardText( BUTTON_CANCEL ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL;
+ if( nDefaultButton == SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL )
+ nDefButton = aButtons.size()-1;
+ }
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_ABORT_RETRY_IGNORE )
+ {
+ aButtons.push_back( Button::GetStandardText( BUTTON_ABORT ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_ABORT;
+ aButtons.push_back( Button::GetStandardText( BUTTON_RETRY ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_RETRY;
+ aButtons.push_back( Button::GetStandardText( BUTTON_IGNORE ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_IGNORE;
+ switch( nDefaultButton )
+ {
+ case SALSYSTEM_SHOWNATIVEMSGBOX_BTN_RETRY: nDefButton = 1;break;
+ case SALSYSTEM_SHOWNATIVEMSGBOX_BTN_IGNORE: nDefButton = 2;break;
+ }
+ }
+ int nResult = ShowNativeDialog( rTitle, rMessage, aButtons, nDefButton );
+
+ return nResult != -1 ? nButtonIds[ nResult ] : 0;
+}
diff --git a/vcl/unx/generic/app/saltimer.cxx b/vcl/unx/generic/app/saltimer.cxx
new file mode 100644
index 000000000000..d68ec388448e
--- /dev/null
+++ b/vcl/unx/generic/app/saltimer.cxx
@@ -0,0 +1,96 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <unx/salunx.h>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+#include <unx/saltimer.h>
+#include <unx/salinst.h>
+
+// -=-= SalData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalData::Timeout() const
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpSalTimer )
+ pSVData->mpSalTimer->CallCallback();
+}
+
+// -=-= SalXLib =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalXLib::StopTimer()
+{
+ m_aTimeout.tv_sec = 0;
+ m_aTimeout.tv_usec = 0;
+ m_nTimeoutMS = 0;
+}
+
+void SalXLib::StartTimer( ULONG nMS )
+{
+ timeval Timeout (m_aTimeout); // previous timeout.
+ gettimeofday (&m_aTimeout, 0);
+
+ m_nTimeoutMS = nMS;
+ m_aTimeout += m_nTimeoutMS;
+
+ if ((Timeout > m_aTimeout) || (Timeout.tv_sec == 0))
+ {
+ // Wakeup from previous timeout (or stopped timer).
+ Wakeup();
+ }
+}
+
+// -=-= SalTimer -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalTimer* X11SalInstance::CreateSalTimer()
+{
+ return new X11SalTimer();
+}
+
+X11SalTimer::~X11SalTimer()
+{
+}
+
+void X11SalTimer::Stop()
+{
+ GetX11SalData()->GetLib()->StopTimer();
+}
+
+void X11SalTimer::Start( ULONG nMS )
+{
+ GetX11SalData()->GetLib()->StartTimer( nMS );
+}
+
diff --git a/vcl/unx/generic/app/sm.cxx b/vcl/unx/generic/app/sm.cxx
new file mode 100644
index 000000000000..c421ceeaf0e3
--- /dev/null
+++ b/vcl/unx/generic/app/sm.cxx
@@ -0,0 +1,801 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <string.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include <osl/process.h>
+#include <osl/security.h>
+#include <osl/conditn.h>
+
+#include <tools/prex.h>
+#include <X11/Xatom.h>
+#include <tools/postx.h>
+
+#include <unx/sm.hxx>
+#include <unx/saldata.hxx>
+#include <unx/saldisp.hxx>
+#include <unx/salframe.h>
+#include <unx/salinst.h>
+
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+#define USE_SM_EXTENSION
+
+#if OSL_DEBUG_LEVEL > 1
+#include <cstdarg>
+static bool bFirstAssert = true;
+#endif
+
+#if OSL_DEBUG_LEVEL > 1
+inline void SMprintf( const char* pFormat, ... )
+#else
+inline void SMprintf( const char*, ... )
+#endif
+{
+#if OSL_DEBUG_LEVEL > 1
+ FILE* fp = fopen( "/tmp/sessionlog.txt", bFirstAssert ? "w" : "a" );
+ if(!fp) return;
+ bFirstAssert = false;
+ std::va_list ap;
+ va_start( ap, pFormat );
+ vfprintf( fp, pFormat, ap );
+ fclose( fp );
+ va_end( ap );
+#endif
+};
+
+static IceSalSession* pOneInstance = NULL;
+
+SalSession* X11SalInstance::CreateSalSession()
+{
+ if( ! pOneInstance )
+ pOneInstance = new IceSalSession();
+ return pOneInstance;
+}
+
+/*
+ * class IceSalSession
+ */
+
+static X11SalFrame* pOldStyleSaveFrame = NULL;
+
+IceSalSession::IceSalSession()
+{
+}
+
+IceSalSession::~IceSalSession()
+{
+ if( pOneInstance == this )
+ pOneInstance = NULL;
+}
+
+void IceSalSession::queryInteraction()
+{
+ if( ! SessionManagerClient::queryInteraction() )
+ {
+ SalSessionInteractionEvent aEvent( false );
+ CallCallback( &aEvent );
+ }
+}
+
+void IceSalSession::interactionDone()
+{
+ SessionManagerClient::interactionDone( false );
+}
+
+void IceSalSession::saveDone()
+{
+ SessionManagerClient::saveDone();
+ if( pOldStyleSaveFrame )
+ {
+ // note: does nothing if not running in generic plugin
+ X11SalFrame::SaveYourselfDone( pOldStyleSaveFrame );
+ }
+}
+
+bool IceSalSession::cancelShutdown()
+{
+ SessionManagerClient::interactionDone( true );
+ return false;
+}
+
+void IceSalSession::handleOldX11SaveYourself( SalFrame* pFrame )
+{
+ // do this only once
+ if( ! pOldStyleSaveFrame )
+ {
+ pOldStyleSaveFrame = static_cast<X11SalFrame*>(pFrame);
+ if( pOneInstance )
+ {
+ SalSessionSaveRequestEvent aEvent( true, false );
+ pOneInstance->CallCallback( &aEvent );
+ }
+ }
+}
+
+extern "C" void SAL_CALL ICEConnectionWorker( void* );
+
+class ICEConnectionObserver
+{
+ friend void SAL_CALL ICEConnectionWorker(void*);
+ static BOOL bIsWatching;
+ static void ICEWatchProc( IceConn connection, IcePointer client_data,
+ Bool opening, IcePointer* watch_data );
+
+ static struct pollfd* pFilehandles;
+ static IceConn* pConnections;
+ static int nConnections;
+ static int nWakeupFiles[2];
+ static oslMutex ICEMutex;
+ static oslThread ICEThread;
+#ifdef USE_SM_EXTENSION
+ static IceIOErrorHandler origIOErrorHandler;
+ static IceErrorHandler origErrorHandler;
+#endif
+public:
+
+ static void activate();
+ static void deactivate();
+ static void lock();
+ static void unlock();
+ static void wakeup();
+};
+
+
+SmcConn SessionManagerClient::aSmcConnection = NULL;
+ByteString SessionManagerClient::aClientID;
+BOOL ICEConnectionObserver::bIsWatching = FALSE;
+struct pollfd* ICEConnectionObserver::pFilehandles = NULL;
+IceConn* ICEConnectionObserver::pConnections = NULL;
+int ICEConnectionObserver::nConnections = 0;
+oslMutex ICEConnectionObserver::ICEMutex = NULL;
+oslThread ICEConnectionObserver::ICEThread = NULL;
+int ICEConnectionObserver::nWakeupFiles[2] = { 0, 0 };
+
+#ifdef USE_SM_EXTENSION
+IceIOErrorHandler ICEConnectionObserver::origIOErrorHandler = NULL;
+IceErrorHandler ICEConnectionObserver::origErrorHandler = NULL;
+
+static void IgnoreIceErrors(IceConn, Bool, int, unsigned long, int, int, IcePointer)
+{
+}
+
+static void IgnoreIceIOErrors(IceConn)
+{
+}
+#endif
+
+// HACK
+bool SessionManagerClient::bDocSaveDone = false;
+
+
+static SmProp* pSmProps = NULL;
+static SmProp** ppSmProps = NULL;
+static int nSmProps = 0;
+static unsigned char *pSmRestartHint = NULL;
+
+
+static void BuildSmPropertyList()
+{
+ if( ! pSmProps )
+ {
+ ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
+
+ nSmProps = 5;
+ pSmProps = new SmProp[ nSmProps ];
+
+ pSmProps[ 0 ].name = const_cast<char*>(SmCloneCommand);
+ pSmProps[ 0 ].type = const_cast<char*>(SmLISTofARRAY8);
+ pSmProps[ 0 ].num_vals = 1;
+ pSmProps[ 0 ].vals = new SmPropValue;
+ pSmProps[ 0 ].vals->length = aExec.Len()+1;
+ pSmProps[ 0 ].vals->value = strdup( aExec.GetBuffer() );
+
+ pSmProps[ 1 ].name = const_cast<char*>(SmProgram);
+ pSmProps[ 1 ].type = const_cast<char*>(SmARRAY8);
+ pSmProps[ 1 ].num_vals = 1;
+ pSmProps[ 1 ].vals = new SmPropValue;
+ pSmProps[ 1 ].vals->length = aExec.Len()+1;
+ pSmProps[ 1 ].vals->value = strdup( aExec.GetBuffer() );
+
+ pSmProps[ 2 ].name = const_cast<char*>(SmRestartCommand);
+ pSmProps[ 2 ].type = const_cast<char*>(SmLISTofARRAY8);
+ pSmProps[ 2 ].num_vals = 3;
+ pSmProps[ 2 ].vals = new SmPropValue[3];
+ pSmProps[ 2 ].vals[0].length = aExec.Len()+1;
+ pSmProps[ 2 ].vals[0].value = strdup( aExec.GetBuffer() );
+ ByteString aRestartOption( "-session=" );
+ aRestartOption.Append( SessionManagerClient::getSessionID() );
+ pSmProps[ 2 ].vals[1].length = aRestartOption.Len()+1;
+ pSmProps[ 2 ].vals[1].value = strdup( aRestartOption.GetBuffer() );
+ ByteString aRestartOptionNoLogo( "-nologo" );
+ pSmProps[ 2 ].vals[2].length = aRestartOptionNoLogo.Len()+1;
+ pSmProps[ 2 ].vals[2].value = strdup( aRestartOptionNoLogo.GetBuffer() );
+
+ rtl::OUString aUserName;
+ rtl::OString aUser;
+ oslSecurity aSec = osl_getCurrentSecurity();
+ if( aSec )
+ {
+ osl_getUserName( aSec, &aUserName.pData );
+ aUser = rtl::OUStringToOString( aUserName, osl_getThreadTextEncoding() );
+ osl_freeSecurityHandle( aSec );
+ }
+
+ pSmProps[ 3 ].name = const_cast<char*>(SmUserID);
+ pSmProps[ 3 ].type = const_cast<char*>(SmARRAY8);
+ pSmProps[ 3 ].num_vals = 1;
+ pSmProps[ 3 ].vals = new SmPropValue;
+ pSmProps[ 3 ].vals->value = strdup( aUser.getStr() );
+ pSmProps[ 3 ].vals->length = strlen( (char *)pSmProps[ 3 ].vals->value )+1;
+
+ pSmProps[ 4 ].name = const_cast<char*>(SmRestartStyleHint);
+ pSmProps[ 4 ].type = const_cast<char*>(SmCARD8);
+ pSmProps[ 4 ].num_vals = 1;
+ pSmProps[ 4 ].vals = new SmPropValue;
+ pSmProps[ 4 ].vals->value = malloc(1);
+ pSmRestartHint = (unsigned char *)pSmProps[ 4 ].vals->value;
+ *pSmRestartHint = SmRestartIfRunning;
+ pSmProps[ 4 ].vals->length = 1;
+
+ ppSmProps = new SmProp*[ nSmProps ];
+ for( int i = 0; i < nSmProps; i++ )
+ ppSmProps[ i ] = &pSmProps[i];
+ }
+}
+
+bool SessionManagerClient::checkDocumentsSaved()
+{
+ return bDocSaveDone;
+}
+
+IMPL_STATIC_LINK( SessionManagerClient, SaveYourselfHdl, void*, EMPTYARG )
+{
+ SMprintf( "posting save documents event shutdown = %s\n", (pThis!=0) ? "true" : "false" );
+
+ static bool bFirstShutdown=true;
+ if (pThis != 0 && bFirstShutdown) //first shutdown request
+ {
+ bFirstShutdown = false;
+ /*
+ If we have no actual frames open, e.g. we launched a quickstarter,
+ and then shutdown all our frames leaving just a quickstarter running,
+ then we don't want to launch an empty toplevel frame on the next
+ start. (The job of scheduling the restart of the quick-starter is a
+ task of the quick-starter)
+ */
+ *pSmRestartHint = SmRestartNever;
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ Window *pWindow = (*it)->GetWindow();
+ if (pWindow && pWindow->IsVisible())
+ {
+ *pSmRestartHint = SmRestartIfRunning;
+ break;
+ }
+ }
+ }
+
+ if( pOneInstance )
+ {
+ SalSessionSaveRequestEvent aEvent( pThis != 0, false );
+ pOneInstance->CallCallback( &aEvent );
+ }
+ else
+ saveDone();
+
+ return 0;
+}
+
+IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, InteractionHdl, void*, EMPTYARG )
+{
+ SMprintf( "interaction link\n" );
+ if( pOneInstance )
+ {
+ SalSessionInteractionEvent aEvent( true );
+ pOneInstance->CallCallback( &aEvent );
+ }
+
+ return 0;
+}
+
+IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, ShutDownCancelHdl, void*, EMPTYARG )
+{
+ SMprintf( "shutdown cancel\n" );
+ if( pOneInstance )
+ {
+ SalSessionShutdownCancelEvent aEvent;
+ pOneInstance->CallCallback( &aEvent );
+ }
+
+ return 0;
+}
+
+void SessionManagerClient::SaveYourselfProc(
+ SmcConn,
+ SmPointer,
+ int save_type,
+ Bool shutdown,
+ int interact_style,
+ Bool
+ )
+{
+ SMprintf( "Session: save yourself, save_type = %s, shutdown = %s, interact_style = %s, fast = %s\n",
+ save_type == SmSaveLocal ? "SmcSaveLocal" :
+ ( save_type == SmSaveGlobal ? "SmcSaveGlobal" :
+ ( save_type == SmSaveBoth ? "SmcSaveBoth" : "<unknown>" ) ),
+ shutdown ? "true" : "false",
+ interact_style == SmInteractStyleNone ? "SmInteractStyleNone" :
+ ( interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" :
+ ( interact_style == SmInteractStyleAny ? "SmInteractStyleAny" : "<unknown>" ) ),
+ false ? "true" : "false"
+ );
+ BuildSmPropertyList();
+#ifdef USE_SM_EXTENSION
+ bDocSaveDone = false;
+ /* #i49875# some session managers send a "die" message if the
+ * saveDone does not come early enough for their convenience
+ * this can occasionally happen on startup, especially the first
+ * startup. So shortcut the "not shutting down" case since the
+ * upper layers are currently not interested in that event anyway.
+ */
+ if( ! shutdown )
+ {
+ SessionManagerClient::saveDone();
+ return;
+ }
+ Application::PostUserEvent( STATIC_LINK( (void*)(shutdown ? 0xffffffff : 0x0), SessionManagerClient, SaveYourselfHdl ) );
+ SMprintf( "waiting for save yourself event to be processed\n" );
+#endif
+}
+
+IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, ShutDownHdl, void*, EMPTYARG )
+{
+ if( pOneInstance )
+ {
+ SalSessionQuitEvent aEvent;
+ pOneInstance->CallCallback( &aEvent );
+ }
+
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ SMprintf( rFrames.begin() != rFrames.end() ? "shutdown on first frame\n" : "shutdown event but no frame\n" );
+ if( rFrames.begin() != rFrames.end() )
+ rFrames.front()->CallCallback( SALEVENT_SHUTDOWN, 0 );
+ return 0;
+}
+
+void SessionManagerClient::DieProc(
+ SmcConn connection,
+ SmPointer
+ )
+{
+ SMprintf( "Session: die\n" );
+ if( connection == aSmcConnection )
+ {
+ Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, ShutDownHdl ) );
+ SMprintf( "waiting for shutdown event to be processed\n" );
+ }
+}
+
+void SessionManagerClient::SaveCompleteProc(
+ SmcConn,
+ SmPointer
+ )
+{
+ SMprintf( "Session: save complete\n" );
+}
+
+void SessionManagerClient::ShutdownCanceledProc(
+ SmcConn connection,
+ SmPointer )
+{
+ SMprintf( "Session: shutdown canceled\n" );
+ if( connection == aSmcConnection )
+ Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, ShutDownCancelHdl ) );
+}
+
+void SessionManagerClient::InteractProc(
+ SmcConn connection,
+ SmPointer )
+{
+ SMprintf( "Session: interaction request completed\n" );
+ if( connection == aSmcConnection )
+ Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, InteractionHdl ) );
+}
+
+void SessionManagerClient::saveDone()
+{
+ if( aSmcConnection )
+ {
+ ICEConnectionObserver::lock();
+ SmcSetProperties( aSmcConnection, nSmProps, ppSmProps );
+ SmcSaveYourselfDone( aSmcConnection, True );
+ SMprintf( "sent SaveYourselfDone SmRestartHint of %d\n", *pSmRestartHint );
+ bDocSaveDone = true;
+ ICEConnectionObserver::unlock();
+ }
+}
+
+
+void SessionManagerClient::open()
+{
+ static SmcCallbacks aCallbacks;
+
+#ifdef USE_SM_EXTENSION
+ // this is the way Xt does it, so we can too
+ if( ! aSmcConnection && getenv( "SESSION_MANAGER" ) )
+ {
+ char aErrBuf[1024];
+ ICEConnectionObserver::activate();
+ ICEConnectionObserver::lock();
+
+ char* pClientID = NULL;
+ const ByteString& rPrevId( getPreviousSessionID() );
+
+ aCallbacks.save_yourself.callback = SaveYourselfProc;
+ aCallbacks.save_yourself.client_data = NULL;
+ aCallbacks.die.callback = DieProc;
+ aCallbacks.die.client_data = NULL;
+ aCallbacks.save_complete.callback = SaveCompleteProc;
+ aCallbacks.save_complete.client_data = NULL;
+ aCallbacks.shutdown_cancelled.callback = ShutdownCanceledProc;
+ aCallbacks.shutdown_cancelled.client_data = NULL;
+ aSmcConnection = SmcOpenConnection( NULL,
+ NULL,
+ SmProtoMajor,
+ SmProtoMinor,
+ SmcSaveYourselfProcMask |
+ SmcDieProcMask |
+ SmcSaveCompleteProcMask |
+ SmcShutdownCancelledProcMask ,
+ &aCallbacks,
+ rPrevId.Len() ? const_cast<char*>(rPrevId.GetBuffer()) : NULL,
+ &pClientID,
+ sizeof( aErrBuf ),
+ aErrBuf );
+ if( ! aSmcConnection )
+ SMprintf( "SmcOpenConnection failed: %s\n", aErrBuf );
+ else
+ SMprintf( "SmcOpenConnection succeeded, client ID is \"%s\"\n", pClientID );
+ aClientID = ByteString( pClientID );
+ free( pClientID );
+ pClientID = NULL;
+ ICEConnectionObserver::unlock();
+
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ if( pDisp->GetDrawable( pDisp->GetDefaultScreenNumber() ) && aClientID.Len() )
+ {
+ XChangeProperty( pDisp->GetDisplay(),
+ pDisp->GetDrawable( pDisp->GetDefaultScreenNumber() ),
+ XInternAtom( pDisp->GetDisplay(), "SM_CLIENT_ID", False ),
+ XA_STRING,
+ 8,
+ PropModeReplace,
+ (unsigned char*)aClientID.GetBuffer(),
+ aClientID.Len()
+ );
+ }
+ }
+ else if( ! aSmcConnection )
+ SMprintf( "no SESSION_MANAGER\n" );
+#endif
+}
+
+const ByteString& SessionManagerClient::getSessionID()
+{
+ return aClientID;
+}
+
+void SessionManagerClient::close()
+{
+ if( aSmcConnection )
+ {
+#ifdef USE_SM_EXTENSION
+ ICEConnectionObserver::lock();
+ SMprintf( "attempting SmcCloseConnection\n" );
+ SmcCloseConnection( aSmcConnection, 0, NULL );
+ SMprintf( "SmcConnection closed\n" );
+ ICEConnectionObserver::unlock();
+ ICEConnectionObserver::deactivate();
+#endif
+ aSmcConnection = NULL;
+ }
+}
+
+bool SessionManagerClient::queryInteraction()
+{
+ bool bRet = false;
+ if( aSmcConnection )
+ {
+ ICEConnectionObserver::lock();
+ if( SmcInteractRequest( aSmcConnection, SmDialogNormal, InteractProc, NULL ) )
+ bRet = true;
+ ICEConnectionObserver::unlock();
+ }
+ return bRet;
+}
+
+void SessionManagerClient::interactionDone( bool bCancelShutdown )
+{
+ if( aSmcConnection )
+ {
+ ICEConnectionObserver::lock();
+ SmcInteractDone( aSmcConnection, bCancelShutdown ? True : False );
+ ICEConnectionObserver::unlock();
+ }
+}
+
+
+String SessionManagerClient::getExecName()
+{
+ rtl::OUString aExec, aSysExec;
+ osl_getExecutableFile( &aExec.pData );
+ osl_getSystemPathFromFileURL( aExec.pData, &aSysExec.pData );
+
+ int nPos = aSysExec.indexOf( rtl::OUString::createFromAscii( ".bin" ) );
+ if( nPos != -1 )
+ aSysExec = aSysExec.copy( 0, nPos );
+ return aSysExec;
+}
+
+
+const ByteString& SessionManagerClient::getPreviousSessionID()
+{
+ static ByteString aPrevId;
+
+ int nCommands = osl_getCommandArgCount();
+ for( int i = 0; i < nCommands; i++ )
+ {
+ ::rtl::OUString aArg;
+ osl_getCommandArg( i, &aArg.pData );
+ if( aArg.compareToAscii( "-session=", 9 ) == 0 )
+ {
+ aPrevId = ByteString( ::rtl::OUStringToOString( aArg.copy( 9 ), osl_getThreadTextEncoding() ) );
+ break;
+ }
+ }
+ SMprintf( "previous ID = \"%s\"\n", aPrevId.GetBuffer() );
+ return aPrevId;
+}
+
+void ICEConnectionObserver::lock()
+{
+ osl_acquireMutex( ICEMutex );
+}
+
+void ICEConnectionObserver::unlock()
+{
+ osl_releaseMutex( ICEMutex );
+}
+
+void ICEConnectionObserver::activate()
+{
+ if( ! bIsWatching )
+ {
+ nWakeupFiles[0] = nWakeupFiles[1] = 0;
+ ICEMutex = osl_createMutex();
+ bIsWatching = TRUE;
+#ifdef USE_SM_EXTENSION
+ /*
+ * Default handlers call exit, we don't care that strongly if something
+ * happens to fail
+ */
+ origIOErrorHandler = IceSetIOErrorHandler( IgnoreIceIOErrors );
+ origErrorHandler = IceSetErrorHandler( IgnoreIceErrors );
+ IceAddConnectionWatch( ICEWatchProc, NULL );
+#endif
+ }
+}
+
+void ICEConnectionObserver::deactivate()
+{
+ if( bIsWatching )
+ {
+ lock();
+ bIsWatching = FALSE;
+#ifdef USE_SM_EXTENSION
+ IceRemoveConnectionWatch( ICEWatchProc, NULL );
+ IceSetErrorHandler( origErrorHandler );
+ IceSetIOErrorHandler( origIOErrorHandler );
+#endif
+ nConnections = 0;
+ if( ICEThread )
+ {
+ osl_terminateThread( ICEThread );
+ wakeup();
+ }
+ unlock();
+ if( ICEThread )
+ {
+ osl_joinWithThread( ICEThread );
+ osl_destroyThread( ICEThread );
+ close( nWakeupFiles[1] );
+ close( nWakeupFiles[0] );
+ ICEThread = NULL;
+ }
+ osl_destroyMutex( ICEMutex );
+ ICEMutex = NULL;
+ }
+}
+
+void ICEConnectionObserver::wakeup()
+{
+ char cChar = 'w';
+ write( nWakeupFiles[1], &cChar, 1 );
+}
+
+void ICEConnectionWorker( void* )
+{
+#ifdef USE_SM_EXTENSION
+ while( osl_scheduleThread(ICEConnectionObserver::ICEThread) && ICEConnectionObserver::nConnections )
+ {
+ ICEConnectionObserver::lock();
+ int nConnectionsBefore = ICEConnectionObserver::nConnections;
+ int nBytes = sizeof( struct pollfd )*(nConnectionsBefore+1);
+ struct pollfd* pLocalFD = (struct pollfd*)rtl_allocateMemory( nBytes );
+ rtl_copyMemory( pLocalFD, ICEConnectionObserver::pFilehandles, nBytes );
+ ICEConnectionObserver::unlock();
+
+ int nRet = poll( pLocalFD,nConnectionsBefore+1,-1 );
+ bool bWakeup = (pLocalFD[0].revents & POLLIN);
+ rtl_freeMemory( pLocalFD );
+
+ if( nRet < 1 )
+ continue;
+
+ // clear wakeup pipe
+ if( bWakeup )
+ {
+ char buf[4];
+ while( read( ICEConnectionObserver::nWakeupFiles[0], buf, sizeof( buf ) ) > 0 )
+ ;
+ SMprintf( "file handles active in wakeup: %d\n", nRet );
+ if( nRet == 1 )
+ continue;
+ }
+
+ // check fd's after we obtained the lock
+ ICEConnectionObserver::lock();
+ if( ICEConnectionObserver::nConnections > 0 && ICEConnectionObserver::nConnections == nConnectionsBefore )
+ {
+ nRet = poll( ICEConnectionObserver::pFilehandles+1, ICEConnectionObserver::nConnections, 0 );
+ if( nRet > 0 )
+ {
+ SMprintf( "IceProcessMessages\n" );
+ Bool bReply;
+ for( int i = 0; i < ICEConnectionObserver::nConnections; i++ )
+ if( ICEConnectionObserver::pFilehandles[i+1].revents & POLLIN )
+ IceProcessMessages( ICEConnectionObserver::pConnections[i], NULL, &bReply );
+ }
+ }
+ ICEConnectionObserver::unlock();
+ }
+#endif
+ SMprintf( "shutting donw ICE dispatch thread\n" );
+}
+
+void ICEConnectionObserver::ICEWatchProc(
+ IceConn connection,
+ IcePointer,
+ Bool opening,
+ IcePointer*
+ )
+{
+ // note: this is a callback function for ICE
+ // this implicitly means that a call into ICE lib is calling this
+ // so the ICEMutex MUST already be locked by the caller
+
+#ifdef USE_SM_EXTENSION
+ if( opening )
+ {
+ int fd = IceConnectionNumber( connection );
+ nConnections++;
+ pConnections = (IceConn*)rtl_reallocateMemory( pConnections, sizeof( IceConn )*nConnections );
+ pFilehandles = (struct pollfd*)rtl_reallocateMemory( pFilehandles, sizeof( struct pollfd )*(nConnections+1) );
+ pConnections[ nConnections-1 ] = connection;
+ pFilehandles[ nConnections ].fd = fd;
+ pFilehandles[ nConnections ].events = POLLIN;
+ if( nConnections == 1 )
+ {
+ if( ! pipe( nWakeupFiles ) )
+ {
+ int flags;
+ pFilehandles[0].fd = nWakeupFiles[0];
+ pFilehandles[0].events = POLLIN;
+ // set close-on-exec and nonblock descriptor flag.
+ if ((flags = fcntl (nWakeupFiles[0], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (nWakeupFiles[0], F_SETFD, flags);
+ }
+ if ((flags = fcntl (nWakeupFiles[0], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (nWakeupFiles[0], F_SETFL, flags);
+ }
+ // set close-on-exec and nonblock descriptor flag.
+ if ((flags = fcntl (nWakeupFiles[1], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (nWakeupFiles[1], F_SETFD, flags);
+ }
+ if ((flags = fcntl (nWakeupFiles[1], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (nWakeupFiles[1], F_SETFL, flags);
+ }
+ ICEThread = osl_createSuspendedThread( ICEConnectionWorker, NULL );
+ osl_resumeThread( ICEThread );
+ }
+ }
+ }
+ else
+ {
+ for( int i = 0; i < nConnections; i++ )
+ {
+ if( pConnections[i] == connection )
+ {
+ if( i < nConnections-1 )
+ {
+ rtl_moveMemory( pConnections+i, pConnections+i+1, sizeof( IceConn )*(nConnections-i-1) );
+ rtl_moveMemory( pFilehandles+i+1, pFilehandles+i+2, sizeof( struct pollfd )*(nConnections-i-1) );
+ }
+ nConnections--;
+ pConnections = (IceConn*)rtl_reallocateMemory( pConnections, sizeof( IceConn )*nConnections );
+ pFilehandles = (struct pollfd*)rtl_reallocateMemory( pFilehandles, sizeof( struct pollfd )*(nConnections+1) );
+ break;
+ }
+ }
+ if( nConnections == 0 && ICEThread )
+ {
+ SMprintf( "terminating ICEThread\n" );
+ osl_terminateThread( ICEThread );
+ wakeup();
+ // must release the mutex here
+ osl_releaseMutex( ICEMutex );
+ osl_joinWithThread( ICEThread );
+ osl_destroyThread( ICEThread );
+ close( nWakeupFiles[1] );
+ close( nWakeupFiles[0] );
+ ICEThread = NULL;
+ }
+ }
+ SMprintf( "ICE connection on %d %s\n",
+ IceConnectionNumber( connection ),
+ opening ? "inserted" : "removed" );
+ SMprintf( "Display connection is %d\n", ConnectionNumber( GetX11SalData()->GetDisplay()->GetDisplay() ) );
+#endif
+}
diff --git a/vcl/unx/generic/app/soicon.cxx b/vcl/unx/generic/app/soicon.cxx
new file mode 100644
index 000000000000..663dc9371caf
--- /dev/null
+++ b/vcl/unx/generic/app/soicon.cxx
@@ -0,0 +1,116 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <unx/salunx.h>
+#include <unx/saldisp.hxx>
+#include <unx/salbmp.h>
+#include <unx/soicon.hxx>
+
+#include <vcl/salbtype.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/graph.hxx>
+
+#include <svdata.hxx>
+#include <svids.hrc>
+#include <salbmp.hxx>
+#include <impbmp.hxx>
+
+
+BOOL SelectAppIconPixmap( SalDisplay *pDisplay, int nScreen,USHORT nIcon, USHORT iconSize,
+ Pixmap& icon_pixmap, Pixmap& icon_mask)
+{
+ if( ! ImplGetResMgr() )
+ return FALSE;
+
+ USHORT nIconSizeOffset;
+
+ if( iconSize >= 48 )
+ nIconSizeOffset = SV_ICON_SIZE48_START;
+ else if( iconSize >= 32 )
+ nIconSizeOffset = SV_ICON_SIZE32_START;
+ else if( iconSize >= 16 )
+ nIconSizeOffset = SV_ICON_SIZE16_START;
+ else
+ return FALSE;
+
+ BitmapEx aIcon( ResId(nIconSizeOffset + nIcon, *ImplGetResMgr()));
+ if( TRUE == aIcon.IsEmpty() )
+ return FALSE;
+
+ SalTwoRect aRect;
+ aRect.mnSrcX = 0; aRect.mnSrcY = 0;
+ aRect.mnSrcWidth = iconSize; aRect.mnSrcHeight = iconSize;
+ aRect.mnDestX = 0; aRect.mnDestY = 0;
+ aRect.mnDestWidth = iconSize; aRect.mnDestHeight = iconSize;
+
+ X11SalBitmap *pBitmap = static_cast < X11SalBitmap * >
+ (aIcon.ImplGetBitmapImpBitmap()->ImplGetSalBitmap());
+
+ icon_pixmap = XCreatePixmap( pDisplay->GetDisplay(),
+ pDisplay->GetRootWindow( nScreen ),
+ iconSize, iconSize,
+ DefaultDepth( pDisplay->GetDisplay(), nScreen )
+ );
+
+ pBitmap->ImplDraw( icon_pixmap,
+ nScreen,
+ DefaultDepth( pDisplay->GetDisplay(), nScreen ),
+ aRect,
+ DefaultGC(pDisplay->GetDisplay(), nScreen ) );
+
+ icon_mask = None;
+
+ if( TRANSPARENT_BITMAP == aIcon.GetTransparentType() )
+ {
+ icon_mask = XCreatePixmap( pDisplay->GetDisplay(),
+ pDisplay->GetRootWindow( pDisplay->GetDefaultScreenNumber() ),
+ iconSize, iconSize, 1);
+
+ XGCValues aValues;
+ aValues.foreground = 0xffffffff;
+ aValues.background = 0;
+ aValues.function = GXcopy;
+ GC aMonoGC = XCreateGC( pDisplay->GetDisplay(), icon_mask,
+ GCFunction|GCForeground|GCBackground, &aValues );
+
+ Bitmap aMask = aIcon.GetMask();
+ aMask.Invert();
+
+ X11SalBitmap *pMask = static_cast < X11SalBitmap * >
+ (aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
+
+ pMask->ImplDraw(icon_mask, nScreen, 1, aRect, aMonoGC);
+ XFreeGC( pDisplay->GetDisplay(), aMonoGC );
+ }
+
+ return TRUE;
+}
+
diff --git a/vcl/unx/generic/app/wmadaptor.cxx b/vcl/unx/generic/app/wmadaptor.cxx
new file mode 100644
index 000000000000..90b2e5426bdf
--- /dev/null
+++ b/vcl/unx/generic/app/wmadaptor.cxx
@@ -0,0 +1,2548 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sal/alloca.h"
+#include "rtl/locale.h"
+
+#include "osl/thread.h"
+#include "osl/process.h"
+
+#include "vcl/configsettings.hxx"
+
+#include "unx/wmadaptor.hxx"
+#include "unx/saldisp.hxx"
+#include "unx/saldata.hxx"
+#include "unx/salframe.h"
+
+#include "salgdi.hxx"
+
+#include "tools/prex.h"
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xresource.h>
+#include "tools/postx.h"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+namespace vcl_sal {
+
+class NetWMAdaptor : public WMAdaptor
+{
+ void setNetWMState( X11SalFrame* pFrame ) const;
+ void initAtoms();
+ virtual bool isValid() const;
+public:
+ NetWMAdaptor( SalDisplay* );
+ virtual ~NetWMAdaptor();
+
+ virtual void setWMName( X11SalFrame* pFrame, const String& rWMName ) const;
+ virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const;
+ virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const;
+ virtual void setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pTransientFrame = NULL ) const;
+ virtual bool supportsICCCMPos() const;
+ virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const;
+ virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const;
+ virtual void showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const;
+ virtual void frameIsMapping( X11SalFrame* pFrame ) const;
+ virtual void setFrameStruts( X11SalFrame* pFrame,
+ int left, int right, int top, int bottom,
+ int left_start_y, int left_end_y,
+ int right_start_y, int right_end_y,
+ int top_start_x, int top_end_x,
+ int bottom_start_x, int bottom_end_x ) const;
+ virtual void setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const;
+};
+
+class GnomeWMAdaptor : public WMAdaptor
+{
+ bool m_bValid;
+
+ void setGnomeWMState( X11SalFrame* pFrame ) const;
+ void initAtoms();
+ virtual bool isValid() const;
+public:
+ GnomeWMAdaptor( SalDisplay * );
+ virtual ~GnomeWMAdaptor();
+
+ virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const;
+ virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const;
+ virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const;
+ virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const;
+};
+
+}
+
+using namespace vcl_sal;
+
+struct WMAdaptorProtocol
+{
+ const char* pProtocol;
+ int nProtocol;
+};
+
+
+/*
+ * table must be sorted ascending in strings
+ * since it is use with bsearch
+ */
+static const WMAdaptorProtocol aProtocolTab[] =
+{
+ { "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", WMAdaptor::KDE_NET_WM_WINDOW_TYPE_OVERRIDE },
+ { "_NET_CURRENT_DESKTOP", WMAdaptor::NET_CURRENT_DESKTOP },
+ { "_NET_NUMBER_OF_DESKTOPS", WMAdaptor::NET_NUMBER_OF_DESKTOPS },
+ { "_NET_WM_DESKTOP", WMAdaptor::NET_WM_DESKTOP },
+ { "_NET_WM_ICON_NAME", WMAdaptor::NET_WM_ICON_NAME },
+ { "_NET_WM_PING", WMAdaptor::NET_WM_PING },
+ { "_NET_WM_STATE", WMAdaptor::NET_WM_STATE },
+ { "_NET_WM_STATE_ABOVE", WMAdaptor::NET_WM_STATE_STAYS_ON_TOP },
+ { "_NET_WM_STATE_FULLSCREEN", WMAdaptor::NET_WM_STATE_FULLSCREEN },
+ { "_NET_WM_STATE_MAXIMIZED_HORIZ", WMAdaptor::NET_WM_STATE_MAXIMIZED_HORZ }, // common bug in e.g. older kwin and sawfish implementations
+ { "_NET_WM_STATE_MAXIMIZED_HORZ", WMAdaptor::NET_WM_STATE_MAXIMIZED_HORZ },
+ { "_NET_WM_STATE_MAXIMIZED_VERT", WMAdaptor::NET_WM_STATE_MAXIMIZED_VERT },
+ { "_NET_WM_STATE_MODAL", WMAdaptor::NET_WM_STATE_MODAL },
+ { "_NET_WM_STATE_SHADED", WMAdaptor::NET_WM_STATE_SHADED },
+ { "_NET_WM_STATE_SKIP_PAGER", WMAdaptor::NET_WM_STATE_SKIP_PAGER },
+ { "_NET_WM_STATE_SKIP_TASKBAR", WMAdaptor::NET_WM_STATE_SKIP_TASKBAR },
+ { "_NET_WM_STATE_STAYS_ON_TOP", WMAdaptor::NET_WM_STATE_STAYS_ON_TOP },
+ { "_NET_WM_STATE_STICKY", WMAdaptor::NET_WM_STATE_STICKY },
+ { "_NET_WM_STRUT", WMAdaptor::NET_WM_STRUT },
+ { "_NET_WM_STRUT_PARTIAL", WMAdaptor::NET_WM_STRUT_PARTIAL },
+ { "_NET_WM_WINDOW_TYPE", WMAdaptor::NET_WM_WINDOW_TYPE },
+ { "_NET_WM_WINDOW_TYPE_DESKTOP", WMAdaptor::NET_WM_WINDOW_TYPE_DESKTOP },
+ { "_NET_WM_WINDOW_TYPE_DIALOG", WMAdaptor::NET_WM_WINDOW_TYPE_DIALOG },
+ { "_NET_WM_WINDOW_TYPE_DOCK", WMAdaptor::NET_WM_WINDOW_TYPE_DOCK },
+ { "_NET_WM_WINDOW_TYPE_MENU", WMAdaptor::NET_WM_WINDOW_TYPE_MENU },
+ { "_NET_WM_WINDOW_TYPE_NORMAL", WMAdaptor::NET_WM_WINDOW_TYPE_NORMAL },
+ { "_NET_WM_WINDOW_TYPE_SPLASH", WMAdaptor::NET_WM_WINDOW_TYPE_SPLASH },
+ { "_NET_WM_WINDOW_TYPE_SPLASHSCREEN", WMAdaptor::NET_WM_WINDOW_TYPE_SPLASH }, // bug in Metacity 2.4.1
+ { "_NET_WM_WINDOW_TYPE_TOOLBAR", WMAdaptor::NET_WM_WINDOW_TYPE_TOOLBAR },
+ { "_NET_WM_WINDOW_TYPE_UTILITY", WMAdaptor::NET_WM_WINDOW_TYPE_UTILITY },
+ { "_NET_WORKAREA", WMAdaptor::NET_WORKAREA },
+ { "_WIN_APP_STATE", WMAdaptor::WIN_APP_STATE },
+ { "_WIN_CLIENT_LIST", WMAdaptor::WIN_CLIENT_LIST },
+ { "_WIN_EXPANDED_SIZE", WMAdaptor::WIN_EXPANDED_SIZE },
+ { "_WIN_HINTS", WMAdaptor::WIN_HINTS },
+ { "_WIN_ICONS", WMAdaptor::WIN_ICONS },
+ { "_WIN_LAYER", WMAdaptor::WIN_LAYER },
+ { "_WIN_STATE", WMAdaptor::WIN_STATE },
+ { "_WIN_WORKSPACE", WMAdaptor::WIN_WORKSPACE },
+ { "_WIN_WORKSPACE_COUNT", WMAdaptor::WIN_WORKSPACE_COUNT }
+};
+
+/*
+ * table containing atoms to get anyway
+ */
+
+static const WMAdaptorProtocol aAtomTab[] =
+{
+ { "WM_STATE", WMAdaptor::WM_STATE },
+ { "_MOTIF_WM_HINTS", WMAdaptor::MOTIF_WM_HINTS },
+ { "WM_PROTOCOLS", WMAdaptor::WM_PROTOCOLS },
+ { "WM_DELETE_WINDOW", WMAdaptor::WM_DELETE_WINDOW },
+ { "WM_TAKE_FOCUS", WMAdaptor::WM_TAKE_FOCUS },
+ { "WM_SAVE_YOURSELF", WMAdaptor::WM_SAVE_YOURSELF },
+ { "WM_COMMAND", WMAdaptor::WM_COMMAND },
+ { "WM_CLIENT_LEADER", WMAdaptor::WM_CLIENT_LEADER },
+ { "WM_LOCALE_NAME", WMAdaptor::WM_LOCALE_NAME },
+ { "WM_TRANSIENT_FOR", WMAdaptor::WM_TRANSIENT_FOR },
+ { "SAL_QUITEVENT", WMAdaptor::SAL_QUITEVENT },
+ { "SAL_USEREVENT", WMAdaptor::SAL_USEREVENT },
+ { "SAL_EXTTEXTEVENT", WMAdaptor::SAL_EXTTEXTEVENT },
+ { "SAL_GETTIMEEVENT", WMAdaptor::SAL_GETTIMEEVENT },
+ { "VCL_SYSTEM_SETTINGS", WMAdaptor::VCL_SYSTEM_SETTINGS },
+ { "DTWM_IS_RUNNING", WMAdaptor::DTWM_IS_RUNNING },
+ { "_XSETTINGS_SETTINGS", WMAdaptor::XSETTINGS },
+ { "_XEMBED", WMAdaptor::XEMBED },
+ { "_XEMBED_INFO", WMAdaptor::XEMBED_INFO },
+ { "_NET_WM_USER_TIME", WMAdaptor::NET_WM_USER_TIME },
+ { "_NET_WM_PID", WMAdaptor::NET_WM_PID }
+};
+
+extern "C" {
+static int compareProtocol( const void* pLeft, const void* pRight )
+{
+ return strcmp( ((const WMAdaptorProtocol*)pLeft)->pProtocol, ((const WMAdaptorProtocol*)pRight)->pProtocol );
+}
+}
+
+WMAdaptor* WMAdaptor::createWMAdaptor( SalDisplay* pSalDisplay )
+{
+ WMAdaptor* pAdaptor = NULL;
+
+ // try a NetWM
+ pAdaptor = new NetWMAdaptor( pSalDisplay );
+ if( ! pAdaptor->isValid() )
+ delete pAdaptor, pAdaptor = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "WM supports extended WM hints\n" );
+#endif
+
+ // try a GnomeWM
+ if( ! pAdaptor )
+ {
+ pAdaptor = new GnomeWMAdaptor( pSalDisplay );
+ if( ! pAdaptor->isValid() )
+ delete pAdaptor, pAdaptor = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "WM supports GNOME WM hints\n" );
+#endif
+ }
+
+ if( ! pAdaptor )
+ pAdaptor = new WMAdaptor( pSalDisplay );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Window Manager's name is \"%s\"\n",
+ ByteString( pAdaptor->getWindowManagerName(), RTL_TEXTENCODING_ISO_8859_1 ).GetBuffer() );
+#endif
+ return pAdaptor;
+}
+
+
+/*
+ * WMAdaptor constructor
+ */
+
+WMAdaptor::WMAdaptor( SalDisplay* pDisplay ) :
+ m_pSalDisplay( pDisplay ),
+ m_bTransientBehaviour( true ),
+ m_bEnableAlwaysOnTopWorks( false ),
+ m_bLegacyPartialFullscreen( false ),
+ m_nWinGravity( StaticGravity ),
+ m_nInitWinGravity( StaticGravity ),
+ m_bWMshouldSwitchWorkspace( true ),
+ m_bWMshouldSwitchWorkspaceInit( false )
+{
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+
+ // default desktops
+ m_nDesktops = 1;
+ m_aWMWorkAreas = ::std::vector< Rectangle >
+ ( 1, Rectangle( Point(), m_pSalDisplay->GetScreenSize( m_pSalDisplay->GetDefaultScreenNumber() ) ) );
+ m_bEqualWorkAreas = true;
+
+ memset( m_aWMAtoms, 0, sizeof( m_aWMAtoms ) );
+ m_pDisplay = m_pSalDisplay->GetDisplay();
+
+ initAtoms();
+ getNetWmName(); // try to discover e.g. Sawfish
+
+ // check for dtwm running
+ if( m_aWMAtoms[ DTWM_IS_RUNNING ] )
+ {
+ if ( (XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ DTWM_IS_RUNNING ],
+ 0, 1,
+ False,
+ XA_INTEGER,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty) == 0
+ && nItems)
+ || (XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ DTWM_IS_RUNNING ],
+ 0, 1,
+ False,
+ m_aWMAtoms[ DTWM_IS_RUNNING ],
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty) == 0
+ && nItems))
+ {
+ if (*pProperty)
+ {
+ m_aWMName = String(RTL_CONSTASCII_USTRINGPARAM("Dtwm"));
+ m_bTransientBehaviour = false;
+ m_nWinGravity = CenterGravity;
+ }
+ XFree (pProperty);
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ if( m_aWMName.Len() == 0 )
+ {
+ // check for window maker - needs different gravity
+ Atom aWMakerRunning = XInternAtom( m_pDisplay, "_WINDOWMAKER_WM_PROTOCOLS", True );
+ if( aWMakerRunning != None &&
+ XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ aWMakerRunning,
+ 0, 32,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0 )
+ {
+ if( aRealType == XA_ATOM )
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("Windowmaker" ) );
+ XFree( pProperty );
+ m_nInitWinGravity = NorthWestGravity;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ if( m_aWMName.Len() == 0 )
+ {
+ if( XInternAtom( m_pDisplay, "_OL_WIN_ATTR", True ) )
+ {
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM( "Olwm" ) );
+ m_nInitWinGravity = NorthWestGravity;
+ }
+ }
+ if( m_aWMName.Len() == 0 )
+ {
+ // check for ReflectionX wm (as it needs a workaround in Windows mode
+ Atom aRwmRunning = XInternAtom( m_pDisplay, "RWM_RUNNING", True );
+ if( aRwmRunning != None &&
+ XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ aRwmRunning,
+ 0, 32,
+ False,
+ aRwmRunning,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0 )
+ {
+ if( aRealType == aRwmRunning )
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("ReflectionX" ) );
+ XFree( pProperty );
+ }
+ else if( (aRwmRunning = XInternAtom( m_pDisplay, "_WRQ_WM_RUNNING", True )) != None &&
+ XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ aRwmRunning,
+ 0, 32,
+ False,
+ XA_STRING,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0 )
+ {
+ if( aRealType == XA_STRING )
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM( "ReflectionX Windows" ) );
+ XFree( pProperty );
+ }
+ }
+ if( m_aWMName.Len() == 0 )
+ {
+ Atom aTTAPlatform = XInternAtom( m_pDisplay, "TTA_CLIENT_PLATFORM", True );
+ if( aTTAPlatform != None &&
+ XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ aTTAPlatform,
+ 0, 32,
+ False,
+ XA_STRING,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0 )
+ {
+ if( aRealType == XA_STRING )
+ {
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("Tarantella" ) );
+ // #i62319# pretend that AlwaysOnTop works since
+ // the alwaysontop workaround in salframe.cxx results
+ // in a raise/lower loop on a Windows tarantella client
+ // FIXME: this property contains an identification string that
+ // in theory should be good enough to recognize running on a
+ // Windows client; however this string does not seem to be
+ // documented as well as the property itself.
+ m_bEnableAlwaysOnTopWorks = true;
+ }
+ XFree( pProperty );
+ }
+ }
+}
+
+/*
+ * WMAdaptor destructor
+ */
+
+WMAdaptor::~WMAdaptor()
+{
+}
+
+/*
+ * NetWMAdaptor constructor
+ */
+
+NetWMAdaptor::NetWMAdaptor( SalDisplay* pSalDisplay ) :
+ WMAdaptor( pSalDisplay )
+{
+ // currently all _NET WMs do transient like expected
+ m_bTransientBehaviour = true;
+
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ bool bNetWM = false;
+
+ initAtoms();
+
+ // check for NetWM
+ bNetWM = getNetWmName();
+ if( bNetWM
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_SUPPORTED ],
+ 0, 0,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_ATOM
+ && nFormat == 32
+ )
+ {
+ if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ // collect supported protocols
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_SUPPORTED ],
+ 0, nBytesLeft/4,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && nItems
+ )
+ {
+ Atom* pAtoms = (Atom*)pProperty;
+ char** pAtomNames = (char**)alloca( sizeof(char*)*nItems );
+ if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "supported protocols:\n" );
+#endif
+ for( unsigned int i = 0; i < nItems; i++ )
+ {
+ // #i80971# protect against invalid atoms
+ if( pAtomNames[i] == NULL )
+ continue;
+
+ int nProtocol = -1;
+ WMAdaptorProtocol aSearch;
+ aSearch.pProtocol = pAtomNames[i];
+ WMAdaptorProtocol* pMatch = (WMAdaptorProtocol*)
+ bsearch( &aSearch,
+ aProtocolTab,
+ sizeof( aProtocolTab )/sizeof( aProtocolTab[0] ),
+ sizeof( struct WMAdaptorProtocol ),
+ compareProtocol );
+ if( pMatch )
+ {
+ nProtocol = pMatch->nProtocol;
+ m_aWMAtoms[ nProtocol ] = pAtoms[ i ];
+ if( pMatch->nProtocol == NET_WM_STATE_STAYS_ON_TOP )
+ m_bEnableAlwaysOnTopWorks = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, " %s%s\n", pAtomNames[i], nProtocol != -1 ? "" : " (unsupported)" );
+#endif
+
+ XFree( pAtomNames[i] );
+ }
+ }
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+
+ // get number of desktops
+ if( m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ]
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ m_nDesktops = *(long*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ // get work areas
+ if( m_aWMAtoms[ NET_WORKAREA ]
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_WORKAREA ],
+ 0, 4*m_nDesktops,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty
+ ) == 0
+ && nItems == 4*(unsigned)m_nDesktops
+ )
+ {
+ m_aWMWorkAreas = ::std::vector< Rectangle > ( m_nDesktops );
+ long* pValues = (long*)pProperty;
+ for( int i = 0; i < m_nDesktops; i++ )
+ {
+ Point aPoint( pValues[4*i],
+ pValues[4*i+1] );
+ Size aSize( pValues[4*i+2],
+ pValues[4*i+3] );
+ Rectangle aWorkArea( aPoint, aSize );
+ m_aWMWorkAreas[i] = aWorkArea;
+ if( aWorkArea != m_aWMWorkAreas[0] )
+ m_bEqualWorkAreas = false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "workarea %d: %ldx%ld+%ld+%ld\n",
+ i,
+ m_aWMWorkAreas[i].GetWidth(),
+ m_aWMWorkAreas[i].GetHeight(),
+ m_aWMWorkAreas[i].Left(),
+ m_aWMWorkAreas[i].Top() );
+#endif
+ }
+ XFree( pProperty );
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%ld workareas for %d desktops !\n", nItems/4, m_nDesktops );
+#endif
+ if( pProperty )
+ {
+ XFree(pProperty);
+ pProperty = NULL;
+ }
+ }
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+}
+
+/*
+ * NetWMAdaptor destructor
+ */
+NetWMAdaptor::~NetWMAdaptor()
+{
+}
+
+/*
+ * GnomeWMAdaptor constructor
+ */
+
+GnomeWMAdaptor::GnomeWMAdaptor( SalDisplay* pSalDisplay ) :
+ WMAdaptor( pSalDisplay ),
+ m_bValid( false )
+{
+ // currently all Gnome WMs do transient like expected
+ m_bTransientBehaviour = true;
+
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+
+ initAtoms();
+
+ // check for GnomeWM
+ if( m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ WIN_PROTOCOLS ] )
+ {
+ XLIB_Window aWMChild = None;
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_CARDINAL
+ && nFormat == 32
+ && nItems != 0
+ )
+ {
+ aWMChild = *(XLIB_Window*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ XLIB_Window aCheckWindow = None;
+ m_pSalDisplay->GetXLib()->PushXErrorLevel( true );
+ if( XGetWindowProperty( m_pDisplay,
+ aWMChild,
+ m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_CARDINAL
+ && nFormat == 32
+ && nItems != 0
+ && ! m_pSalDisplay->GetXLib()->HasXErrorOccured()
+ )
+ {
+ aCheckWindow = *(XLIB_Window*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ if( aCheckWindow == aWMChild )
+ {
+ m_bValid = true;
+ /*
+ * get name of WM
+ * this is NOT part of the GNOME WM hints, but e.g. Sawfish
+ * already supports this part of the extended WM hints
+ */
+ m_aWMAtoms[ UTF8_STRING ] = XInternAtom( m_pDisplay, "UTF8_STRING", False );
+ getNetWmName();
+ }
+ }
+ m_pSalDisplay->GetXLib()->PopXErrorLevel();
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ if( m_bValid
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ WIN_PROTOCOLS ],
+ 0, 0,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_ATOM
+ && nFormat == 32
+ )
+ {
+ if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ // collect supported protocols
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ WIN_PROTOCOLS ],
+ 0, nBytesLeft/4,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ Atom* pAtoms = (Atom*)pProperty;
+ char** pAtomNames = (char**)alloca( sizeof(char*)*nItems );
+ if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "supported protocols:\n" );
+#endif
+ for( unsigned int i = 0; i < nItems; i++ )
+ {
+ // #i80971# protect against invalid atoms
+ if( pAtomNames[i] == NULL )
+ continue;
+
+ int nProtocol = -1;
+ WMAdaptorProtocol aSearch;
+ aSearch.pProtocol = pAtomNames[i];
+ WMAdaptorProtocol* pMatch = (WMAdaptorProtocol*)
+ bsearch( &aSearch,
+ aProtocolTab,
+ sizeof( aProtocolTab )/sizeof( aProtocolTab[0] ),
+ sizeof( struct WMAdaptorProtocol ),
+ compareProtocol );
+ if( pMatch )
+ {
+ nProtocol = pMatch->nProtocol;
+ m_aWMAtoms[ nProtocol ] = pAtoms[ i ];
+ if( pMatch->nProtocol == WIN_LAYER )
+ m_bEnableAlwaysOnTopWorks = true;
+ }
+ if( strncmp( "_ICEWM_TRAY", pAtomNames[i], 11 ) == 0 )
+ {
+ m_aWMName = String(RTL_CONSTASCII_USTRINGPARAM("IceWM" ));
+ m_nWinGravity = NorthWestGravity;
+ m_nInitWinGravity = NorthWestGravity;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, " %s%s\n", pAtomNames[i], nProtocol != -1 ? "" : " (unsupported)" );
+#endif
+
+ XFree( pAtomNames[i] );
+ }
+ }
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+
+ // get number of desktops
+ if( m_aWMAtoms[ WIN_WORKSPACE_COUNT ]
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ WIN_WORKSPACE_COUNT ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ m_nDesktops = *(long*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+}
+
+/*
+ * GnomeWMAdaptor destructor
+ */
+GnomeWMAdaptor::~GnomeWMAdaptor()
+{
+}
+
+/*
+ * getNetWmName()
+ */
+bool WMAdaptor::getNetWmName()
+{
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ bool bNetWM = false;
+
+ if( m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ NET_WM_NAME ] )
+ {
+ XLIB_Window aWMChild = None;
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ],
+ 0, 1,
+ False,
+ XA_WINDOW,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_WINDOW
+ && nFormat == 32
+ && nItems != 0
+ )
+ {
+ aWMChild = *(XLIB_Window*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ XLIB_Window aCheckWindow = None;
+ m_pSalDisplay->GetXLib()->PushXErrorLevel( true );
+ if( XGetWindowProperty( m_pDisplay,
+ aWMChild,
+ m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ],
+ 0, 1,
+ False,
+ XA_WINDOW,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_WINDOW
+ && nFormat == 32
+ && nItems != 0
+ && ! m_pSalDisplay->GetXLib()->HasXErrorOccured()
+ )
+ {
+ aCheckWindow = *(XLIB_Window*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ if( aCheckWindow == aWMChild )
+ {
+ bNetWM = true;
+ // get name of WM
+ m_aWMAtoms[ UTF8_STRING ] = XInternAtom( m_pDisplay, "UTF8_STRING", False );
+ if( XGetWindowProperty( m_pDisplay,
+ aWMChild,
+ m_aWMAtoms[ NET_WM_NAME ],
+ 0, 256,
+ False,
+ AnyPropertyType, /* m_aWMAtoms[ UTF8_STRING ],*/
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && nItems != 0
+ )
+ {
+ if (aRealType == m_aWMAtoms[ UTF8_STRING ])
+ {
+ m_aWMName = String( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_UTF8 );
+ }
+ else
+ if (aRealType == XA_STRING)
+ {
+ m_aWMName = String( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ // if this is metacity, check for version to enable a legacy workaround
+ if( m_aWMName.EqualsAscii( "Metacity" ) )
+ {
+ int nVersionMajor = 0, nVersionMinor = 0;
+ Atom nVersionAtom = XInternAtom( m_pDisplay, "_METACITY_VERSION", True );
+ if( nVersionAtom )
+ {
+ if( XGetWindowProperty( m_pDisplay,
+ aWMChild,
+ nVersionAtom,
+ 0, 256,
+ False,
+ m_aWMAtoms[ UTF8_STRING ],
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && nItems != 0
+ )
+ {
+ String aMetaVersion( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_UTF8 );
+ nVersionMajor = aMetaVersion.GetToken( 0, '.' ).ToInt32();
+ nVersionMinor = aMetaVersion.GetToken( 1, '.' ).ToInt32();
+ }
+ if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ if( nVersionMajor < 2 || (nVersionMajor == 2 && nVersionMinor < 12) )
+ m_bLegacyPartialFullscreen = true;
+ }
+ }
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ m_pSalDisplay->GetXLib()->PopXErrorLevel();
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ return bNetWM;
+}
+
+bool WMAdaptor::getWMshouldSwitchWorkspace() const
+{
+ if( ! m_bWMshouldSwitchWorkspaceInit )
+ {
+ WMAdaptor * pWMA = const_cast<WMAdaptor*>(this);
+
+ pWMA->m_bWMshouldSwitchWorkspace = true;
+ vcl::SettingsConfigItem* pItem = vcl::SettingsConfigItem::get();
+ rtl::OUString aSetting( pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "WM" ) ),
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ShouldSwitchWorkspace" ) ) ) );
+ if( aSetting.getLength() == 0 )
+ {
+ if( m_aWMName.EqualsAscii( "awesome" ) )
+ {
+ pWMA->m_bWMshouldSwitchWorkspace = false;
+ }
+ }
+ else
+ pWMA->m_bWMshouldSwitchWorkspace = aSetting.toBoolean();
+ pWMA->m_bWMshouldSwitchWorkspaceInit = true;
+ }
+ return m_bWMshouldSwitchWorkspace;
+}
+
+/*
+ * WMAdaptor::isValid()
+ */
+bool WMAdaptor::isValid() const
+{
+ return true;
+}
+
+/*
+ * NetWMAdaptor::isValid()
+ */
+bool NetWMAdaptor::isValid() const
+{
+ // some necessary sanity checks; there are WMs out there
+ // which implement some of the WM hints spec without
+ // real functionality
+ return
+ m_aWMAtoms[ NET_SUPPORTED ]
+ && m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ]
+ && m_aWMAtoms[ NET_WM_NAME ]
+ && m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ]
+ && m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ]
+ ;
+}
+
+/*
+ * GnomeWMAdaptor::isValid()
+ */
+bool GnomeWMAdaptor::isValid() const
+{
+ return m_bValid;
+}
+
+/*
+ * WMAdaptor::initAtoms
+ */
+
+void WMAdaptor::initAtoms()
+{
+ // get basic atoms
+ for( unsigned int i = 0; i < sizeof( aAtomTab )/sizeof( aAtomTab[0] ); i++ )
+ m_aWMAtoms[ aAtomTab[i].nProtocol ] = XInternAtom( m_pDisplay, aAtomTab[i].pProtocol, False );
+ m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] = XInternAtom( m_pDisplay, "_NET_SUPPORTING_WM_CHECK", True );
+ m_aWMAtoms[ NET_WM_NAME ] = XInternAtom( m_pDisplay, "_NET_WM_NAME", True );
+}
+
+/*
+ * NetWMAdaptor::initAtoms
+ */
+
+void NetWMAdaptor::initAtoms()
+{
+ WMAdaptor::initAtoms();
+
+ m_aWMAtoms[ NET_SUPPORTED ] = XInternAtom( m_pDisplay, "_NET_SUPPORTED", True );
+}
+
+/*
+ * GnomeWMAdaptor::initAtoms
+ */
+
+void GnomeWMAdaptor::initAtoms()
+{
+ WMAdaptor::initAtoms();
+
+ m_aWMAtoms[ WIN_PROTOCOLS ] = XInternAtom( m_pDisplay, "_WIN_PROTOCOLS", True );
+ m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] = XInternAtom( m_pDisplay, "_WIN_SUPPORTING_WM_CHECK", True );
+}
+
+/*
+ * WMAdaptor::setWMName
+ * sets WM_NAME
+ * WM_ICON_NAME
+ */
+
+void WMAdaptor::setWMName( X11SalFrame* pFrame, const String& rWMName ) const
+{
+ ByteString aTitle( rWMName, osl_getThreadTextEncoding() );
+
+ if( ! rWMName.Len() && m_aWMName.EqualsAscii( "Dtwm" ) )
+ aTitle = " ";
+
+ ::rtl::OString aWMLocale;
+ rtl_Locale* pLocale = NULL;
+ osl_getProcessLocale( &pLocale );
+ if( pLocale )
+ {
+ ::rtl::OUString aLocaleString( pLocale->Language );
+ ::rtl::OUString aCountry( pLocale->Country );
+ ::rtl::OUString aVariant( pLocale->Variant );
+
+ if( aCountry.getLength() )
+ {
+ aLocaleString += ::rtl::OUString::createFromAscii( "_" );
+ aLocaleString += aCountry;
+ }
+ if( aVariant.getLength() )
+ aLocaleString += aVariant;
+ aWMLocale = ::rtl::OUStringToOString( aLocaleString, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ else
+ {
+ static const char* pLang = getenv( "LANG" );
+ aWMLocale = pLang ? pLang : "C";
+ }
+
+ static bool bTrustXmb = true;
+ #ifdef SOLARIS
+ /* #i64273# there are some weird cases when using IIIMP on Solaris
+ * where for unknown reasons XmbTextListToTextProperty results in
+ * garbage. Test one string once to ensure safety.
+ *
+ * FIXME: This must be a bug in xiiimp.so.2 somewhere. However
+ * it was not possible to recreate this in a small sample program.
+ * This reeks of memory corruption somehow.
+ */
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+ XTextProperty aTestProp = { NULL, None, 0, 0 };
+ const char *pText = "trustme";
+ XmbTextListToTextProperty( m_pDisplay,
+ &const_cast<char*>(pText),
+ 1,
+ XStdICCTextStyle,
+ &aTestProp );
+ bTrustXmb = (aTestProp.nitems == 7) &&
+ (aTestProp.value != NULL ) &&
+ (strncmp( (char*)aTestProp.value, pText, 7 ) == 0) &&
+ (aTestProp.encoding == XA_STRING);
+ if( aTestProp.value )
+ XFree( aTestProp.value );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s\n",
+ bTrustXmb ?
+ "XmbTextListToTextProperty seems to work" :
+ "XmbTextListToTextProperty does not seem to work" );
+ #endif
+ }
+ #endif
+
+ char* pT = const_cast<char*>(aTitle.GetBuffer());
+ XTextProperty aProp = { NULL, None, 0, 0 };
+ if( bTrustXmb )
+ {
+ XmbTextListToTextProperty( m_pDisplay,
+ &pT,
+ 1,
+ XStdICCTextStyle,
+ &aProp );
+ }
+
+ unsigned char* pData = aProp.nitems ? aProp.value : (unsigned char*)aTitle.GetBuffer();
+ Atom nType = aProp.nitems ? aProp.encoding : XA_STRING;
+ int nFormat = aProp.nitems ? aProp.format : 8;
+ int nBytes = aProp.nitems ? aProp.nitems : aTitle.Len();
+ const SystemEnvData* pEnv = pFrame->GetSystemData();
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ XA_WM_NAME,
+ nType,
+ nFormat,
+ PropModeReplace,
+ pData,
+ nBytes );
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ XA_WM_ICON_NAME,
+ nType,
+ nFormat,
+ PropModeReplace,
+ pData,
+ nBytes );
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ m_aWMAtoms[ WM_LOCALE_NAME ],
+ XA_STRING,
+ 8,
+ PropModeReplace,
+ (unsigned char*)aWMLocale.getStr(),
+ aWMLocale.getLength() );
+ if (aProp.value != NULL)
+ XFree( aProp.value );
+}
+
+/*
+ * NetWMAdaptor::setWMName
+ * sets WM_NAME
+ * _NET_WM_NAME
+ * WM_ICON_NAME
+ * _NET_WM_ICON_NAME
+ */
+void NetWMAdaptor::setWMName( X11SalFrame* pFrame, const String& rWMName ) const
+{
+ WMAdaptor::setWMName( pFrame, rWMName );
+
+ ByteString aTitle( rWMName, RTL_TEXTENCODING_UTF8 );
+ const SystemEnvData* pEnv = pFrame->GetSystemData();
+ if( m_aWMAtoms[ NET_WM_NAME ] )
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ m_aWMAtoms[ NET_WM_NAME ],
+ m_aWMAtoms[ UTF8_STRING ],
+ 8,
+ PropModeReplace,
+ (unsigned char*)aTitle.GetBuffer(),
+ aTitle.Len()+1 );
+ if( m_aWMAtoms[ NET_WM_ICON_NAME ] )
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ m_aWMAtoms[ NET_WM_ICON_NAME ],
+ m_aWMAtoms[ UTF8_STRING ],
+ 8,
+ PropModeReplace,
+ (unsigned char*)aTitle.GetBuffer(),
+ aTitle.Len()+1 );
+ // The +1 copies the terminating null byte. Although
+ // the spec says, this should not be necessary
+ // at least the kwin implementation seems to depend
+ // on the null byte
+}
+
+/*
+ * NetWMAdaptor::setNetWMState
+ * sets _NET_WM_STATE
+ */
+void NetWMAdaptor::setNetWMState( X11SalFrame* pFrame ) const
+{
+ if( m_aWMAtoms[ NET_WM_STATE ] )
+ {
+ Atom aStateAtoms[ 10 ];
+ int nStateAtoms = 0;
+
+ // set NET_WM_STATE_MODAL
+ if( m_aWMAtoms[ NET_WM_STATE_MODAL ]
+ && pFrame->meWindowType == windowType_ModalDialogue )
+ {
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MODAL ];
+ /*
+ * #90998# NET_WM_STATE_SKIP_TASKBAR set on a frame will
+ * cause kwin not to give it the focus on map request
+ * this seems to be a bug in kwin
+ * aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ];
+ */
+ }
+ if( pFrame->mbMaximizedVert
+ && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ];
+ if( pFrame->mbMaximizedHorz
+ && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ];
+ if( pFrame->bAlwaysOnTop_ && m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ];
+ if( pFrame->mbShaded && m_aWMAtoms[ NET_WM_STATE_SHADED ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SHADED ];
+ if( pFrame->mbFullScreen && m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ];
+ if( pFrame->meWindowType == windowType_Utility && m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ];
+
+ if( nStateAtoms )
+ {
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ NET_WM_STATE ],
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char*)aStateAtoms,
+ nStateAtoms
+ );
+ }
+ else
+ XDeleteProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ NET_WM_STATE ] );
+ if( pFrame->mbMaximizedHorz
+ && pFrame->mbMaximizedVert
+ && ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) )
+ {
+ /*
+ * for maximizing use NorthWestGravity (including decoration)
+ */
+ XSizeHints hints;
+ long supplied;
+ bool bHint = false;
+ if( XGetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints,
+ &supplied ) )
+ {
+ bHint = true;
+ hints.flags |= PWinGravity;
+ hints.win_gravity = NorthWestGravity;
+ XSetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints );
+ XSync( m_pDisplay, False );
+ }
+
+ // SetPosSize necessary to set width/height, min/max w/h
+ sal_Int32 nCurrent = 0;
+ /*
+ * get current desktop here if work areas have different size
+ * (does this happen on any platform ?)
+ */
+ if( ! m_bEqualWorkAreas )
+ {
+ nCurrent = getCurrentWorkArea();
+ if( nCurrent < 0 )
+ nCurrent = 0;
+ }
+ Rectangle aPosSize = m_aWMWorkAreas[nCurrent];
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ aPosSize = Rectangle( Point( aPosSize.Left() + rGeom.nLeftDecoration,
+ aPosSize.Top() + rGeom.nTopDecoration ),
+ Size( aPosSize.GetWidth()
+ - rGeom.nLeftDecoration
+ - rGeom.nRightDecoration,
+ aPosSize.GetHeight()
+ - rGeom.nTopDecoration
+ - rGeom.nBottomDecoration )
+ );
+ pFrame->SetPosSize( aPosSize );
+
+ /*
+ * reset gravity hint to static gravity
+ * (this should not move window according to ICCCM)
+ */
+ if( bHint && pFrame->nShowState_ != SHOWSTATE_UNKNOWN )
+ {
+ hints.win_gravity = StaticGravity;
+ XSetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints );
+ }
+ }
+ }
+}
+
+/*
+ * GnomeWMAdaptor::setNetWMState
+ * sets _WIN_STATE
+ */
+void GnomeWMAdaptor::setGnomeWMState( X11SalFrame* pFrame ) const
+{
+ if( m_aWMAtoms[ WIN_STATE ] )
+ {
+ sal_uInt32 nWinWMState = 0;
+
+ if( pFrame->mbMaximizedVert )
+ nWinWMState |= 1 << 2;
+ if( pFrame->mbMaximizedHorz )
+ nWinWMState |= 1 << 3;
+ if( pFrame->mbShaded )
+ nWinWMState |= 1 << 5;
+
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ WIN_STATE ],
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&nWinWMState,
+ 1
+ );
+ if( pFrame->mbMaximizedHorz
+ && pFrame->mbMaximizedVert
+ && ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) )
+ {
+ /*
+ * for maximizing use NorthWestGravity (including decoration)
+ */
+ XSizeHints hints;
+ long supplied;
+ bool bHint = false;
+ if( XGetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints,
+ &supplied ) )
+ {
+ bHint = true;
+ hints.flags |= PWinGravity;
+ hints.win_gravity = NorthWestGravity;
+ XSetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints );
+ XSync( m_pDisplay, False );
+ }
+
+ // SetPosSize necessary to set width/height, min/max w/h
+ sal_Int32 nCurrent = 0;
+ /*
+ * get current desktop here if work areas have different size
+ * (does this happen on any platform ?)
+ */
+ if( ! m_bEqualWorkAreas )
+ {
+ nCurrent = getCurrentWorkArea();
+ if( nCurrent < 0 )
+ nCurrent = 0;
+ }
+ Rectangle aPosSize = m_aWMWorkAreas[nCurrent];
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ aPosSize = Rectangle( Point( aPosSize.Left() + rGeom.nLeftDecoration,
+ aPosSize.Top() + rGeom.nTopDecoration ),
+ Size( aPosSize.GetWidth()
+ - rGeom.nLeftDecoration
+ - rGeom.nRightDecoration,
+ aPosSize.GetHeight()
+ - rGeom.nTopDecoration
+ - rGeom.nBottomDecoration )
+ );
+ pFrame->SetPosSize( aPosSize );
+
+ /*
+ * reset gravity hint to static gravity
+ * (this should not move window according to ICCCM)
+ */
+ if( bHint && pFrame->nShowState_ != SHOWSTATE_UNKNOWN )
+ {
+ hints.win_gravity = StaticGravity;
+ XSetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints );
+ }
+ }
+ }
+}
+
+/*
+ * WMAdaptor::setFrameDecoration
+ * sets _MOTIF_WM_HINTS
+ * WM_TRANSIENT_FOR
+ */
+
+void WMAdaptor::setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pReferenceFrame ) const
+{
+ pFrame->meWindowType = eType;
+ pFrame->mnDecorationFlags = nDecorationFlags;
+
+ if( ! pFrame->mbFullScreen )
+ {
+ // set mwm hints
+ struct _mwmhints {
+ unsigned long flags, func, deco;
+ long input_mode;
+ unsigned long status;
+ } aHint;
+
+ aHint.flags = 15; /* flags for functions, decoration, input mode and status */
+ aHint.deco = 0;
+ aHint.func = 1L << 2;
+ aHint.status = 0;
+ aHint.input_mode = 0;
+
+ // evaluate decoration flags
+ if( nDecorationFlags & decoration_All )
+ aHint.deco = 1, aHint.func = 1;
+ else
+ {
+ if( nDecorationFlags & decoration_Title )
+ aHint.deco |= 1L << 3;
+ if( nDecorationFlags & decoration_Border )
+ aHint.deco |= 1L << 1;
+ if( nDecorationFlags & decoration_Resize )
+ aHint.deco |= 1L << 2, aHint.func |= 1L << 1;
+ if( nDecorationFlags & decoration_MinimizeBtn )
+ aHint.deco |= 1L << 5, aHint.func |= 1L << 3;
+ if( nDecorationFlags & decoration_MaximizeBtn )
+ aHint.deco |= 1L << 6, aHint.func |= 1L << 4;
+ if( nDecorationFlags & decoration_CloseBtn )
+ aHint.deco |= 1L << 4, aHint.func |= 1L << 5;
+ }
+ // evaluate window type
+ switch( eType )
+ {
+ case windowType_ModalDialogue:
+ aHint.input_mode = 1;
+ break;
+ default:
+ break;
+ }
+
+ // set the hint
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ MOTIF_WM_HINTS ],
+ m_aWMAtoms[ MOTIF_WM_HINTS ],
+ 32,
+ PropModeReplace,
+ (unsigned char*)&aHint,
+ 5 );
+ }
+
+ // set transientFor hint
+ /* #91030# dtwm will not map a dialogue if the transient
+ * window is iconified. This is deemed undesireable because
+ * message boxes do not get mapped, so use the root as transient
+ * instead.
+ */
+ if( pReferenceFrame )
+ {
+ XSetTransientForHint( m_pDisplay,
+ pFrame->GetShellWindow(),
+ pReferenceFrame->bMapped_ ?
+ pReferenceFrame->GetShellWindow() :
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() )
+ );
+ if( ! pReferenceFrame->bMapped_ )
+ pFrame->mbTransientForRoot = true;
+ }
+ // #110333# in case no one ever sets a title prevent
+ // the Dtwm taking the class instead
+ if( m_aWMName.EqualsAscii( "Dtwm" ) )
+ setWMName( pFrame, String() );
+}
+
+/*
+ * NetWMAdaptor::setFrameDecoration
+ * sets _MOTIF_WM_HINTS
+ * _NET_WM_WINDOW_TYPE
+ * _NET_WM_STATE
+ * WM_TRANSIENT_FOR
+ */
+
+void NetWMAdaptor::setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pReferenceFrame ) const
+{
+ WMAdaptor::setFrameTypeAndDecoration( pFrame, eType, nDecorationFlags, pReferenceFrame );
+
+ setNetWMState( pFrame );
+
+ // set NET_WM_WINDOW_TYPE
+ if( m_aWMAtoms[ NET_WM_WINDOW_TYPE ] )
+ {
+ Atom aWindowTypes[4];
+ int nWindowTypes = 0;
+ switch( eType )
+ {
+ case windowType_Utility:
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_UTILITY ] ?
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_UTILITY ] :
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ];
+ break;
+ case windowType_ModelessDialogue:
+ case windowType_ModalDialogue:
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ];
+ break;
+ case windowType_Splash:
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] ?
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] :
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ];
+ break;
+ case windowType_Toolbar:
+ if( m_aWMAtoms[ KDE_NET_WM_WINDOW_TYPE_OVERRIDE ] )
+ aWindowTypes[nWindowTypes++] = m_aWMAtoms[ KDE_NET_WM_WINDOW_TYPE_OVERRIDE ];
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] ?
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] :
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL];
+ break;
+ case windowType_Dock:
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_DOCK ] ?
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_DOCK ] :
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL];
+ break;
+ default:
+ aWindowTypes[nWindowTypes++] = m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ];
+ break;
+ }
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE ],
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char*)aWindowTypes,
+ nWindowTypes );
+ }
+ if( ( eType == windowType_ModalDialogue ||
+ eType == windowType_ModelessDialogue )
+ && ! pReferenceFrame )
+ {
+ XSetTransientForHint( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ) );
+ pFrame->mbTransientForRoot = true;
+ }
+}
+
+/*
+ * WMAdaptor::maximizeFrame
+ */
+
+void WMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
+{
+ pFrame->mbMaximizedVert = bVertical;
+ pFrame->mbMaximizedHorz = bHorizontal;
+
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+
+ // discard pending configure notifies for this frame
+ XSync( m_pDisplay, False );
+ XEvent aDiscard;
+ while( XCheckTypedWindowEvent( m_pDisplay,
+ pFrame->GetShellWindow(),
+ ConfigureNotify,
+ &aDiscard ) )
+ ;
+ while( XCheckTypedWindowEvent( m_pDisplay,
+ pFrame->GetWindow(),
+ ConfigureNotify,
+ &aDiscard ) )
+ ;
+
+ if( bHorizontal || bVertical )
+ {
+ Size aScreenSize( m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() ) );
+ Point aTL( rGeom.nLeftDecoration, rGeom.nTopDecoration );
+ if( m_pSalDisplay->IsXinerama() )
+ {
+ Point aMed( aTL.X() + rGeom.nWidth/2, aTL.Y() + rGeom.nHeight/2 );
+ const std::vector< Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens();
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ if( rScreens[i].IsInside( aMed ) )
+ {
+ aTL += rScreens[i].TopLeft();
+ aScreenSize = rScreens[i].GetSize();
+ break;
+ }
+ }
+ Rectangle aTarget( aTL,
+ Size( aScreenSize.Width() - rGeom.nLeftDecoration - rGeom.nTopDecoration,
+ aScreenSize.Height() - rGeom.nTopDecoration - rGeom.nBottomDecoration )
+ );
+ if( ! bHorizontal )
+ {
+ aTarget.SetSize(
+ Size(
+ pFrame->maRestorePosSize.IsEmpty() ?
+ rGeom.nWidth : pFrame->maRestorePosSize.GetWidth(),
+ aTarget.GetHeight()
+ )
+ );
+ aTarget.Left() =
+ pFrame->maRestorePosSize.IsEmpty() ?
+ rGeom.nX : pFrame->maRestorePosSize.Left();
+ }
+ else if( ! bVertical )
+ {
+ aTarget.SetSize(
+ Size(
+ aTarget.GetWidth(),
+ pFrame->maRestorePosSize.IsEmpty() ?
+ rGeom.nHeight : pFrame->maRestorePosSize.GetHeight()
+ )
+ );
+ aTarget.Top() =
+ pFrame->maRestorePosSize.IsEmpty() ?
+ rGeom.nY : pFrame->maRestorePosSize.Top();
+ }
+
+ Rectangle aRestore( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
+ if( pFrame->bMapped_ )
+ {
+ XSetInputFocus( m_pDisplay,
+ pFrame->GetShellWindow(),
+ RevertToNone,
+ CurrentTime
+ );
+ if( m_aWMName.EqualsAscii( "Dtwm" ) )
+ {
+ /*
+ * Dtwm will only position correctly with center gravity
+ * and in this case the request actually changes the frame
+ * not the shell window
+ */
+ aTarget = Rectangle( Point( 0, 0 ), aScreenSize );
+ aRestore.Move( -rGeom.nLeftDecoration, -rGeom.nTopDecoration );
+ }
+ }
+
+ if( pFrame->maRestorePosSize.IsEmpty() )
+ pFrame->maRestorePosSize = aRestore;
+
+ pFrame->SetPosSize( aTarget );
+ pFrame->nWidth_ = aTarget.GetWidth();
+ pFrame->nHeight_ = aTarget.GetHeight();
+ XRaiseWindow( m_pDisplay,
+ pFrame->GetShellWindow()
+ );
+ if( pFrame->GetStackingWindow() )
+ XRaiseWindow( m_pDisplay,
+ pFrame->GetStackingWindow()
+ );
+
+ }
+ else
+ {
+ pFrame->SetPosSize( pFrame->maRestorePosSize );
+ pFrame->maRestorePosSize = Rectangle();
+ pFrame->nWidth_ = rGeom.nWidth;
+ pFrame->nHeight_ = rGeom.nHeight;
+ if( m_aWMName.EqualsAscii( "Dtwm" ) && pFrame->bMapped_ )
+ {
+ pFrame->maGeometry.nX += rGeom.nLeftDecoration;
+ pFrame->maGeometry.nY += rGeom.nTopDecoration;
+ }
+ }
+}
+
+/*
+ * NetWMAdaptor::maximizeFrame
+ * changes _NET_WM_STATE by sending a client message
+ */
+
+void NetWMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
+{
+ pFrame->mbMaximizedVert = bVertical;
+ pFrame->mbMaximizedHorz = bHorizontal;
+
+ if( m_aWMAtoms[ NET_WM_STATE ]
+ && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ]
+ && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ]
+ && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT )
+ )
+ {
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bHorizontal ? 1 : 0;
+ aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ];
+ aEvent.xclient.data.l[2] = bHorizontal == bVertical ? m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] : 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ if( bHorizontal != bVertical )
+ {
+ aEvent.xclient.data.l[0]= bVertical ? 1 : 0;
+ aEvent.xclient.data.l[1]= m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ];
+ aEvent.xclient.data.l[2]= 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ }
+ else
+ {
+ // window not mapped yet, set _NET_WM_STATE directly
+ setNetWMState( pFrame );
+ }
+ if( !bHorizontal && !bVertical )
+ pFrame->maRestorePosSize = Rectangle();
+ else if( pFrame->maRestorePosSize.IsEmpty() )
+ {
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ pFrame->maRestorePosSize =
+ Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
+ }
+ }
+ else
+ WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical );
+}
+
+/*
+ * GnomeWMAdaptor::maximizeFrame
+ * changes _WIN_STATE by sending a client message
+ */
+
+void GnomeWMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
+{
+ pFrame->mbMaximizedVert = bVertical;
+ pFrame->mbMaximizedHorz = bHorizontal;
+
+ if( m_aWMAtoms[ WIN_STATE ]
+ && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT )
+ )
+ {
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ WIN_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = (1<<2)|(1<<3);
+ aEvent.xclient.data.l[1] =
+ (bVertical ? (1<<2) : 0)
+ | (bHorizontal ? (1<<3) : 0);
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask,
+ &aEvent
+ );
+ }
+ else
+ // window not mapped yet, set _WIN_STATE directly
+ setGnomeWMState( pFrame );
+
+ if( !bHorizontal && !bVertical )
+ pFrame->maRestorePosSize = Rectangle();
+ else if( pFrame->maRestorePosSize.IsEmpty() )
+ {
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ pFrame->maRestorePosSize =
+ Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
+ }
+ }
+ else
+ WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical );
+}
+
+/*
+ * WMAdaptor::supportsICCCMPos
+ */
+
+bool WMAdaptor::supportsICCCMPos() const
+{
+ return
+ m_aWMName.EqualsAscii( "Sawfish" )
+ || m_aWMName.EqualsAscii( "Dtwm" );
+}
+
+/*
+ * NetWMAdaptor::supportsICCCMPos
+ */
+
+bool NetWMAdaptor::supportsICCCMPos() const
+{
+ return true;
+}
+
+
+/*
+ * WMAdaptor::enableAlwaysOnTop
+ */
+void WMAdaptor::enableAlwaysOnTop( X11SalFrame*, bool /*bEnable*/ ) const
+{
+}
+
+/*
+ * NetWMAdaptor::enableAlwaysOnTop
+ */
+void NetWMAdaptor::enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const
+{
+ pFrame->bAlwaysOnTop_ = bEnable;
+ if( m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ] )
+ {
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bEnable ? 1 : 0;
+ aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ];
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ setNetWMState( pFrame );
+ }
+}
+
+/*
+ * GnomeWMAdaptor::enableAlwaysOnTop
+ */
+void GnomeWMAdaptor::enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const
+{
+ pFrame->bAlwaysOnTop_ = bEnable;
+ if( m_aWMAtoms[ WIN_LAYER ] )
+ {
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ WIN_LAYER ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bEnable ? 6 : 4;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ {
+ sal_uInt32 nNewLayer = bEnable ? 6 : 4;
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ WIN_LAYER ],
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&nNewLayer,
+ 1
+ );
+ }
+ }
+}
+
+/*
+ * WMAdaptor::changeReferenceFrame
+ */
+void WMAdaptor::changeReferenceFrame( X11SalFrame* pFrame, X11SalFrame* pReferenceFrame ) const
+{
+ if( ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_PLUG )
+ && ! pFrame->IsOverrideRedirect()
+ && ! pFrame->IsFloatGrabWindow()
+ )
+ {
+ XLIB_Window aTransient = pFrame->pDisplay_->GetRootWindow( pFrame->GetScreenNumber() );
+ pFrame->mbTransientForRoot = true;
+ if( pReferenceFrame )
+ {
+ aTransient = pReferenceFrame->GetShellWindow();
+ pFrame->mbTransientForRoot = false;
+ }
+ XSetTransientForHint( m_pDisplay,
+ pFrame->GetShellWindow(),
+ aTransient );
+ }
+}
+
+/*
+ * WMAdaptor::handlePropertyNotify
+ */
+int WMAdaptor::handlePropertyNotify( X11SalFrame*, XPropertyEvent* ) const
+{
+ return 0;
+}
+
+/*
+ * NetWMAdaptor::handlePropertyNotify
+ */
+int NetWMAdaptor::handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const
+{
+ int nHandled = 1;
+ if( pEvent->atom == m_aWMAtoms[ NET_WM_STATE ] )
+ {
+ pFrame->mbMaximizedHorz = pFrame->mbMaximizedVert = false;
+ pFrame->mbShaded = false;
+
+ if( pEvent->state == PropertyNewValue )
+ {
+ Atom nType, *pStates;
+ int nFormat;
+ unsigned long nItems, nBytesLeft;
+ unsigned char* pData = NULL;
+ long nOffset = 0;
+ do
+ {
+ XGetWindowProperty( m_pDisplay,
+ pEvent->window,
+ m_aWMAtoms[ NET_WM_STATE ],
+ nOffset, 64,
+ False,
+ XA_ATOM,
+ &nType,
+ &nFormat,
+ &nItems, &nBytesLeft,
+ &pData );
+ if( pData )
+ {
+ if( nType == XA_ATOM && nFormat == 32 && nItems > 0 )
+ {
+ pStates = (Atom*)pData;
+ for( unsigned long i = 0; i < nItems; i++ )
+ {
+ if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] )
+ pFrame->mbMaximizedVert = true;
+ else if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] )
+ pFrame->mbMaximizedHorz = true;
+ else if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_SHADED ] && m_aWMAtoms[ NET_WM_STATE_SHADED ] )
+ pFrame->mbShaded = true;
+ }
+ }
+ XFree( pData );
+ pData = NULL;
+ nOffset += nItems * nFormat / 32;
+ }
+ else
+ break;
+ } while( nBytesLeft > 0 );
+ }
+
+ if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) )
+ pFrame->maRestorePosSize = Rectangle();
+ else
+ {
+ const SalFrameGeometry& rGeom = pFrame->GetUnmirroredGeometry();
+ // the current geometry may already be changed by the corresponding
+ // ConfigureNotify, but this cannot be helped
+ pFrame->maRestorePosSize =
+ Rectangle( Point( rGeom.nX, rGeom.nY ),
+ Size( rGeom.nWidth, rGeom.nHeight ) );
+ }
+ }
+ else if( pEvent->atom == m_aWMAtoms[ NET_WM_DESKTOP ] )
+ {
+ pFrame->m_nWorkArea = getWindowWorkArea( pFrame->GetShellWindow() );
+ }
+ else
+ nHandled = 0;
+
+ return nHandled;
+}
+
+/*
+ * GnomeWMAdaptor::handlePropertyNotify
+ */
+int GnomeWMAdaptor::handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const
+{
+ int nHandled = 1;
+ if( pEvent->atom == m_aWMAtoms[ WIN_STATE ] )
+ {
+ pFrame->mbMaximizedHorz = pFrame->mbMaximizedVert = false;
+ pFrame->mbShaded = false;
+
+ if( pEvent->state == PropertyNewValue )
+ {
+ Atom nType;
+ int nFormat = 0;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pData = 0;
+ XGetWindowProperty( m_pDisplay,
+ pEvent->window,
+ m_aWMAtoms[ WIN_STATE ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &nType,
+ &nFormat,
+ &nItems, &nBytesLeft,
+ &pData );
+ if( pData )
+ {
+ if( nType == XA_CARDINAL && nFormat == 32 && nItems == 1 )
+ {
+ sal_uInt32 nWinState = *(sal_uInt32*)pData;
+ if( nWinState & (1<<2) )
+ pFrame->mbMaximizedVert = true;
+ if( nWinState & (1<<3) )
+ pFrame->mbMaximizedHorz = true;
+ if( nWinState & (1<<5) )
+ pFrame->mbShaded = true;
+ }
+ XFree( pData );
+ }
+ }
+
+ if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) )
+ pFrame->maRestorePosSize = Rectangle();
+ else
+ {
+ const SalFrameGeometry& rGeom = pFrame->GetUnmirroredGeometry();
+ // the current geometry may already be changed by the corresponding
+ // ConfigureNotify, but this cannot be helped
+ pFrame->maRestorePosSize =
+ Rectangle( Point( rGeom.nX, rGeom.nY ),
+ Size( rGeom.nWidth, rGeom.nHeight ) );
+ }
+ }
+ else if( pEvent->atom == m_aWMAtoms[ NET_WM_DESKTOP ] )
+ {
+ pFrame->m_nWorkArea = getWindowWorkArea( pFrame->GetShellWindow() );
+ }
+ else
+ nHandled = 0;
+
+ return nHandled;
+}
+
+/*
+ * WMAdaptor::shade
+ */
+void WMAdaptor::shade( X11SalFrame*, bool /*bToShaded*/ ) const
+{
+}
+
+/*
+ * NetWMAdaptor::shade
+ */
+void NetWMAdaptor::shade( X11SalFrame* pFrame, bool bToShaded ) const
+{
+ if( m_aWMAtoms[ NET_WM_STATE ]
+ && m_aWMAtoms[ NET_WM_STATE_SHADED ]
+ && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT )
+ )
+ {
+ pFrame->mbShaded = bToShaded;
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bToShaded ? 1 : 0;
+ aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_SHADED ];
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ {
+ // window not mapped yet, set _NET_WM_STATE directly
+ setNetWMState( pFrame );
+ }
+ }
+}
+
+/*
+ * GnomeWMAdaptor::shade
+ */
+void GnomeWMAdaptor::shade( X11SalFrame* pFrame, bool bToShaded ) const
+{
+ if( m_aWMAtoms[ WIN_STATE ] )
+ {
+ pFrame->mbShaded = bToShaded;
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ WIN_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = (1<<5);
+ aEvent.xclient.data.l[1] = bToShaded ? (1<<5) : 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ setGnomeWMState( pFrame );
+ }
+}
+
+/*
+ * WMAdaptor::showFullScreen
+ */
+void WMAdaptor::showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const
+{
+ pFrame->mbFullScreen = bFullScreen;
+ maximizeFrame( pFrame, bFullScreen, bFullScreen );
+}
+
+/*
+ * NetWMAdaptor::showFullScreen
+ */
+void NetWMAdaptor::showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const
+{
+ if( m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] )
+ {
+ pFrame->mbFullScreen = bFullScreen;
+ if( bFullScreen )
+ {
+ if( m_aWMAtoms[ MOTIF_WM_HINTS ] )
+ {
+ XDeleteProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ MOTIF_WM_HINTS ] );
+ }
+ }
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bFullScreen ? 1 : 0;
+ aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ];
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ {
+ // window not mapped yet, set _NET_WM_STATE directly
+ setNetWMState( pFrame );
+ }
+ // #i42750# guess size before resize event shows up
+ if( bFullScreen )
+ {
+ if( m_pSalDisplay->IsXinerama() )
+ {
+ XLIB_Window aRoot, aChild;
+ int root_x = 0, root_y = 0, lx, ly;
+ unsigned int mask;
+ XQueryPointer( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ &aRoot, &aChild,
+ &root_x, &root_y, &lx, &ly, &mask );
+ const std::vector< Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens();
+ Point aMousePoint( root_x, root_y );
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ {
+ if( rScreens[i].IsInside( aMousePoint ) )
+ {
+ pFrame->maGeometry.nX = rScreens[i].Left();
+ pFrame->maGeometry.nY = rScreens[i].Top();
+ pFrame->maGeometry.nWidth = rScreens[i].GetWidth();
+ pFrame->maGeometry.nHeight = rScreens[i].GetHeight();
+ break;
+ }
+ }
+ }
+ else
+ {
+ Size aSize = m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() );
+ pFrame->maGeometry.nX = 0;
+ pFrame->maGeometry.nY = 0;
+ pFrame->maGeometry.nWidth = aSize.Width();
+ pFrame->maGeometry.nHeight = aSize.Height();
+ }
+ pFrame->CallCallback( SALEVENT_MOVERESIZE, NULL );
+ }
+ }
+ else WMAdaptor::showFullScreen( pFrame, bFullScreen );
+}
+
+/*
+ * WMAdaptor::getCurrentWorkArea
+ */
+// FIXME: multiscreen case
+int WMAdaptor::getCurrentWorkArea() const
+{
+ int nCurrent = -1;
+ if( m_aWMAtoms[ NET_CURRENT_DESKTOP ] )
+ {
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_CURRENT_DESKTOP ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ nCurrent = int(*(sal_Int32*)pProperty);
+ XFree( pProperty );
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ return nCurrent;
+}
+
+/*
+ * WMAdaptor::getWindowWorkArea
+ */
+int WMAdaptor::getWindowWorkArea( XLIB_Window aWindow ) const
+{
+ int nCurrent = -1;
+ if( m_aWMAtoms[ NET_WM_DESKTOP ] )
+ {
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ if( XGetWindowProperty( m_pDisplay,
+ aWindow,
+ m_aWMAtoms[ NET_WM_DESKTOP ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ nCurrent = int(*(sal_Int32*)pProperty);
+ XFree( pProperty );
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ return nCurrent;
+}
+
+/*
+ * WMAdaptor::getCurrentWorkArea
+ */
+// fixme: multi screen case
+void WMAdaptor::switchToWorkArea( int nWorkArea, bool bConsiderWM ) const
+{
+ if( bConsiderWM && ! getWMshouldSwitchWorkspace() )
+ return;
+
+ if( m_aWMAtoms[ NET_CURRENT_DESKTOP ] )
+ {
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() );
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_CURRENT_DESKTOP ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = nWorkArea;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+}
+
+/*
+ * WMAdaptor::frameIsMapping
+ */
+void WMAdaptor::frameIsMapping( X11SalFrame* ) const
+{
+}
+
+/*
+ * NetWMAdaptor::frameIsMapping
+ */
+void NetWMAdaptor::frameIsMapping( X11SalFrame* pFrame ) const
+{
+ setNetWMState( pFrame );
+}
+
+/*
+ * WMAdaptor::setFrameStruts
+ */
+void WMAdaptor::setFrameStruts( X11SalFrame*,
+ int, int, int, int,
+ int, int, int, int,
+ int, int, int, int ) const
+{
+}
+
+/*
+ * NetWMAdaptor::setFrameStruts
+ */
+void NetWMAdaptor::setFrameStruts( X11SalFrame* pFrame,
+ int left, int right, int top, int bottom,
+ int left_start_y, int left_end_y,
+ int right_start_y, int right_end_y,
+ int top_start_x, int top_end_x,
+ int bottom_start_x, int bottom_end_x ) const
+{
+ long nData[12];
+ nData[0] = left;
+ nData[1] = right;
+ nData[2] = top;
+ nData[3] = bottom;
+ nData[4] = left_start_y;
+ nData[5] = left_end_y;
+ nData[6] = right_start_y;
+ nData[7] = right_end_y;
+ nData[8] = top_start_x;
+ nData[9] = top_end_x;
+ nData[10]= bottom_start_x;
+ nData[11]= bottom_end_x;
+ Atom aProperty = None;
+ int nSetData = 0;
+
+ if( m_aWMAtoms[NET_WM_STRUT_PARTIAL] )
+ {
+ aProperty = m_aWMAtoms[NET_WM_STRUT_PARTIAL];
+ nSetData = 12;
+ }
+ else if( m_aWMAtoms[NET_WM_STRUT] )
+ {
+ aProperty = m_aWMAtoms[NET_WM_STRUT];
+ nSetData = 4;
+ }
+ if( nSetData )
+ {
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ aProperty,
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&nData,
+ nSetData
+ );
+ }
+}
+
+/*
+ * WMAdaptor::setUserTime
+ */
+void WMAdaptor::setUserTime( X11SalFrame*, long ) const
+{
+}
+
+/*
+ * NetWMAdaptor::setUserTime
+ */
+void NetWMAdaptor::setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const
+{
+ if( m_aWMAtoms[NET_WM_USER_TIME] )
+ {
+ XChangeProperty( m_pDisplay,
+ i_pFrame->GetShellWindow(),
+ m_aWMAtoms[NET_WM_USER_TIME],
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&i_nUserTime,
+ 1
+ );
+ }
+}
+
+/*
+ * WMAdaptor::setPID
+ */
+void WMAdaptor::setPID( X11SalFrame* i_pFrame ) const
+{
+ if( m_aWMAtoms[NET_WM_PID] )
+ {
+ long nPID = (long)getpid();
+ XChangeProperty( m_pDisplay,
+ i_pFrame->GetShellWindow(),
+ m_aWMAtoms[NET_WM_PID],
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&nPID,
+ 1
+ );
+ }
+}
+
+/*
+* WMAdaptor::setClientMachine
+*/
+void WMAdaptor::setClientMachine( X11SalFrame* i_pFrame ) const
+{
+ rtl::OString aWmClient( rtl::OUStringToOString( GetX11SalData()->GetLocalHostName(), RTL_TEXTENCODING_ASCII_US ) );
+ XTextProperty aClientProp = { (unsigned char*)aWmClient.getStr(), XA_STRING, 8, aWmClient.getLength() };
+ XSetWMClientMachine( m_pDisplay, i_pFrame->GetShellWindow(), &aClientProp );
+}
+
+void WMAdaptor::answerPing( X11SalFrame* i_pFrame, XClientMessageEvent* i_pEvent ) const
+{
+ if( m_aWMAtoms[NET_WM_PING] &&
+ i_pEvent->message_type == m_aWMAtoms[ WM_PROTOCOLS ] &&
+ (Atom)i_pEvent->data.l[0] == m_aWMAtoms[ NET_WM_PING ] )
+ {
+ XEvent aEvent;
+ aEvent.xclient = *i_pEvent;
+ aEvent.xclient.window = m_pSalDisplay->GetRootWindow( i_pFrame->GetScreenNumber() );
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( i_pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ XFlush( m_pDisplay );
+ }
+}